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

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;

import jp.riken.brain.ni.samuraigraph.base.SGData;
import jp.riken.brain.ni.samuraigraph.base.SGUtilityText;
import jp.riken.brain.ni.samuraigraph.data.SGDataTypeConstants;
import jp.riken.brain.ni.samuraigraph.data.SGSXYData;
import jp.riken.brain.ni.samuraigraph.data.SGSXYMultipleData;
import jp.riken.brain.ni.samuraigraph.data.SGSXYSamplingData;


/**
 * A class to create data objects.
 */
public class SGDataCreator
{

	/**
	 * 
	 *
	 */
	public SGDataCreator()
	{
		
	}


	/**
	 * Creates a data object.
	 * @param path - the path name of the file
	 * @param infoList - information of data
	 * @return created data
	 * @throws FileNotFoundException
	 */
	public SGData create( final String path, final ArrayList infoList )
		throws FileNotFoundException
	{
		if( path==null || infoList==null )
		{
			throw new NullPointerException("path==null || infoList==null");
		}

		// when information is empty, returns null
		if( infoList.size()==0 )
		{
			return null;
		}

		SGData data = null;
		final String dataType = (String)infoList.get(0);
		if( dataType.equals( SGDataTypeConstants.SXY_DATA ) )
		{
			data = this.createSXYData(path);
		}
		else if( dataType.equals( SGDataTypeConstants.VXY_DATA ) )
		{
			
		}
		else if( dataType.equals( SGDataTypeConstants.SXY_MULTIPLE_DATA ) )
		{
			data = this.createSXYMultipleData(path);
		}
		else if( dataType.equals( SGDataTypeConstants.SXY_SAMPLING_DATA ) )
		{
			if( infoList.size()<=1 )
			{
				return null;
			}

			// 第2引数にはサンプリング周波数
			final double rate = ((Double)infoList.get(1)).doubleValue();

			data = this.createSXYSamplingData(path,rate);
		}

		return data;
	}



	/**
	 * 
	 * @return
	 */
	private SGSXYData createSXYData( final String path )
		throws FileNotFoundException
	{

		// ファイルからデータ列数を取得
		final int num = this.getColumnNumber(path);
		if( num==-1 )
		{
			return null;
		}
		if( num<2 )
		{
			return null;
		}

		// リストの配列を作成
		ArrayList[] listArray = this.createListArray( path, num );
		if( listArray==null )
		{
			return null;
		}


		// check
		final int dataLength = listArray[0].size();
		for( int ii=1; ii<listArray.length; ii++ )
		{
			if( listArray[ii].size()!=dataLength )
			{
				return null;
			}
		}


		//
		// create data object
		//

		SGSXYData data = null;
		String str = null;
		Double d = null;
		{
			double[] xArray = new double[dataLength];
			double[] yArray = new double[dataLength];
			for( int ii=0; ii<dataLength; ii++ )
			{
				str = (String)listArray[0].get(ii);
				d = SGUtilityText.getDouble(str);
				if( d==null )
				{
					return null;
				}
				xArray[ii] = d.doubleValue();

				str = (String)listArray[1].get(ii);
				d = SGUtilityText.getDouble(str);
				if( d==null )
				{
					return null;
				}
				yArray[ii] = d.doubleValue();
			}

			double[] lArray = null;
			double[] uArray = null;
			String[] strArray = null;
			switch( num )
			{
				case 2 :
				{
					break;
				}
				case 4 :
				{
					lArray = new double[dataLength];
					uArray = new double[dataLength];
					for( int ii=0; ii<dataLength; ii++ )
					{
						str = (String)listArray[2].get(ii);
						d = SGUtilityText.getDouble(str);
						if( d==null )
						{
							return null;
						}
						lArray[ii] = d.doubleValue();

						str = (String)listArray[3].get(ii);
						d = SGUtilityText.getDouble(str);
						if( d==null )
						{
							return null;
						}
						uArray[ii] = d.doubleValue();
					}
					break;
				}
				case 3 :
				{
					strArray = new String[dataLength];
					for( int ii=0; ii<dataLength; ii++ )
					{
						strArray[ii] = (String)listArray[2].get(ii);
					}
					break;
				}
				case 5 :
				{
					lArray = new double[dataLength];
					uArray = new double[dataLength];
					strArray = new String[dataLength];
					for( int ii=0; ii<dataLength; ii++ )
					{
						str = (String)listArray[2].get(ii);
						d = SGUtilityText.getDouble(str);
						if( d==null )
						{
							return null;
						}
						lArray[ii] = d.doubleValue();

						str = (String)listArray[3].get(ii);
						d = SGUtilityText.getDouble(str);
						if( d==null )
						{
							return null;
						}
						uArray[ii] = d.doubleValue();

						strArray[ii] = (String)listArray[4].get(ii);
					}
					break;
				}
			
			}

			data = new SGSXYData( xArray, yArray, lArray, uArray, strArray );
		}

		return data;
	}




	/**
	 * 
	 * @return
	 */
	private SGSXYMultipleData createSXYMultipleData( final String path )
		throws FileNotFoundException
	{

		// ファイルからデータ列数を取得
		final int num = this.getColumnNumber(path);
		if( num==-1 )
		{
			return null;
		}
		if( num < 2 )
		{
			return null;
		}

		// リストの配列を作成
		ArrayList[] listArray = this.createListArray( path, num );
		if( listArray==null )
		{
			return null;
		}

		// check
		final int dataLength = listArray[0].size();
		for( int ii=1; ii<listArray.length; ii++ )
		{
			if( listArray[ii].size()!=dataLength )
			{
				return null;
			}
		}


		//
		// create data object
		//

		SGSXYMultipleData data = null;
		{
			double[] xArray = new double[dataLength];
			for( int ii=0; ii<dataLength; ii++ )
			{
				String str = (String)listArray[0].get(ii);
				Double d = SGUtilityText.getDouble(str);
				if( d==null )
				{
					return null;
				}
				xArray[ii] = d.doubleValue();
			}

			double[][] yArray = new double[num-1][];
			for( int ii=0; ii<num-1; ii++ )
			{
				yArray[ii] = new double[dataLength];
				for( int jj=0; jj<dataLength; jj++ )
				{
					String str = (String)listArray[ii+1].get(jj);
					Double d = SGUtilityText.getDouble(str);
					if( d==null )
					{
						return null;
					}
					yArray[ii][jj] = d.doubleValue();
				}
			}

			data = new SGSXYMultipleData( xArray, yArray );
		}

		return data;
	}



	/**
	 * 
	 * @return
	 */
	private SGSXYMultipleData createSXYSamplingData(
		final String path, final double sRate )
			throws FileNotFoundException
	{

		// ファイルからデータ列数を取得
		final int num = this.getColumnNumber(path);
		if( num==-1 )
		{
			return null;
		}
		if( num < 1 )
		{
			return null;
		}

		// リストの配列を作成
		ArrayList[] listArray = this.createListArray( path, num );
		if( listArray==null )
		{
			return null;
		}

		// check
		final int dataLength = listArray[0].size();
		for( int ii=1; ii<listArray.length; ii++ )
		{
			if( listArray[ii].size()!=dataLength )
			{
				return null;
			}
		}


		//
		// create data object
		//

		SGSXYSamplingData data = null;

		Double d = null;
		String str = null;
		{
			double[][] yArray = new double[num][];
			for( int ii=0; ii<num; ii++ )
			{
				yArray[ii] = new double[dataLength];
				for( int jj=0; jj<dataLength; jj++ )
				{
					str = (String)listArray[ii].get(jj);
					d = SGUtilityText.getDouble(str);
					if( d==null )
					{
						return null;
					}
					yArray[ii][jj] = d.doubleValue();
				}
			}

			data = new SGSXYSamplingData( sRate, yArray );
		}

		return data;
	}



	/**
	 * 
	 */
	private int getColumnNumber( final String path )
		throws FileNotFoundException
	{
		// 最初の1行を読み込んで情報を取得する
		int num = -1;

		BufferedReader br = null;
		try
		{
			br = new BufferedReader( new FileReader(path) );
			ArrayList tokenList = this.getFirstTokenList(br);
			num = tokenList.size();
		}
		catch( FileNotFoundException ex )
		{
			throw ex;
		}
		finally
		{
			if( br!=null )
			{
				try
				{
					br.close();
				}
				catch( IOException ex )
				{
					
				}
			}
		}

		return num;
	}



	/**
	 * Creates an array of the list.
	 * @param path
	 * @param num
	 * @return
	 * @throws FileNotFoundException
	 */
	private ArrayList[] createListArray( final String path, final int num )
		throws FileNotFoundException
	{

		// create an array of list
		ArrayList[] listArray = new ArrayList[num];
		for( int ii=0; ii<listArray.length; ii++ )
		{
			listArray[ii] = new ArrayList();
		}

		BufferedReader br = null;
		try
		{
			br = new BufferedReader( new FileReader(path) );

			String line = null;
			while(true)
			{
				line = SGUtilityText.readLine(br);
				if( line==null )
				{
					break;
				}
		
				// break the string into tokens
				final ArrayList tokenList = new ArrayList();
				if( SGUtilityText.tokenize( line, tokenList ) == false )
				{
					return null;
				}
				if( tokenList.size()!=num )
				{
					if( tokenList.size()!=0 )
					{
						return null;
					}
					else
					{
						continue;
					}
				}

				// array of the tokens
				final String[] array = new String[num];
				for( int ii=0; ii<num; ii++ )
				{
					String str = (String)tokenList.get(ii);
					listArray[ii].add( str );
				}
			}
		}
		catch( FileNotFoundException ex )
		{
			throw ex;
		}
		finally
		{
			if( br!=null )
			{
				try
				{
					br.close();
				}
				catch( IOException ex )
				{
					
				}
			}
		}

		return listArray;
	}




	/**
	 * determine the data-type from the first line
	 */
	public boolean getFileTypeCandidateList(
		final String path,
		final ArrayList cList,
		final ArrayList tokenNumList ) throws FileNotFoundException
	{
		BufferedReader br = null;
		try
		{
			br = new BufferedReader( new FileReader( path ) );
			ArrayList tokenList = this.getFirstTokenList(br);
			final int tokenNum = tokenList.size();

			// get candidates of data-type
			if( tokenNum==2		// x,y
				|| tokenNum==3		// x,y,string
				|| tokenNum==5		// x,y,e+,e-,string
				)
			{
				if( this.evaluateDataTypeSXY(tokenList) )
				{
					cList.add(SGDataTypeConstants.SXY_DATA);
				}
			}
			else if( tokenNum==4 )
			{
				if( this.evaluateDataTypeSXY(tokenList) )
				{
					cList.add(SGDataTypeConstants.SXY_DATA);
				}

//				cList.add(SGDataTypeConstants.VXY_DATA);
			}
			if( tokenNum>=2 )
			{
				if( this.evaluateDataTypeSXYMultiple(tokenList) )
				{
					cList.add(SGDataTypeConstants.SXY_MULTIPLE_DATA);
				}
			}
			if( tokenNum>=1 )
			{
				if( this.evaluateDataTypeSXYMultiple(tokenList) )
				{
					cList.add(SGDataTypeConstants.SXY_SAMPLING_DATA);
				}
			}

			tokenNumList.add( new Integer(tokenNum) );

		}
		catch( FileNotFoundException ex )
		{
			throw ex;
		}
		finally
		{
			if( br!=null )
			{
				try
				{
					br.close();
				}
				catch( IOException ex )
				{
					
				}
			}
		}

		return true;
	}



	/**
	 * 
	 */
	private boolean evaluateDataTypeSXY( final ArrayList tokenList )
	{

		int num = 0;
		if( tokenList.size()==2 || tokenList.size()==4 )
		{
			num = tokenList.size();
		}
		else if( tokenList.size()==3 )
		{
			num = 2;
		}
		else if( tokenList.size()==5 )
		{
			num = 4;
		}

		for( int ii=0; ii<num; ii++ )
		{
			String str = (String)tokenList.get(ii);
			Double d = SGUtilityText.getDouble(str);
			if( d==null )
			{
				return false;
			}
		}

		return true;

	}



	/**
	 * 
	 */
	private boolean evaluateDataTypeSXYMultiple( final ArrayList tokenList )
	{

		for( int ii=0; ii<tokenList.size(); ii++ )
		{
			String str = (String)tokenList.get(ii);
			Double d = SGUtilityText.getDouble(str);
			if( d==null )
			{
				return false;
			}
		}

		return true;

	}



	/**
	 * 
	 * @param br - a buffered reader
	 * @return a list of tokens
	 */
	private ArrayList getFirstTokenList( BufferedReader br )
	{
		ArrayList tokenList = new ArrayList();
		while( true )
		{
			String line = SGUtilityText.readLine(br);
			if( line == null )
			{
				break;
			}

			// tokenize the line
			tokenList.clear();
			SGUtilityText.tokenize( line, tokenList );
			final int size = tokenList.size();	// the number of tokens
			if( size!=0 )
			{
				break;
			}
		}

		return tokenList;
	}


}

