
package jp.riken.brain.ni.samuraigraph.data;

import java.io.IOException;
import java.io.Writer;

import jp.riken.brain.ni.samuraigraph.base.SGData;
import jp.riken.brain.ni.samuraigraph.base.SGUtility;

/**
 * Data with an array of x-values and arrays of y-values.
 */
public class SGSXYMultipleData extends SGData
	implements SGISXYTypeMultipleData, Cloneable
{

	/**
	 * Array of x values.
	 */
	protected double[] mXValueArray = null;


	/**
	 * Array of y values.
	 */
	protected double[][] mYValueArray = null;


	/**
	 * 
	 */
	public SGSXYMultipleData()
	{
		super();
	}


	/**
	 * 
	 * @param xArray
	 * @param yArray
	 */
	public SGSXYMultipleData(
		final double[] xArray,
		final double[][] yArray )
	{
		super();

		if( xArray==null || yArray==null )
		{
			throw new IllegalArgumentException("xArray==null || yArray==null");
		}

		if( yArray.length==0 )
		{
			throw new IllegalArgumentException("yArray.length==0");
		}

		int len = xArray.length;
		for( int ii=0; ii<yArray.length; ii++ )
		{
			if( yArray[ii].length != len )
			{
				throw new IllegalArgumentException("yArray[ii].length != len");
			}
		}

		this.mXValueArray = (double[])xArray.clone();
		this.mYValueArray = new double[yArray.length][];
		for( int ii=0; ii<yArray.length; ii++ )
		{
			this.mYValueArray[ii] = (double[])yArray[ii].clone();
		}

	}


	/**
	 * 
	 */
	public int getDataNumber()
	{
		if( this.mYValueArray==null )
		{
			return -1;
		}
		else
		{
			return this.mYValueArray.length;
		}
	}


	/**
	 * 
	 * @return
	 */
	public int getPointsNumber()
	{
		if( this.mXValueArray==null )
		{
			return -1;
		}
		else
		{
			return this.mXValueArray.length;
		}
	}


	/**
	 * Returns the name of data type.
	 * @return
	 */
	public String getDataType()
	{
		return SGDataTypeConstants.SXY_MULTIPLE_DATA;
	}


	/**
	 * 
	 * @param n
	 * @return
	 */
	public Double getXValue( final int n )
	{
		double[] array = this.getXValueArray();
		if( array!=null )
		{
			return new Double( array[n] );
		}
		else
		{
			return null;
		}
	}



	/**
	 * 
	 * @param m
	 * @param n
	 * @return
	 */
	public Double getYValue( final int m, final int n )
	{
		double[][] array = this.getYValueArray();
		if( array!=null )
		{
			return new Double( array[m][n] );
		}
		else
		{
			return null;
		}
	}


	/**
	 * 
	 */
	public SGISXYTypeData[] getSXYDataArray()
	{
		SGISXYTypeData[] array = new SGISXYTypeData[this.mYValueArray.length];
		double[] xArray = this.getXValueArray();
		for( int ii=0; ii<array.length; ii++ )
		{
			array[ii] = new SGSXYData( xArray, this.mYValueArray[ii] );
		}

		return array;
	}


	/**
	 * Returns a copy of x-value array.
	 * @return x-value array
	 */
	public double[] getXValueArray()
	{
		return SGUtility.copyDoubleArray( this.mXValueArray );
	}


	/**
	 * 
	 * @return
	 */
	public double[][] getYValueArray()
	{
		return this.mYValueArray;
	}


	/**
	 * 
	 */
	public double getMinValueX()
	{
		double min = Double.MAX_VALUE;
		final int len = this.getPointsNumber();
		for( int ii=0; ii<len; ii++ )
		{
			final double value = this.getXValue(ii).doubleValue();
			if( value < min )
			{
				min = value;
			}
		}

		return min;
	}


	/**
	 * 
	 */
	public double getMaxValueX()
	{
		double max = - Double.MAX_VALUE;
		final int len = this.getPointsNumber();
		for( int ii=0; ii<len; ii++ )
		{
			final double value = this.getXValue(ii).doubleValue();
			if( value > max )
			{
				max = value;
			}
		}

		return max;
	}


	/**
	 * 
	 */
	public double getMinValueY()
	{
		double min = Double.MAX_VALUE;
		for( int ii=0; ii<this.mYValueArray.length; ii++ )
		{
			for( int jj=0; jj<this.mYValueArray[ii].length; jj++ )
			{
				final double value = this.mYValueArray[ii][jj];
				if( value < min )
				{
					min = value;
				}
			}
		}

		return min;
	}


	/**
	 * 
	 */
	public double getMaxValueY()
	{
		double max = - Double.MAX_VALUE;
		for( int ii=0; ii<this.mYValueArray.length; ii++ )
		{
			for( int jj=0; jj<this.mYValueArray[ii].length; jj++ )
			{
				final double value = this.mYValueArray[ii][jj];
				if( value > max )
				{
					max = value;
				}
			}
		}

		return max;
	}



	/**
	 * 
	 */
	public boolean setData( final SGData data )
	{
		if( !(data instanceof SGSXYMultipleData) )
		{
			return false;
		}

		SGSXYMultipleData data_ = (SGSXYMultipleData)data;
		this.mXValueArray = data_.mXValueArray;
		this.mYValueArray = data_.mYValueArray;

		return true;
	}



	/**
	 * 
	 */
	public Object clone()
	{
		try
		{
			return super.clone();
		}
		catch( CloneNotSupportedException ex )
		{
			// this shouldn't happen, since we are Cloneable
			throw new InternalError();
		}
	}


	/**
	 * Calling the clone method.
	 */
	public Object copy()
	{
		return this.clone();
	}


	/**
	 * 
	 */
	public String toString()
	{
		String str = "[";
		str += "X=";
		str += this.toDoubleArrayString( this.mXValueArray ) + ", ";
		
		str += "Y={";
		final int num = this.getDataNumber();
		for( int ii=0; ii<num; ii++ )
		{
			double[] array = this.mYValueArray[ii];
			str += this.toDoubleArrayString( array );
			if( ii==array.length-1 )
			{
				break;
			}
			str += ",";
		}
		str += "}";

		str += "]";

		return str;
	}



	/**
	 * 
	 */
	public void dispose()
	{
		super.dispose();
		this.mXValueArray = null;
		this.mYValueArray = null;
	}

	/*
	 * write data to file
	 * @see jp.riken.brain.ni.samuraigraph.base.SGData#writeData(java.io.FileWriter)
	 */
	protected boolean writeData( Writer fw ) throws IOException
	{
		if(this.mXValueArray == null || this.mXValueArray.length == 0)
			return false;
		for(int ii=0; ii<this.mXValueArray.length; ii++){
			String line = "";
			line += this.mXValueArray[ii];
			for(int jj=0; jj<this.mYValueArray.length; jj++)
				line += "," + this.mYValueArray[jj][ii];
			line += "\n";
			fw.write(line);
		}
		return true;
	}

}

