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

import java.io.IOException;
import java.io.Writer;
import java.text.ParseException;
import java.util.Calendar;
import jp.riken.brain.ni.samuraigraph.base.SGData;
import jp.riken.brain.ni.samuraigraph.base.SGUtility;
import jp.riken.brain.ni.samuraigraph.base.SGUtilityText;

/**
 * Scalar type two dimensional data with date values.
 */
public class SGSXYDateData extends SGDateData
	implements SGISXYTypeData
{

	// a data object created with date information
	private SGSXYData mData = null;


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


	/**
	 * 
	 */
	public SGSXYDateData(
		final String[] titleArray,
		final String[] dateArray,
		final double[] yValueArray ) throws ParseException
	{
		this( titleArray, dateArray, yValueArray, null, null, null );
	}


	/**
	 * 
	 */
	public SGSXYDateData(
		final String[] titleArray,
		final String[] dateArray,
		final double[] yValueArray,
		final String[] labelArray ) throws ParseException
	{
		this( titleArray, dateArray, yValueArray, null, null, labelArray );
	}


	/**
	 * 
	 */
	public SGSXYDateData(
		final String[] titleArray,
		final String[] dateArray,
		final double[] yValueArray,
		final double[] lowerErrorArray,
		final double[] upperErrorArray ) throws ParseException
	{
		this( titleArray, dateArray, yValueArray, lowerErrorArray, upperErrorArray, null );
	}


	/**
	 * 
	 */
	public SGSXYDateData(
		final String[] titleArray,
		final String[] dateArray,
		final double[] yValueArray,
		final double[] lowerErrorArray,
		final double[] upperErrorArray,
		final String[] labelArray ) throws ParseException
	{
		super( titleArray, dateArray );

		if( yValueArray.length!=dateArray.length )
		{
			throw new IllegalArgumentException("yValueArray.length!=dateArray.length");
		}

		if( lowerErrorArray!=null & upperErrorArray!=null )
		{
			if( lowerErrorArray.length!=dateArray.length )
			{
				throw new IllegalArgumentException("lowerErrorArray.length!=dateArray.length");
			}

			if( upperErrorArray.length!=dateArray.length )
			{
				throw new IllegalArgumentException("upperErrorArray.length!=dateArray.length");
			}
		}
		
		if( labelArray!=null )
		{
			if( labelArray.length!=dateArray.length )
			{
				throw new IllegalArgumentException("labelArray.length!=dateArray.length");
			}
		}

		final double[] xValueArray = this.calcXValueArray();
		final String[] stringArray = labelArray!=null ? SGUtility.copyStringArray( labelArray ) : SGUtility.copyStringArray( dateArray );
		this.mData = new SGSXYData( null,  xValueArray, yValueArray, lowerErrorArray, upperErrorArray, stringArray );
	}


	/**
	 * 
	 */
	public SGSXYDateData(
		final String[] titleArray,
		final int[] yearArray,
		final int[] monthArray,
		final int[] dateArray,
		final double[] yValueArray )
	{
		this( titleArray, yearArray, monthArray, dateArray, null, null, yValueArray );
	}


	/**
	 * 
	 */
	public SGSXYDateData(
		final String[] titleArray,
		final int[] yearArray,
		final int[] monthArray,
		final int[] dateArray,
		final double[] yValueArray,
		final double[] lowerErrorArray,
		final double[] upperErrorArray )
	{
		super( titleArray, yearArray, monthArray, dateArray );

		if( yValueArray==null )
		{
			throw new IllegalArgumentException("yValueArray==null");
		}

		if( yValueArray.length!=yearArray.length )
		{
			throw new IllegalArgumentException("yValueArray.length!=yearArray.length");
		}

		if( lowerErrorArray!=null & upperErrorArray!=null )
		{
			if( lowerErrorArray.length!=yearArray.length )
			{
				throw new IllegalArgumentException("lowerErrorArray.length!=yearArray.length");
			}

			if( upperErrorArray.length!=yearArray.length )
			{
				throw new IllegalArgumentException("upperErrorArray.length!=yearArray.length");
			}
		}

		final double[] xValueArray = this.calcXValueArray();
		final String[] stringArray = this.getStringArray( yearArray, monthArray, dateArray );
		this.mData = new SGSXYData( null, xValueArray, yValueArray, lowerErrorArray, upperErrorArray, stringArray );
	}


//	/**
//	 * 
//	 */
//	public SGSXYCalendarData(
//		final int[] yearArray, final int[] monthArray, final int[] dateArray,
//		final double[][] yValueArray )
//	{
//		super( yearArray, monthArray, dateArray );
//
//		if( yValueArray==null )
//		{
//			throw new IllegalArgumentException("yValueArray==null");
//		}
//
//		if( yValueArray.length!=yearArray.length )
//		{
//			throw new IllegalArgumentException("yValueArray.length!=yearArray.length");
//		}
//
//		final double[] xValueArray = this.calcXValueArray();
//		this.mData = new SGSXYMultipleData( xValueArray, yValueArray );
//	}


	// calculate x values
	private double[] calcXValueArray()
	{
		final InnerDate[] dArray = this.mDateArray;
		final int num = dArray.length;
		final double[] xValueArray = new double[num];
		final Calendar cal = Calendar.getInstance();
		final int ratio = 1000*3600*24;
		for( int ii=0; ii<num; ii++ )
		{
			final InnerDate d = dArray[ii];
			cal.set( d.year, d.month, d.date );
			xValueArray[ii] = cal.getTimeInMillis()/ratio;
		}

		return xValueArray;
	}


	// returns the array of text strings
	private String[] getStringArray(
		final int[] yearArray, final int[] monthArray, final int[] dateArray )
	{
		final String[] stringArray = new String[yearArray.length];
		InnerDate date;
		for( int ii=0; ii<stringArray.length; ii++ )
		{
			date = new InnerDate(yearArray[ii], monthArray[ii], dateArray[ii]);
			stringArray[ii] = date.mDateString;
		}
		return stringArray;
	}


	/**
	 * 
	 */
	public int getPointsNumber()
	{
		return this.mData.getPointsNumber();
	}


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


	/**
	 * Set data.
	 * @param data - data set to this object
	 */
	public boolean setData( final SGData data )
	{
		if( !(data instanceof SGSXYDateData) )
		{
			throw new IllegalArgumentException("!(data instanceof SGSXYCalendarData)");
		}
		
		if( super.setData( data ) == false )
		{
			return false;
		}

		SGSXYDateData dData = (SGSXYDateData)data;
		this.mData = (SGSXYData)dData.mData.copy();

		return true;
	}


	/**
	 * 
	 */
	public double getMinValueX()
	{
		return this.mData.getMinValueX();
	}


	/**
	 * 
	 */
	public double getMaxValueX()
	{
		return this.mData.getMaxValueX();
	}


	/**
	 * 
	 */
	public double getMinValueY()
	{
		return this.mData.getMinValueY();
	}


	/**
	 * 
	 */
	public double getMaxValueY()
	{
		return this.mData.getMaxValueY();
	}


	/**
	 * Returns the x value with the given index.
	 * @param n - index
	 * @return x-value with the given index
	 */
	public Double getXValue( final int n )
	{
		return this.mData.getXValue(n);
	}


	/**
	 * Returns the y value with the given index.
	 * @param n - index
	 * @return y-value with the given index
	 */
	public Double getYValue( final int n )
	{
		return this.mData.getYValue(n);
	}


	/**
	 * Returns the lower error value with the given index if it exists.
	 * @param n - index
	 * @return lower error value with the given index
	 */
	public Double getLowerErrorValue( final int n )
	{
		return this.mData.getLowerErrorValue(n);
	}


	/**
	 * Returns the upper error value with the given index if it exists.
	 * @param n - index
	 * @return upper error value with the given index
	 */
	public Double getUpperErrorValue( final int n )
	{
		return this.mData.getUpperErrorValue(n);
	}



	/**
	 * Returns the string with the given index if it exists.
	 * @param n - index
	 * @return a string with the given index
	 */
	public String getString( final int n )
	{
		return this.mData.getString(n);
	}


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


	/**
	 * Returns a copy of y-value array.
	 * @return y-value array
	 */
	public double[] getYValueArray()
	{
		return this.mData.getYValueArray();
	}


	/**
	 * Returns a copy of lower-error-value array if they exist.
	 * @return lower-error-value array
	 */
	public double[] getLowerErrorValueArray()
	{
		return this.mData.getLowerErrorValueArray();
	}


	/**
	 * Returns a copy of upper-error-value array if they exist.
	 * @return upper-error-value array
	 */
	public double[] getUpperErrorValueArray()
	{
		return this.mData.getUpperErrorValueArray();
	}


	/**
	 * Returns a copy of string array if they exist.
	 * @return string array
	 */
	public String[] getStringArray()
	{
		return this.mData.getStringArray();
	}


	/**
	 * Returns whether this data has error values.
	 * @return whether this data has error values
	 */
	public boolean isErrorValueHolding()
	{
		return this.mData.isErrorValueHolding();
	}


	/**
	 * Returns whether this data has strings.
	 * @return whether this data has strings
	 */
	public boolean isStringArrayHolding()
	{
		return this.mData.isStringArrayHolding();
	}



	/**
	 * 
	 */
	public void dispose()
	{
		super.dispose();
		
		// do not dispose mData because it can be shared with
		// other data objects
		
		this.mData = 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.mData == null || this.mData.mXValueArray.length == 0)
			return false;
		for(int ii=0; ii<this.mData.mXValueArray.length; ii++){
			String line = this.mDateArray[ii].mDateString + "," + this.mData.mYValueArray[ii];
			if(this.mData.mUpperErrorArray != null){
				line += "," + this.mData.mUpperErrorArray[ii] + "," + this.mData.mLowerErrorArray[ii];
			}
			if(this.mData.mStringArray[ii] != null){
				line += "," + SGUtilityText.getCSVString( this.mData.mStringArray[ii] );
			}
			line += "\n";
			fw.write(line);
		}
		return true;
	}
	
//	// main method
//	public static void main( String[] args ) throws Exception
//	{
//		String[] xArray = {
//			"2005/1/1",
//			"2005/2/1",
//			"2005/3/1",
//			"2005/4/1",
//			"2005/5/1",
//			"2005/6/1",
//			"2005/7/1",
//			"2005/8/1",
//			"2005/9/1",
//			"2005/10/1",
//			"2005/11/1",
//			"2005/12/1",
//			"2006/1/1"
//		};
//
//		double[] yArray = {
//			3.1,
//			8.0,
//			1.4,
//			2.5,
//			5.8,
//			6.3,
//			10.8,
//			3.4,
//			4.1,
//			8.5,
//			6.8,
//			9.5,
//			7.3
//		};
//
//		double[] lArray = new double[xArray.length];
//		double[] uArray = new double[xArray.length];
//
//		SGSXYDateData d = new SGSXYDateData( null, xArray, yArray, lArray, uArray );
//
//		SGSXYData dataSXY = (SGSXYData)d.mData;
//		double[] xArray_ = dataSXY.getXValueArray();
//		double[] yArray_ = dataSXY.getYValueArray();
//		String[] sArray_ = dataSXY.getStringArray();
//		for( int ii=0; ii<xArray_.length; ii++ )
//		{
//			System.out.println( xArray[ii] + "  " + (long)xArray_[ii] + "  "+ yArray_[ii] + "  " + sArray_[ii] );
//			if( ii!=xArray_.length-1 )
//			{
//				System.out.println( (long)( xArray_[ii+1] - xArray_[ii] )/(3600*24*1000) );
//			}
//		}
//		System.out.println();
//	}

}

