package gl;

class Matrix3x3
{
    double elem[][];

    //-----------------------------------------------------------------------

    Matrix3x3()
    {
	super();
	elem = new double [3][3];
	loadIdentity();
    }

    //-----------------------------------------------------------------------

    Matrix3x3( Matrix3x3 that )
    {
	super();
	elem = new double [3][3];
	this.copy( that );
    }

    //-----------------------------------------------------------------------

    Matrix3x3( double a, double b, double c,
	       double d, double e, double f,
	       double g, double h, double i )
    {
	super();
	elem = new double [3][3];
	elem[0][0] = a; elem[0][1] = b; elem[0][2] = c;
	elem[1][0] = d; elem[1][1] = e; elem[1][2] = f;
	elem[2][0] = g; elem[2][1] = h; elem[2][2] = i;
    }

    //-----------------------------------------------------------------------

    void loadIdentity()
    {
	elem[0][0] = elem[1][1] = elem[2][2] = 1.0;
	elem[0][1] = elem[0][2] = elem[1][0] = 0.0;
	elem[1][2] = elem[2][0] = elem[2][1] = 0.0;
    }

    //-----------------------------------------------------------------------
    
    void copy( Matrix3x3 that )
    {
	for ( int i = 0; i < 3; i++ )
	{
	    for ( int j = 0; j < 3; j++ )
	    {
		this.elem[i][j] = that.elem[i][j];
	    }
	}
    }

    //-----------------------------------------------------------------------

    Matrix3x3 times( Matrix3x3 that )
    {
	Matrix3x3 product = new Matrix3x3();

	for ( int i = 0; i < 3; i++ )
	{
	    for ( int j = 0; j < 3; j++ )
	    {
		double sum = 0.0;

		for ( int k = 0; k < 3; k++ )
		{
		    sum += this.elem[i][k] * that.elem[k][j];
		}
		product.elem[i][j] = sum;
	    }
	}

	return product;
    }

    //-----------------------------------------------------------------------

    void multiplyOnLeftBy( Matrix3x3 that )
    {
	Matrix3x3 product = that.times( this );
	this.copy( product );
    }

    //-----------------------------------------------------------------------

    void multiplyOnRightBy( Matrix3x3 that )
    {
	Matrix3x3 product = this.times( that );
	this.copy( product );
    }

    //-----------------------------------------------------------------------
    
    Matrix3x3 inverse()
    {
	Matrix3x3 O = new Matrix3x3( this );
	Matrix3x3 A = new Matrix3x3();
	double s;
	
	for ( int i = 0; i < 3; i++ )
	{
	    s = O.elem[i][i];
	    for ( int k = 0; k < 3; k++ )
	    {
		O.elem[i][k] /= s;
		A.elem[i][k] /= s;
	    }
	    for ( int j = 0; j < 3; j++ )
	    {
		if ( i != j ) {
		    s = O.elem[j][i];
		    for ( int k = 0; k < 3; k++ )
		    {
			O.elem[j][k] -= O.elem[i][k] * s;
			A.elem[j][k] -= A.elem[i][k] * s;
		    }
		}
	    }
	}
	
	return A;
    }

    //-----------------------------------------------------------------------

    void setElement( int i, int j, double value )
			throws java.lang.ArrayIndexOutOfBoundsException
    {
	this.elem[i][j] = value;
    }

    //-----------------------------------------------------------------------

    double elementAt( int i, int j )
			throws java.lang.ArrayIndexOutOfBoundsException
    {
	return this.elem[i][j];
    }

    //-----------------------------------------------------------------------

    public String toString()
    {
	return "[" + (int) elem[0][0] + "," +
		     (int) elem[0][1] + "," +
		     (int) elem[0][2] + ";" +
		     (int) elem[1][0] + "," +
		     (int) elem[1][1] + "," +
		     (int) elem[1][2] + ";" +
		     (int) elem[2][0] + "," +
		     (int) elem[2][1] + "," +
		     (int) elem[2][2] + "]";
    }

    //-----------------------------------------------------------------------
}
