
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.text.DateFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.NoSuchElementException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import jp.riken.brain.ni.samuraigraph.base.SGCSVTokenizer;
import jp.riken.brain.ni.samuraigraph.base.SGData;
import jp.riken.brain.ni.samuraigraph.base.SGIProgressControl;
import jp.riken.brain.ni.samuraigraph.base.SGUtilityText;
import jp.riken.brain.ni.samuraigraph.data.SGDataTypeConstants;
import jp.riken.brain.ni.samuraigraph.data.SGISXYTypeData;
import jp.riken.brain.ni.samuraigraph.data.SGIVXYTypeData;
import jp.riken.brain.ni.samuraigraph.data.SGSXYData;
import jp.riken.brain.ni.samuraigraph.data.SGSXYDateData;
import jp.riken.brain.ni.samuraigraph.data.SGSXYMultipleData;
import jp.riken.brain.ni.samuraigraph.data.SGSXYSamplingData;
import jp.riken.brain.ni.samuraigraph.data.SGVXYData;


/**
 * A class to create data objects.
 */
public class SGDataCreator
{
	
	private static final String PROGRESS_MESSAGE_READFILE   = "Read File";
	private static final String PROGRESS_MESSAGE_CREATEDATA = "Create Data";
	
	/**
	 * The default constructor.
	 *
	 */
	public SGDataCreator()
	{
		super();
	}
	
	
	/**
	 * Creates a data object.
	 * @param path - the path name of the file
	 * @param infoList - information of data. [0]: dataType, [1]: data specific info.
	 * @return created data
	 * @throws FileNotFoundException
	 * @throws NullPointerException
	 */
	public SGData create( final String path, final ArrayList infoList, final SGIProgressControl progress )
	throws FileNotFoundException, IllegalArgumentException
	{
		SGData data = null;
		progress.startProgress();
		try {
			if( path==null || infoList==null )
			{
				throw new IllegalArgumentException("path==null || infoList==null");
			}
			
			// when information is empty, returns null
			if( infoList.size()==0 )
			{
				return null;
			}
			
			final String dataType = (String)infoList.get(0);
			if( dataType.equals( SGDataTypeConstants.SXY_DATA ) )
			{
				data = (SGData)this.createSXYData(path, progress);
			}
			else if( dataType.equals( SGDataTypeConstants.SXY_DATE_DATA ) )
			{
				data = (SGData)this.createSXYDateData(path, progress);
			}
			else if( dataType.equals( SGDataTypeConstants.VXY_DATA ) )
			{
				if( infoList.size()<=1 )
				{
					return null;
				}
				
				// get polar flag
				Object obj = infoList.get(1);
				if( ( obj instanceof Boolean ) == false )
				{
					return null;
				}
				Boolean b = (Boolean)obj;
				data = (SGData)this.createVXYData(path, b.booleanValue(), progress );
			}
			else if( dataType.equals( SGDataTypeConstants.SXY_MULTIPLE_DATA ) )
			{
				data = this.createSXYMultipleData(path, progress);
			}
			else if( dataType.equals( SGDataTypeConstants.SXY_SAMPLING_DATA ) )
			{
				if( infoList.size()<=1 )
				{
					return null;
				}
				
				// get sampling rate
				Object obj = infoList.get(1);
				if( ( obj instanceof Number ) == false )
				{
					return null;
				}
				Number num = (Number)obj;
				data = this.createSXYSamplingData( path, num.doubleValue(), progress );
			}
		}
		catch ( FileNotFoundException ex )
		{	
			throw ex;
		}
		catch ( IllegalArgumentException ex )
		{	
			throw ex;
		}
		finally {
			progress.endProgress();
		}
		return data;
	}
	
	
	
	private static ArrayList getSXYTextColumnIndexList( final int columnNum )
	{
		ArrayList list = new ArrayList();
		// column == 1 : number
		// column == 2 : number, number
		// column == 3 : number, number, string
		// column == 4 : number, number, number, number
		// column == 5 : number, number, number, number, string
		// column >= 6 : ?
		for(int ii = 0; ii<columnNum; ii++){
			if((columnNum == 3 && ii == 2) || (columnNum == 5 && ii == 4))
				list.add( new Integer(0) );
			else
				list.add( new Integer(1) );
		}
		return list;
	}
	
	private static ArrayList getVXYTextColumnIndexList( final int columnNum )
	{
		ArrayList list = new ArrayList();
		// all culumns integer required 
		for(int ii = 0; ii<columnNum; ii++)
			list.add( new Integer(1) );
		return list;
	}
	
	private static ArrayList getSXYMultipleTextColumnIndexList( final int columnNum )
	{
		ArrayList list = new ArrayList();
		// all culumns integer required 
		for(int ii = 0; ii<columnNum; ii++)
			list.add( new Integer(1) );
		return list;
	}
	
	
	private static ArrayList getSXYDateTextColumnIndexList( final int columnNum )
	{
		ArrayList list = new ArrayList();
		// column == 1 : ?
		// column == 2 : string, number
		// column == 3 : string, number, string
		// column == 4 : string, number, number, number
		// column == 5 : string, number, number, number, string
		// column >= 6 : ?
		for(int ii=0; ii<columnNum; ii++){
			if(ii==0 || (columnNum==3 && ii==2) || (columnNum==5 && ii==4)){
				list.add( new Integer(0) );
			}else{
				list.add( new Integer(1) );				
			}
		}
		
		return list;
	}
	
	
	/**
	 * create SXY Data
	 * @return
	 */
	private SGISXYTypeData createSXYData( final String path, final SGIProgressControl progress )
	throws FileNotFoundException
	{
		progress.setProgressMessage( PROGRESS_MESSAGE_READFILE );
		progress.setIndeterminateProgress( true );
		
		// get the number of columns
		final int ncol = this.getColumnNumber(path);
		if( ncol < 2 || ncol > 5 )
			return null;
		
		// read text data from file
		ArrayList columnIndexList = getSXYTextColumnIndexList( ncol );
		ArrayList titleList = new ArrayList();
		ArrayList[] listArray = this.createListArray( path, ncol, titleList, columnIndexList );
		if( listArray==null )
			return null;
		
		// allocate memory
		progress.setProgressMessage( PROGRESS_MESSAGE_CREATEDATA );
		final int dataLength = listArray[0].size();
		SGISXYTypeData data = null;
		String str = null;
		Double d = null;
		
		// SXY data
		// tArray - column title
		// xArray - X value : col = 2, 3, 4, 5
		// yArray - Y value : col = 2, 3, 4, 5
		// lArray - lower error : col = 4, 5
		// uArray - upper error : col = 4, 5
		// sArray - string label : col = 3, 5
		String[]  tArray = ( titleList.size() != 0 ) ? new String[ncol] : null;
		double[] xArray = new double[dataLength];
		double[] yArray = new double[dataLength];
		double[] lArray = ( ncol == 4 || ncol == 5) ? new double[dataLength] : null;
		double[] uArray = ( ncol == 4 || ncol == 5) ? new double[dataLength] : null;
		String[]  sArray = ( ncol == 3 || ncol == 5) ? new String[dataLength] : null;
		
		// set column titles
		for ( int ii=0; ii < titleList.size(); ii++ )
			tArray[ii] = (String)titleList.get(ii);
		
		// set values to memory
		progress.setIndeterminateProgress( false );
		for ( int ii=0; ii < dataLength; ii++ )		
		{
			progress.setProgressValue( (float)ii/(float)dataLength );
			// xArray
			str = (String)listArray[0].get(ii);
			d = SGUtilityText.getDouble(str);
			if ( d == null )
				return null;
			xArray[ii] = d.doubleValue();
			
			// yArray
			str = (String)listArray[1].get(ii);
			d = SGUtilityText.getDouble(str);
			if( d==null )
				return null;
			yArray[ii] = d.doubleValue();
			
			if( ncol == 4 || ncol == 5)
			{
				// lArray
				str = (String)listArray[2].get(ii);
				d = SGUtilityText.getDouble(str);
				if( d==null )
					return null;
				lArray[ii] = d.doubleValue();
				
				// uArray
				str = (String)listArray[3].get(ii);
				d = SGUtilityText.getDouble(str);
				if( d==null )
					return null;
				uArray[ii] = d.doubleValue();
			}
			
			// strArray
			if( ncol == 3 || ncol == 5)
				sArray[ii] = (String)listArray[ncol-1].get(ii);
		}
		
		// create data class
		data = new SGSXYData(tArray, xArray, yArray, lArray, uArray, sArray );
		return data;
	}
	
	
	/**
	 * create SXY Date Data
	 * @return
	 */
	private SGISXYTypeData createSXYDateData( final String path, final SGIProgressControl progress )
	throws FileNotFoundException
	{
		progress.setProgressMessage( PROGRESS_MESSAGE_READFILE );
		progress.setIndeterminateProgress( true );
		
		// get the number of columns
		final int ncol = this.getColumnNumber(path);
		if( ncol < 2 || ncol > 5 )
			return null;
		
		// read text data from file
		ArrayList columnIndexList = getSXYDateTextColumnIndexList( ncol );
		ArrayList titleList = new ArrayList();
		ArrayList[] listArray = this.createListArray( path, ncol, titleList, columnIndexList );
		if( listArray==null )
			return null;
		
		// allocate memory
		progress.setProgressMessage( PROGRESS_MESSAGE_CREATEDATA );
		final int dataLength = listArray[0].size();
		SGISXYTypeData data = null;
		String str = null;
		Double d = null;
		
		// SXY Date data
		// tArray - column title
		// dArray - date : col = 2, 3, 4, 5
		// yArray - Y value : col = 2, 3, 4, 5
		// lArray - lower error : col = 4, 5
		// uArray - upper error : col = 4, 5
		// sArray - string label : col = 3, 5
		String[]  tArray = ( titleList.size() != 0 ) ? new String[ncol] : null;
		String[]  dArray = new String[dataLength];
		double[] yArray = new double[dataLength];
		double[] lArray = ( ncol == 4 || ncol == 5) ? new double[dataLength] : null;
		double[] uArray = ( ncol == 4 || ncol == 5) ? new double[dataLength] : null;
		String[]  sArray = ( ncol == 3 || ncol == 5) ? new String[dataLength] : null;
		
		// set column titles
		for ( int ii=0; ii < titleList.size(); ii++ )
			tArray[ii] = (String)titleList.get(ii);
		
		// set values to memory
		for( int ii=0; ii<dataLength; ii++ )
		{
			progress.setProgressValue( (float)ii/(float)dataLength );
			
			// dArray
			dArray[ii] = (String)listArray[0].get(ii);
			
			// yArray
			str = (String)listArray[1].get(ii);
			d = SGUtilityText.getDouble(str);
			if( d==null )
				return null;
			yArray[ii] = d.doubleValue();
			
			if( ncol == 4 || ncol == 5)
			{
				// lArray
				str = (String)listArray[2].get(ii);
				d = SGUtilityText.getDouble(str);
				if( d==null )
					return null;
				lArray[ii] = d.doubleValue();
				
				// uArray
				str = (String)listArray[3].get(ii);
				d = SGUtilityText.getDouble(str);
				if( d==null )
					return null;
				uArray[ii] = d.doubleValue();
			}
			
			// strArray
			if( ncol == 3 || ncol == 5)
				sArray[ii] = (String)listArray[ncol-1].get(ii);
		}
		
		// create data class
		try
		{
			data = new SGSXYDateData( tArray, dArray, yArray, lArray, uArray, sArray );
		}
		catch( ParseException ex )
		{
		}
		
		return data;
	}
	
	
	
	/**
	 * create SXY Multiple data
	 * @return
	 */
	private SGSXYMultipleData createSXYMultipleData( final String path, final SGIProgressControl progress )
	throws FileNotFoundException
	{
		progress.setProgressMessage( PROGRESS_MESSAGE_READFILE );
		progress.setIndeterminateProgress( true );
		
		// get the number of columns
		final int ncol = this.getColumnNumber(path);
		if( ncol < 2 )
			return null;
		
		// read text data from file
		ArrayList columnIndexList = getSXYMultipleTextColumnIndexList( ncol );
		ArrayList titleList = new ArrayList();
		ArrayList[] listArray = this.createListArray( path, ncol, titleList, columnIndexList );
		if( listArray==null )
			return null;
		
		// allocate memory
		progress.setProgressMessage( PROGRESS_MESSAGE_CREATEDATA );
		final int dataLength = listArray[0].size();
		SGSXYMultipleData data = null;
		String str = null;
		Double d = null;
		
		// SXY Multiple data
		// tArray - column title
		// xArray - X value : col >= 2
		// yArray[] - Y values array : col >= 2
		String[]  tArray = ( titleList.size() != 0 ) ? new String[ncol] : null;
		double[] xArray = new double[dataLength];
		double[][] yArray = new double[ncol-1][];
		for( int ii=0; ii<ncol-1; ii++ )
			yArray[ii] = new double[dataLength];
		
		// set column titles
		for ( int ii=0; ii < titleList.size(); ii++ )
			tArray[ii] = (String)titleList.get(ii);
		
		// set values to memory
		for( int ii=0; ii<dataLength; ii++ )
		{
			progress.setProgressValue( (float)ii/(float)dataLength );
			
			// xArray
			str = (String)listArray[0].get(ii);
			d = SGUtilityText.getDouble(str);
			if( d==null )
				return null;
			xArray[ii] = d.doubleValue();
			
			// yArray
			for( int jj=0; jj<ncol-1; jj++ )
			{
				str = (String)listArray[jj+1].get(ii);
				d = SGUtilityText.getDouble(str);
				if( d==null )
					return null;
				yArray[jj][ii] = d.doubleValue();
			}
		}
		
		// create data class
		data = new SGSXYMultipleData( tArray, xArray, yArray );
		
		return data;
	}
	
	
	/**
	 * create SXY Sampling data
	 * @return
	 */
	private SGSXYMultipleData createSXYSamplingData( final String path, final double sRate, final SGIProgressControl progress )
	throws FileNotFoundException
	{
		progress.setProgressMessage( PROGRESS_MESSAGE_READFILE );
		progress.setIndeterminateProgress( true );
		
		// get the number of columns
		final int ncol = this.getColumnNumber(path);
		if( ncol < 1 )
			return null;
		
		// read text data from file
		ArrayList columnIndexList = getSXYMultipleTextColumnIndexList( ncol );
		ArrayList titleList = new ArrayList();
		ArrayList[] listArray = this.createListArray( path, ncol, titleList, columnIndexList );
		if( listArray==null )
			return null;
		
		// allocate memory
		progress.setProgressMessage( PROGRESS_MESSAGE_CREATEDATA );
		final int dataLength = listArray[0].size();
		SGSXYMultipleData data = null;
		String str = null;
		Double d = null;
		
		// SXY Sampling data
		// tArray - column title
		// yArray[] - Y values array : col >= 1
		String[]  tArray = ( titleList.size() != 0 ) ? new String[ncol] : null;
		double[] xArray = new double[dataLength];
		double[][] yArray = new double[ncol][];
		for( int ii=0; ii<ncol; ii++ )
			yArray[ii] = new double[dataLength];
		
		// set column titles
		for ( int ii=0; ii < titleList.size(); ii++ )
			tArray[ii] = (String)titleList.get(ii);
		
		// set values to memory
		for( int ii=0; ii<dataLength; ii++ )
		{
			progress.setProgressValue( (float)ii/(float)dataLength );
			
			// yArray
			for( int jj=0; jj<ncol; jj++ )
			{
				str = (String)listArray[jj].get(ii);
				d = SGUtilityText.getDouble(str);
				if( d==null )
					return null;
				yArray[jj][ii] = d.doubleValue();
			}
		}
		
		// create data class
		data = new SGSXYSamplingData( tArray, sRate, yArray );
		
		return data;
	}
	
	
	/**
	 * 
	 * @return
	 */
	private SGIVXYTypeData createVXYData( final String path, final boolean isPolar, final SGIProgressControl progress )
	throws FileNotFoundException
	{
		progress.setProgressMessage( PROGRESS_MESSAGE_READFILE );
		progress.setIndeterminateProgress( true );
		
		// get the number of columns
		final int ncol = this.getColumnNumber(path);
		if( ncol != 4 )
			return null;
		
		// read text data from file
		ArrayList columnIndexList = getVXYTextColumnIndexList( ncol );
		ArrayList titleList = new ArrayList();
		ArrayList[] listArray = this.createListArray( path, ncol, titleList, columnIndexList );
		if( listArray==null )
			return null;
		
		// allocate memory
		progress.setProgressMessage( PROGRESS_MESSAGE_CREATEDATA );
		final int dataLength = listArray[0].size();
		SGIVXYTypeData data = null;
		String str = null;
		Double d = null;

		// SXY Multiple data
		// tArray - column title
		// xArray - X value : col = 4
		// yArray - Y value : col = 4
		// mArray - magnitude or end point of X : col = 4
		// aArray - angle or end point of Y : col = 4
		String[]  tArray = ( titleList.size() != 0 ) ? new String[ncol] : null;
		double[] xArray = new double[dataLength];
		double[] yArray = new double[dataLength];
		double[] mArray = new double[dataLength];
		double[] aArray = new double[dataLength];
		
		// set column titles
		for ( int ii=0; ii < titleList.size(); ii++ )
			tArray[ii] = (String)titleList.get(ii);
		
		// set values to memory
		for( int ii=0; ii<dataLength; ii++ )
		{
			progress.setProgressValue( (float)ii/(float)dataLength );
	
			// xArray
			str = (String)listArray[0].get(ii);
			d = SGUtilityText.getDouble(str);
			if ( d == null )
				return null;
			xArray[ii] = d.doubleValue();
			
			// yArray
			str = (String)listArray[1].get(ii);
			d = SGUtilityText.getDouble(str);
			if( d==null )
				return null;
			yArray[ii] = d.doubleValue();
			
			// mArray
			str = (String)listArray[2].get(ii);
			d = SGUtilityText.getDouble(str);
			if( d==null )
				return null;
			if( isPolar && d.doubleValue() < 0.0 )
				return null;
			mArray[ii] = d.doubleValue();
			
			// aArray
			str = (String)listArray[3].get(ii);
			d = SGUtilityText.getDouble(str);
			if( d==null )
				return null;
			aArray[ii] = d.doubleValue();
		}

		// create data class
		data = new SGVXYData( tArray, xArray, yArray, mArray, aArray, isPolar );
		
		return data;
	}
	
	
	
	// Reads the first line and returns the number of token
	private int getColumnNumber( final String path )
	throws FileNotFoundException
	{
		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, 
			final ArrayList titleList,
			final ArrayList columnIndexList )
	throws FileNotFoundException
	{
		
		// create an array of list
		ArrayList[] listArray = new ArrayList[num];
		for( int ii=0; ii<listArray.length; ii++ )
		{
			listArray[ii] = new ArrayList();
		}
		
		// read the file
		BufferedReader br = null;
		try
		{
			br = new BufferedReader( new FileReader(path) );
			boolean isFirstLine = true;
			
			while( true )
			{
				// read a line
				final String line = SGUtilityText.readLine(br);
				if( line==null )
				{
					break;
				}
				
				// break the string into tokens
				final ArrayList tokenList = new ArrayList();
				// line is read from data file
				if( SGUtilityText.tokenize( line, tokenList, true ) == false )
				{
					return null;
				}
				
				// check the tokens
				if( tokenList.size()!=num )
				{
					if( tokenList.size()!=0 )
					{
						// format error
						return null;
					}
					// only contains spaces and tabs
					continue;
				}
				
				// format check
				ArrayList indexList = getColumnIndexListOfNumber(tokenList);
				
				if ( isFirstLine ) {
					if( this.evaluteTitleList( indexList ) ) {
						titleList.addAll(tokenList);
						isFirstLine = false;
						continue;
					}
				}
				
				if(machesNumberColumnIndex(columnIndexList, indexList) == false)
					return null;
				
				// 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 )
				{
					
				}
			}
		}
		
		// check array index
		final int dataLength = listArray[0].size();
		for( int ii=1; ii<listArray.length; ii++ )
		{
			if( listArray[ii].size()!=dataLength )
				return null;
		}
		
		return listArray;
	}
	
	// check index list : can token index convert column index ? 
	private boolean machesNumberColumnIndex(final ArrayList columnList, final ArrayList tokenIndexList){
		Integer column;
		Integer token;
		if(columnList.size() != tokenIndexList.size())
			return false;
		for(int ii=0; ii<columnList.size(); ii++){
			column = (Integer)columnList.get(ii);
			token  = (Integer)tokenIndexList.get(ii);
			if(column.intValue() == 1 && token.intValue() == 0)
				return false;
		}
		return true;
	}
	
//	public static void main( String[] args ) throws Exception
//	{
//	System.out.println("start");
//	
//	String path = "D:\\Tmp\\test.txt";
//	
//	ArrayList list = new ArrayList();
//	list.add( SGDataTypeConstants.VXY_DATA );
//	list.add( Boolean.FALSE );
//	
//	SGDataCreator c = new SGDataCreator();
//	SGData data = c.create( path, list );
//	
//	System.out.println(data);
//	
//	System.out.println("end");
//	}
	
	// returns a list of number convertable column index
	private static ArrayList getColumnIndexListOfNumber( final ArrayList tokenlist )
	{
		final String NUM_PATTERN = "^[+-]?[0-9]+(\\.[0-9]*)?([eE][+-]?[0-9]+)?$";
		Pattern pattern;
		Matcher matcher;
		ArrayList list = new ArrayList();
		pattern = Pattern.compile(NUM_PATTERN);
		for(int ii = 0; ii < tokenlist.size(); ii++){
			String token = (String)tokenlist.get(ii);
			matcher = pattern.matcher(token);			
			if(matcher.matches())
				list.add(new Integer(1));
			else
				list.add(new Integer(0));
		}
		return list;
	}
	
	// check title list
	private boolean evaluteTitleList( final ArrayList indexList )
	{
		boolean ret = true;
		if( indexList.size() == 0 )
			return false;
		for ( int ii=0; ii<indexList.size(); ii++) {
			Integer val = (Integer)indexList.get(ii);
			if (val.intValue() != 0)
				ret = false;
		}
		return ret;
	}
	
	/**
	 * Determine the data-type from the first line.
	 */
	public boolean getFileTypeCandidateList(
			final String path,
			final ArrayList cList
	) throws FileNotFoundException
	{
		BufferedReader br = null;
		try
		{
			br = new BufferedReader( new FileReader( path ) );
			
			ArrayList tokenList = this.getFirstTokenList(br);
			int tokenNum = tokenList.size();
			HashSet cSet = new HashSet();
			
			// get number convertable culumns
			ArrayList indexList = getColumnIndexListOfNumber(tokenList);
			
			// get titles
			if( this.evaluteTitleList(indexList) )
			{
				// this is title. read next line for indexList
				tokenList = this.getFirstTokenList(br);
				indexList = getColumnIndexListOfNumber(tokenList);
			}
			
			// SXY
			if( this.evaluateDataTypeSXY(tokenList) )
			{
				ArrayList columnIndexList = getSXYTextColumnIndexList(tokenNum);
				if( machesNumberColumnIndex( columnIndexList, indexList ) )
				{
					cSet.add(SGDataTypeConstants.SXY_DATA);
				}
			}
			
			// VXY
			if( this.evaluateDataTypeVXY(tokenList) )
			{
				ArrayList columnIndexList = getVXYTextColumnIndexList(tokenNum);
				if( machesNumberColumnIndex( columnIndexList, indexList ) )
				{
					cSet.add(SGDataTypeConstants.VXY_DATA);
				}
			}
			
			// SXY Multiple
			if( this.evaluateDataTypeSXYMultiple(tokenList) )
			{
				ArrayList columnIndexList = getSXYMultipleTextColumnIndexList(tokenNum);
				if( machesNumberColumnIndex( columnIndexList, indexList ) )
				{
					if( tokenNum>=3 )
					{
						cSet.add(SGDataTypeConstants.SXY_MULTIPLE_DATA);
					}
					
					if( tokenNum>=1 )
					{
						cSet.add(SGDataTypeConstants.SXY_SAMPLING_DATA);
					}
				}
			}
			
			// SXY Date
			if( this.evaluateDataTypeSXYDate( tokenList ) )
			{
				ArrayList columnIndexList = getSXYDateTextColumnIndexList(tokenNum);
				if( machesNumberColumnIndex( columnIndexList, indexList ) )
				{
					cSet.add(SGDataTypeConstants.SXY_DATE_DATA);
				}
			}
			
			cList.addAll( cSet );
		}
		catch( FileNotFoundException ex )
		{
			throw ex;
		}
		finally
		{
			if( br!=null )
			{
				try
				{
					br.close();
				}
				catch( IOException ex )
				{
					
				}
			}
		}
		
		return true;
	}
	
	
	
	/**
	 * 
	 */
	private boolean evaluateDataTypeSXY( final ArrayList tokenList )
	{
		final int size = tokenList.size();
		
		ArrayList numberIndexList = new ArrayList();
		if( size==2 | size==4 )
		{
			for( int ii=0; ii<size; ii++ )
			{
				numberIndexList.add( new Integer(ii) );
			}
		}
		else if( size==3 )
		{
			numberIndexList.add( new Integer(0) );
			numberIndexList.add( new Integer(1) );
		}
		else if( size==5 )
		{
			for( int ii=0; ii<4; ii++ )
			{
				numberIndexList.add( new Integer(ii) );
			}
		}
		else
		{
			return false;
		}
		
		
		boolean b = true;
		for( int ii=0; ii<numberIndexList.size(); ii++ )
		{
			final int index = ((Integer)numberIndexList.get(ii)).intValue();
			String str = (String)tokenList.get(index);
			Double d = SGUtilityText.getDouble(str);
			if( d==null )
			{
				b = false;
				break;
			}
		}
		
		return b;
	}
	
	
	/**
	 * 
	 */
	private boolean evaluateDataTypeVXY( final ArrayList tokenList )
	{
		boolean b = true;
		final int size = tokenList.size();
		if( size!=4 )
		{
			return false;
		}
		
		for( int ii=0; ii<size; ii++ )
		{
			String str = (String)tokenList.get(ii);
			Double d = SGUtilityText.getDouble(str);
			if( d==null )
			{
				b = false;
				break;
			}
		}
		
		return b;
	}
	
	
	
	/**
	 * 
	 */
	private boolean evaluateDataTypeSXYMultiple( final ArrayList tokenList )
	{
		boolean b = true;
		final int size = tokenList.size();
		for( int ii=0; ii<size; ii++ )
		{
			String str = (String)tokenList.get(ii);
			Double d = SGUtilityText.getDouble(str);
			if( d==null )
			{
				b = false;
				break;
			}
		}
		
		return b;
	}
	
	
	//
	private boolean evaluateDataTypeSXYDate( final ArrayList tokenList )
	{
		final int num = tokenList.size();
		if( num!=2 & num!=3 & num!=4 & num!=5 )
		{
			return false;
		}
		
		// date
		final ArrayList dList = new ArrayList();
		dList.add( tokenList.get(0) );
		
		final DateFormat df = DateFormat.getDateInstance();
		for( int ii=0; ii<dList.size(); ii++ )
		{
			final String str = (String)dList.get(ii);
			final Date d = SGUtilityText.getDate(str);
			if( d==null )
			{
				return false;
			}
		}
		
		
		// number
		final ArrayList nList = new ArrayList();
		nList.add( tokenList.get(1) );
		if( num==4 | num==5  )
		{
			nList.add( tokenList.get(1) );
			nList.add( tokenList.get(2) );
			nList.add( tokenList.get(3) );
		}
		
		for( int ii=0; ii<nList.size(); ii++ )
		{
			final String str = (String)nList.get(ii);
			final Double d = SGUtilityText.getDouble(str);
			if( d==null )
			{
				return false;
			}
		}
		
		return true;
	}
	
	
	/**
	 * Returns a list of tokens of the first line.
	 * @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();
			SGCSVTokenizer csvt = new SGCSVTokenizer(line, true); // from data file
			while (csvt.hasMoreTokens()) {
				try {
					String result = csvt.nextToken();
					tokenList.add(result);
				} catch (NoSuchElementException e) {
				}
			}
			final int size = tokenList.size();	// the number of tokens
			if( size!=0 )
			{
				break;
			}
		}
		
		return tokenList;
	}
	
	
}

