package daruma.geometry;

import daruma.geometry.CoordinateSystem;
import daruma.geometry.DrmPoint;

import daruma.geometry.TransformationException;
import daruma.geometry.TransformationErrorException;

import daruma.util.LogWriter;

public class AffineCoordinateSystemTransformation
    extends CoordinateSystemTransformation
{
    private double[][] matrix;

    public AffineCoordinateSystemTransformation( String identifier,
						 CoordinateSystem sourceCS,
						 CoordinateSystem targetCS ,
						 double[][] matrix )
    {
	super( identifier , sourceCS , targetCS );

	this.matrix = matrix.clone();
    }

    public double[][] getMatrix()
    {
	return this.matrix;
    }

    @Override
    public String getTransformName()
    {
	return "affine";
    }

    @Override
    public String encode()
    {
	StringBuilder buf = new StringBuilder();

	for ( int i = 0 ; i < this.matrix.length ; ++ i )
	{
	    for ( int j = 0 ; j < this.matrix[i].length ; ++ j )
	    {
		if ( i != 0 || j != 0 )
		{
		    buf.append( " " );
		}

		buf.append( this.matrix[i][j] );
	    }
	}

	return buf.toString();
    }


    @Override
    public DrmPoint transform( DrmPoint point ) throws TransformationException
    {
	int dim = point.getDimension();

	/*
	//
	// strict coordinate transform
	//

	if ( dim != this.matrix.length )
	{
	    throw new TransformationException( "dimension mismatch" );
	}

	// XXX
	assert dim == 2; 
	*/


	//
	// non-strict coordinate transform
	//

	if ( dim < this.matrix.length )
	{
	    throw new TransformationException( "dimension mismatch" );
	}

	assert dim >= 2; 

	// XXX
	if ( dim > 2 )
	{
	    dim = 2;
	}

	double[] org = new double[dim + 1];
	org[0] = point.getX();
	org[1] = point.getY();
	org[2] = 1.0;

	double[] val = new double[dim];

	for ( int axis = 0 ; axis < dim ; ++ axis )
	{
	    val[axis] = 0.0;

	    for ( int i = 0 ; i < dim + 1 ; ++ i )
	    {
		val[axis] += this.matrix[axis][i] * org[i];

		LogWriter.qwrite( "DEBUG",
				  "ret[", axis , "] += ",
				  this.matrix[axis][i], " * ", org[i] );
	    }
	}

	DrmPoint ret = new DrmPoint( val[0], val[1] );
	ret.setSrsName( this.getTargetCS().getSrsName() );

	return ret;
    }
}
