/*------------------------------------------------------------------------------*
 * File Name: famosFile.c				 										*
 * Creation: Sim 2006-12-4														*
 * Purpose: read famos file														*
 * Copyright (c) ABCD Corp.	2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010		*
 * All Rights Reserved															*
 * 																				*
 * Modification Log:															*
 *	Hong 12/18/09 QA80-14858 FAMOS_NEED_TRIGGER_TIME							*
 *	Sim 02-04-2010 QA81-15063 MOVE_IMP_FILE_INFO_OUT_FROM_COL_USER_INFO_TREE	*
 *	Sim 02-05-2010 QA81-15063 ROLL_BACK_MOVE_COL_INFO_OUT_OF_USER_TREE			*
 *	Hong 03/01/10 QA80-14858 FIX_ORIGIN_RUNTIME_ERR_IMPORT_SOME_FAMOS_FILE		*
 *	Hong 03/02/10 QA80-14858 FIX_SOME_DATASET_LOST_COVERED_BY_FOLLOWING_DATASET	*
 *	Hong 03/09/10 QA80-14858-P5 FIX_WRONG_Y_AXES_SCALE							*
 *	Hong 03/09/10 QA80-14858-P5 MATRIX_DATA_NO_NEED_TRANSPOSE_AFTER_READ_DATA_REQUIRED_ADDITIVE
 *	Hong 03/01/10 QA80-14858-P5 ADDITIVE_REQUIRED_ALL_SINGLE_COLUMN_DATA_INTO_WKS
 *	Hong 07/08/10 ORG-499-P1 FIX_FAIL_IMPORT_SPECAIL_FAMOS_FILE_WITH_UNKOWN_KEY	*
 *------------------------------------------------------------------------------*/
 
////////////////////////////////////////////////////////////////////////////////////
// Including the system header file Origin.h should be sufficient for most Origin
// applications and is recommended. Origin.h includes many of the most common system
// header files and is automatically pre-compiled when Origin runs the first time.
// Programs including Origin.h subsequently compile much more quickly as long as
// the size and number of other included header files is minimized. All NAG header
// files are now included in Origin.h and no longer need be separately included.
//
// Right-click on the line below and select 'Open "Origin.h"' to open the Origin.h
// system header file.
#include <Origin.h> 
////////////////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////////////////
// Include your own header files here.
#include <oErrMsg.h>

#include "famosFile.h"
#include <..\Originlab\fu_utils.h> ///---Sim 02-04-2010 QA81-15063 MOVE_IMP_FILE_INFO_OUT_FROM_COL_USER_INFO_TREE

////////////////////////////////////////////////////////////////////////////////////
// Start your functions here.

// these for construct info order
typedef enum {
	KEYID_UNKNOWN = 1,
	KEYID_CF = 2,
	KEYID_CK,
	KEYID_NO,
	KEYID_CT,
	KEYID_CB,
	KEYID_CI,
	KEYID_CG,
	KEYID_CD,
	KEYID_NT,
	KEYID_CZ,
	KEYID_CC,
	KEYID_CP,
	KEYID_CR,
	KEYID_ND,
	KEYID_CN,
	KEYID_CS,
	KEYID_NU,
	KEYID_Cb,
}FAMOS_KEYID;

int KeyOrder[20] =
{
	0,//TOP OF KEYS LIST
	-2,//KEYID_UNKNOWN = 1,
	1,//KEYID_CF = 2,
	1,//KEYID_CK,
	1,//KEYID_NO,
	1,//KEYID_CT,
	1,//KEYID_CB,
	1,//KEYID_CI,
	1,//KEYID_CG,
	4,//KEYID_CD,
	4,//KEYID_NT,
	4,//KEYID_CZ,
	3,//KEYID_CC,
	4,//KEYID_CP,
	4,//KEYID_CR,
	4,//KEYID_ND,
	4,//KEYID_CN,
	-1,//KEYID_CS,
	-2,//KEYID_NU,
	-1//KEYID_Cb,
};

#define MAX_ORDER 32767

// these for Data Type on Origin
int FamosDataType[14] =
{
	FSI_DOUBLE,	//FAMOS_NUMTYPE_UNKNOWN = 0,	// need correct
	FSI_BYTE,	//FAMOS_NUMTYPE_UBYTE ,
	FSI_CHAR,	//FAMOS_NUMTYPE_BYTE ,
	FSI_USHORT,	//FAMOS_NUMTYPE_USHORT,
	FSI_SHORT,	//FAMOS_NUMTYPE_SHORT ,
	FSI_ULONG,	//FAMOS_NUMTYPE_ULONG,
	FSI_LONG,	//FAMOS_NUMTYPE_LONG,
	FSI_REAL,	//FAMOS_NUMTYPE_FLOAT,
	FSI_DOUBLE,	//FAMOS_NUMTYPE_DOUBLE,
	FSI_DOUBLE,	//FAMOS_NUMTYPE_IMCREC,			// need correct
	FSI_DOUBLE,	//FAMOS_NUMTYPE_TIMEASC,		// need correct
	FSI_SHORT,	//FAMOS_NUMTYPE_2BYTED,
	FSI_DOUBLE	//FAMOS_NUMTYPE_ULONG48 = 13,	// need correct
};


//////////////////////////////////////////////////////////////////
// FamosFile class public function
//////////////////////////////////////////////////////////////////
int FamosFile::ReadInfo(TreeNode& trFileInfo)  //not completed
{
	//load all keys:
	Tree trAllKeys;
	int nRet, nStartPos = 0;
	///---Sim 09-25-2007 SHOW_MSG_FOR_UNSUPPORTED_VERSION
	//while( _KEYREAD_ERR_OK == ( nRet = addNextKey(trAllKeys, &nStartPos) ) ) {};
	TreeNode trKey;
	while( _KEYREAD_ERR_OK == ( nRet = addNextKey(trAllKeys, trKey, &nStartPos) ) )
	{
		if ( (trKey.wID) && (FAMOS_KEYID_DF == trKey.wID.nVal || FAMOS_KEYID_CF == trKey.wID.nVal) )
		{
			if ( (trKey.nVer) && trKey.nVer.nVal < 2 )
				return IMPERR_FAMOS_UNSUPPORT_VER;
		}
		
	}
	///---END SHOW_MSG_FOR_UNSUPPORTED_VERSION
	
	
	if ( _KEYREAD_ERR_ERR == nRet )
		return IMPERR_HEADER;

	constructKeysInfo(trFileInfo, trAllKeys);
	
	m_trFileInfo.Replace(trFileInfo);
	
	return 0;
}

int FamosFile::Import(Layer& lyDest, TreeNode& trInfo, bool& bSampleInterval, int nC1)//, TreeNode& trFileInfo)
{
	bSampleInterval = m_bSampleInterval = false;
	
	int nRet = ReadInfo(m_trFileInfo);
	if ( nRet )
		return nRet;
	
	// data is imported start from nC1 col of datasheet, delete the cols more than nC1
	//Worksheet wks(lyDest);
	//if ( wks )
	//{
		//wks.SetSize(-1, nC1);
	//}
	if ( m_orng )
		m_orng.Reset();
	
	int nCol = nC1;
	TreeNode trCG0 = m_trFileInfo.CG0;
	int			nWksIndex = -1; /// Hong 03/04/10 QA80-14858 FIX_SOME_DATASET_LOST_COVERED_BY_FOLLOWING_DATASET
	if ( trCG0 )
	{
		foreach(TreeNode trCG in trCG0.Children)
		{
			/// Hong 03/04/10 QA80-14858 FIX_SOME_DATASET_LOST_COVERED_BY_FOLLOWING_DATASET
			//importDataFields(lyDest, trCG, nCol);
			importDataFields(lyDest, trCG, nCol, nWksIndex);
			/// end FIX_SOME_DATASET_LOST_COVERED_BY_FOLLOWING_DATASET
		}
	}

	m_orng.Add((Datasheet)lyDest, nC1, "Range", nCol - 1);

	// Single value is saved in tree info.
	TreeNode trSingleVariable = trInfo.AddNode("SingleVariable");
	
	TreeNode trCT0 = m_trFileInfo.CT0;
	if ( trCT0 )
	{
		TreeNode trSingleText = trSingleVariable.AddNode("SingleText");
		foreach(TreeNode trCT in trCT0.Children)
		{
			addSingleText(trSingleText, trCT);
		}
	}
	
	TreeNode trCI0 = m_trFileInfo.CI0;
	if ( trCI0 )
	{
		TreeNode trSingleValue = trSingleVariable.AddNode("SingleValue");
		foreach(TreeNode trCI in trCI0.Children)
		{
			addSingleValue(trSingleValue, trCI);
		}
	}
	
	bSampleInterval = m_bSampleInterval; // m_bSampleInterval is changed after importing
	return 0;
}
/// Sophy 5/04/2008 SHOW_WARNING_MESSAGE_WHEN_IMPORT_INVALID_DATA_FILE
bool FamosFile::HasImportedData()
{
	return bHasImportedData;
}
/// End SHOW_WARNING_MESSAGE_WHEN_IMPORT_INVALID_DATA_FILE
//////////////////////////////////////////////////////////////////
// FamosFile class private function
//////////////////////////////////////////////////////////////////
/// Hong 03/04/10 QA80-14858 FIX_SOME_DATASET_LOST_COVERED_BY_FOLLOWING_DATASET
//int FamosFile::importDataFields(Layer& lyDest, TreeNode& trCG, int& nFirstCol)
int FamosFile::importDataFields(Layer& lyDest, TreeNode& trCG, int& nFirstCol, int& nWksIndex)
/// end FIX_SOME_DATASET_LOST_COVERED_BY_FOLLOWING_DATASET
{
	TreeNode trCC0 = trCG.CC0;
	
	bool bHasZ = false;
	/// Hong 03/01/10 QA80-14858-P5 ADDITIVE_REQUIRED_ALL_SINGLE_COLUMN_DATA_INTO_WKS
	//if ( trCG.CZ )
	if ( trCG.CZ && trCG.CZ.para.nSegmentLengh.nVal > 0 )
	/// end ADDITIVE_REQUIRED_ALL_SINGLE_COLUMN_DATA_INTO_WKS
		bHasZ = true;
	
	if ( bHasZ )
	{
		TreeNode trCD = trCG.CD;
		foreach(TreeNode trCC in trCC0.Children)
		{
			if ( trCC.CD )
				trCD = trCC.CD;
			/// Hong 03/04/10 QA80-14858 FIX_SOME_DATASET_LOST_COVERED_BY_FOLLOWING_DATASET
			/*
			MatrixLayer ml = lyDest;
			if ( !ml )
			{
				int nLayer = 0;
				if ( !m_mp )
				{
					m_mp.Create("Origin");
				}
				else
				{
					nLayer = m_mp.AddLayer();
				}
				ml = m_mp.Layers(nLayer);
				lyDest = ml;
			}
			*/
			MatrixLayer	ml = lyDest;
			if ( !ml && !m_mp )
			{
				m_mp.Create("Origin");
				ml = m_mp.Layers(0);
				lyDest = ml;
			}
			else if ( !m_mp )
			{
				ml.GetParent(m_mp);
			}
			else
			{
				ml = m_mp.Layers(m_mp.AddLayer());
				lyDest = ml;
			}
			/// END FIX_SOME_DATASET_LOST_COVERED_BY_FOLLOWING_DATASET
			
			importDataMatrix(ml, trCC, trCG.CZ, trCD);
		}
	}
	else
	{
		/// Hong 03/04/10 QA80-14858 FIX_SOME_DATASET_LOST_COVERED_BY_FOLLOWING_DATASET
		/*
		Worksheet wksDest = lyDest;
		if ( !wksDest ) 
		{
			int nLayer = 0;
			if ( !m_wp )
			{
				m_wp.Create("Origin");
			}
			else
			{
				nLayer = m_wp.AddLayer();
			}
			wksDest = m_wp.Layers(nLayer);
			lyDest = wksDest;
			nFirstCol = 0;
		}
		*/
		Worksheet 	wksDest = lyDest;
		if ( !wksDest && !m_wp )
		{
			m_wp.Create("Origin");
			nWksIndex = 0;
			wksDest = m_wp.Layers(nWksIndex);
			lyDest = wksDest;
			nFirstCol = 0;
		}
		else if ( !m_wp )
		{
			wksDest.GetParent(m_wp);
			nWksIndex = wksDest.GetIndex();
		}
		else
		{
			wksDest = m_wp.Layers(nWksIndex);
		}
		/// end FIX_SOME_DATASET_LOST_COVERED_BY_FOLLOWING_DATASET
		
		// initialize the size of worksheet columns
		//int nFirstCol = wks_find_empty_column(wksDest);
		//if ( nFirstCol < 0 )
			//nFirstCol = wksDest.GetNumCols();
		
		//int nCol = nFirstCol;
		int nNumCC = trCC0.GetNodeCount();
		//int nXCol = -1;
		//int nFieldType = trCG.para.nFieldType.nVal;
		// prepare one column to x-axis, before we don't know whether x component is exist in data field
		//if ( isXYDataField(nFieldType) ) // XY mode
		//{
			//nXCol = nCol++;
			//nNumCC++; 
		//}
		
		if ( wksDest.GetNumCols() < nFirstCol + nNumCC )
			wksDest.SetSize(-1, nFirstCol + nNumCC);
	
		// import data field
		int nCol = nFirstCol;
		int nFieldType = trCG.para.nFieldType.nVal;
		bool bComplexData = isComplexDataField(nFieldType);
		bool bHasX = false;
		
		Column col;
		TreeNode trCN;
		TreeNode trCD = trCG.CD;
		TreeNode trCC;
		
		/// Hong 12/18/09 QA80-14858 FAMOS_NEED_TRIGGER_TIME
		TreeNode	trNT = trCG.NT;
		/// end FAMOS_NEED_TRIGGER_TIME
		
		// import x-axis
		foreach(trCC in trCC0.Children)
		{
			string strType = getComponentType(nFieldType, trCC.para.nComIndx.nVal);
			if ( "X" == strType ) // component is x-axis
			{
				col.Attach(wksDest, nCol++);
				col.SetType(OKDATAOBJ_DESIGNATION_X);
				/// Hong 12/18/09 QA80-14858 FAMOS_NEED_TRIGGER_TIME
				//importComponent(col, trCC, trCN);
				importComponent(col, trCC, trCN, trNT);
				/// end FAMOS_NEED_TRIGGER_TIME
				bHasX = true;
			}
		}
		
		// import non x-axis
		foreach(trCC in trCC0.Children)
		{
			string strType = getComponentType(nFieldType, trCC.para.nComIndx.nVal);
			if ( "X" != strType ) // component is non x-axis
			{
				col.Attach(wksDest, nCol++);
				col.SetType(OKDATAOBJ_DESIGNATION_Y);
			
				/// Hong 12/18/09 QA80-14858 FAMOS_NEED_TRIGGER_TIME
				//importComponent(col, trCC, trCN);
				importComponent(col, trCC, trCN, trNT);
				/// end FAMOS_NEED_TRIGGER_TIME
				
				if ( "X" != strType && "Y" != strType && "real" != strType)
				{
					col.SetLongName(col.GetLongName() + " - " + strType);
				}
				
				if ( trCC.CD )
					trCD = trCC.CD;
				
				if ( bComplexData )
				{	// pass name to next component
					if ( trCC.CN )
						trCN = trCC.CN;
				}
			}
		}

		// the size need adjust, maybe x-axis component is in data field, 
		// but we had assumed it isn't exist, and prepare it firstly.
		//wksDest.SetSize(-1, nFirstCol + nNumCC);

		if ( !bHasX && trCD )	// time column isn't set by x-axis component, it should be set by CD key
		{
			//if ( bUseSampleInterval )
			//{
				// has created x column, need remove it
				//if ( 0 <= nXCol ) 
				//{
					//wksDest.DeleteCol(nXCol);
					//nNumCC--;
				//}
				
				int nBuffRef = trCG.CC0.CC.CP.para.nBuffRef.nVal;
				setSampleInterval(wksDest, nFirstCol, nNumCC, trCD, nBuffRef);
				
				m_bSampleInterval = true;
			//}
			//else
			//{	// add x-axis column
				//if ( -1 == nXCol ) // didn't create X column yet
				//{
					//string strColName;
					//wksDest.InsertCol(nFirstCol, NULL, strColName);
					//nXCol = nFirstCol;
				//}
				//
				//col.Attach(wksDest, nXCol);
				//int nDataSize = wksDest.Columns(nXCol+1).GetUpperBound()+1;
				//int nBuffRef = trCG.CC0.CC.CP.para.nBuffRef.nVal;
				//setXColData(col, nDataSize, trCD, nBuffRef);
			//}
		}
		
		nFirstCol += nNumCC;
	}	
	return 0;
}

void FamosFile::setSampleInterval(Worksheet& wks, int nC1, int nNumCols, const TreeNode& trCD, int nBuffRef)
{
	double x0, dx;
	dx = trCD.para.dx.dVal;
	x0 = getX0FromBufDesc(trCD, nBuffRef);

	for ( int ii = nC1; ii < nC1 + nNumCols; ii++ )
	{
		Column cc(wks, ii);
		int nRet = wks.SetEvenSampling(x0, dx, cc, trCD.para.strUnit.strVal, _L(""));
		if ( nRet )
			ASSERT(false);		
	}
}

void FamosFile::setXColData(Column& colX, int nDataSize, const TreeNode& trCD, int nBuffRef)
{
	double x0, dx;
	dx = trCD.para.dx.dVal;
	
	x0 = getX0FromBufDesc(trCD, nBuffRef);
	
	colX.SetFormat(OKCOLTYPE_NUMERIC);
	colX.SetInternalData(FSI_DOUBLE);
	colX.SetType(OKDATAOBJ_DESIGNATION_X);
	Dataset dsx(colX);
	dsx.Data(x0, x0+ dx*(nDataSize-1), dx);
	colX.SetUnits(trCD.para.strUnit.strVal);
}

double FamosFile::getX0FromBufDesc(const TreeNode& trCD, int nBuffRef)
{
	double x0 = 0;
	if ( 1 == trCD.nVer.nVal )
	{
		x0 = getX0FromBufDesc(nBuffRef);
	}
	else if ( 2 <= trCD.nVer.nVal )
	{
		x0 = trCD.para.x0.dVal;
		if ( 1 == trCD.para.nPretriggerUse.nVal )
			x0 = getX0FromBufDesc(nBuffRef);
	}
	return x0;
}

double FamosFile::getX0FromBufDesc(int nBuffRef)
{
	/// Hong 12/18/09 QA80-14858 FAMOS_NEED_TRIGGER_TIME
	/*
	TreeNode trCb0 = m_trFileInfo.GetNode("Cb0");
	
	foreach(TreeNode trCb in trCb0.Children)
	{
		TreeNode trBufs = trCb.Bufs; // there are more than 1 bufs in Cb key, need search all bufs
		foreach(TreeNode trBuf in trBufs.Children)
		{
			if ( trBuf.nBufferRefence.nVal == nBuffRef )
			{
				return trBuf.x0.dVal;
			}
		}
	}
	/// end FAMOS_NEED_TRIGGER_TIME
	*/
	TreeNode	trBuf = getBufInCb(nBuffRef);
	if ( trBuf )
		return trBuf.x0.dVal;
	
	return 0;
}

bool FamosFile::isXYDataField(int nDataFieldType)
{
	return (2 == nDataFieldType || 3 == nDataFieldType);
}

bool FamosFile::isComplexDataField(int nDataFieldType)
{
	return (4 == nDataFieldType || 5 == nDataFieldType || 6 == nDataFieldType);
}

string FamosFile::getComponentType(int nDataFieldType, int nComponentIndex)
{
	switch ( nDataFieldType )
	{
	case 1: // Real number
		if ( 1 == nComponentIndex )
			return "real";
		break;
	case 2: // XY, x monotonous increasing
	case 3: // 3 XY, characteristic curve
		if ( 1 == nComponentIndex )
			return "Y";
		if ( 2 == nComponentIndex )
			return "X";
		break;
	case 4: // Complex, real, imaginary part
		if ( 1 == nComponentIndex )
			return "real part";
		if ( 2 == nComponentIndex )
			return "imaginary part";
		break;
	case 5: // Complex, magnitude, phase
		if ( 1 == nComponentIndex )
			return "magnitude";
		if ( 2 == nComponentIndex )
			return "phase";
		break;
	case 6: // Complex, magnitude in dB, phase
		if ( 1 == nComponentIndex )
			return "magnitude in dB";
		if ( 2 == nComponentIndex )
			return "phase";
		break;
	}
	return "";
}

/// Hong 12/18/09 QA80-14858 FAMOS_NEED_TRIGGER_TIME
//int FamosFile::importComponent(Column& col, TreeNode& trCC, TreeNode& trCNLast) // = NULL
int FamosFile::importComponent(Column& col, TreeNode& trCC, TreeNode& trCNLast, TreeNode& trNT) // = NULL, = NULL
/// end FAMOS_NEED_TRIGGER_TIME
{
	TreeNode trCP = trCC.CP;
	if ( !trCP )
		return -1; // need better error message
	
	int nBuffRef = trCP.para.nBuffRef.nVal;
	vector<char> vc;
	getBuffer(vc, nBuffRef);
	if ( (0 != trCP.para.nOffset.nVal) || (0 != trCP.para.nIntervalByte.nVal) )
		filtrateBuffer(vc, trCP.para.nBytes.nVal, trCP.para.nOffset.nVal, trCP.para.nIntervalByte.nVal);	
	if ( (trCP.para.nSignBits.nVal < trCP.para.nBytes.nVal * 8) || (0 != trCP.para.sMask.nVal) )
		setSignificantBuffer(vc, trCP.para.nBytes.nVal, trCP.para.nSignBits.nVal, trCP.para.sMask.nVal);
	
	// setup column size
	int nRows = vc.GetSize() / trCP.para.nBytes.nVal;
	col.SetUpperBound(nRows - 1);
	setDataFormat(col, trCP.para.nNumberFormat.nVal, trCP.para.nBytes.nVal);
	
	// load data to column
	int nElementSize;				
	UINT nNumElements;				
	LPVOID lpData = col.GetInternalDataBuffer(&nElementSize, &nNumElements);
	if ( nElementSize != trCP.para.nBytes.nVal )
		return -1;
		
	if ( nNumElements > nRows )	// fix out of range
		nNumElements = nRows;
	
	UINT nSizeToLoad = nElementSize * nNumElements;
	
	memcpy(lpData, vc, nSizeToLoad);
	
	TreeNode trCR = trCC.CR;
	if ( trCR )
	{
		if ( 1 == trCR.para.nTransformation.nVal )
			setColFactorAndOffset(col, trCR.para.dFactor.dVal, trCR.para.dOffset.dVal);
		col.SetUnits(trCR.para.strUnit.strVal);
	}
	
	TreeNode trCN = trCC.CN;
	if ( !trCN && trCNLast )
		trCN = trCNLast;
	
	if ( trCN )
	{
		col.SetLongName(trCN.para.strName.strVal);
		col.SetComments(trCN.para.strComment.strVal);
	}
	
	///---Sim 2007-1-27 ADD_USER_INFO_TREE
	string strColumnInfo = "ColumnInfo";
	Tree trColumnInfo;
	trColumnInfo.AddTextNode(m_strFileName, "ImportFile");
	trColumnInfo.Enable = ENABLE_READ_ONLY;
	trColumnInfo.SetAttribute(STR_ATTRIB_BRANCH, GETNBRANCH_OPEN);
	/// Hong 12/18/09 QA80-14858 FAMOS_NEED_TRIGGER_TIME
	if ( trNT )
	{
		double		dVal = getTriggerTime(trNT, nBuffRef);
		if ( 0 != dVal )
		{
			TreeNode	trDate = trColumnInfo.AddNumericNode(dVal, "Date", TRGP_DOUBLE);
			trDate.SetAttribute(STR_LABEL_ATTRIB, _L("Created Date"));
			trDate.SetAttribute(STR_ATTRIB_NUMFMT, "D10");
		}
	}
	/// end FAMOS_NEED_TRIGGER_TIME
	///---Sim 02-05-2010 QA81-15063 ROLL_BACK_MOVE_COL_INFO_OUT_OF_USER_TREE
	//trColumnInfo.Show = 0; ///---Sim 02-04-2010 QA81-15063 MOVE_IMP_FILE_INFO_OUT_FROM_COL_USER_INFO_TREE
	//set_user_info(col, strColumnInfo, trColumnInfo);
	fu_set_import_file_info(col, trColumnInfo, strColumnInfo, IMPORT_INFO_TO_USER_TREE);
	///---END QA81-15063 ROLL_BACK_MOVE_COL_INFO_OUT_OF_USER_TREE
	///---END ADD_USER_INFO_TREE
	///---Sim 02-04-2010 QA81-15063 MOVE_IMP_FILE_INFO_OUT_FROM_COL_USER_INFO_TREE
	///---Sim 02-05-2010 QA81-15063 ROLL_BACK_MOVE_COL_INFO_OUT_OF_USER_TREE
	// roll back move column info out of user tree, as CP said
	//fu_set_import_file_name_info(col, m_strFileName);
//
	//trColumnInfo.RemoveChild("ImportFile");
	//trColumnInfo.Show = 1;
	//set_import_file_info(col, trColumnInfo, "Famos");
	///---END QA81-15063 ROLL_BACK_MOVE_COL_INFO_OUT_OF_USER_TREE
	///---END QA81-15063 MOVE_IMP_FILE_INFO_OUT_FROM_COL_USER_INFO_TREE
	/// Sophy 5/04/2008 SHOW_WARNING_MESSAGE_WHEN_IMPORT_INVALID_DATA_FILE
	if( !bHasImportedData )
		bHasImportedData = true;
	/// End SHOW_WARNING_MESSAGE_WHEN_IMPORT_INVALID_DATA_FILE
	return 0;
}

/// Hong 12/18/09 QA80-14858 FAMOS_NEED_TRIGGER_TIME
double	FamosFile::getTriggerTime(TreeNode& trNT, int nBuffRef)
{
	ASSERT(trNT && trNT.para);
	TreeNode		trPara = trNT.para;
	double			dVal = 0;
	if ( trPara.nYear.nVal >= 1980 )
	{
		SYSTEMTIME	systime;
		systime.wYear = trPara.nYear.nVal;
		systime.wMonth = trPara.nMonth.nVal;
		systime.wDay = trPara.nDay.nVal;
		systime.wHour = trPara.nHours.nVal;
		systime.wMinute = trPara.nMinutes.nVal;
		systime.wSecond = (int)trPara.dSeconds.dVal;
		systime.wMilliseconds = 1000 * (trPara.dSeconds.dVal - systime.wSecond);
		SystemTimeToJulianDate(&dVal, &systime);
	}
	double		dAddTime = getAddTime(nBuffRef);
	if ( dAddTime > 0 )
	{
		dAddTime /= 86400;
		dVal += dAddTime;
	}
	return dVal;
}

double	FamosFile::getAddTime(int nBuffRef)
{
	TreeNode	trBuf = getBufInCb(nBuffRef);
	if ( trBuf )
		return trBuf.dAddTime.dVal;

	return 0;
}

TreeNode	FamosFile::getBufInCb(int nBuffRef)
{
	TreeNode	trInvalid;
	TreeNode 	trCb0 = m_trFileInfo.GetNode("Cb0");
	if ( !trCb0 )
		return trInvalid;
	
	foreach ( TreeNode trCb in trCb0.Children )
	{
		TreeNode trBufs = trCb.Bufs; // there are more than 1 bufs in Cb key, need search all bufs
		foreach ( TreeNode trBuf in trBufs.Children )
		{
			if ( trBuf.nBufferRefence.nVal == nBuffRef )
				return trBuf;
		}
	}
	return trInvalid;
}
/// end FAMOS_NEED_TRIGGER_TIME

void setColFactorAndOffset(Column& col, double dFactor, double dOffset)
{
	// get data
	vectorbase& vb = col.GetDataObject();
	vector<double> vv;
	vv = vb;
	
	// transfer data
	vv *= dFactor;
	vv += dOffset;
	
	// set data
	col.SetInternalDataType(FSI_DOUBLE, 0);
	Dataset ds(col);
	ds = vv;
}

void setColFactorAndOffset(MatrixLayer& ml, double dFactor, double dOffset)
{
	MatrixObject mi(ml, 0);
	// get data
	matrixbase& mb = mi.GetDataObject();
	matrix<double> mat;
	mat = mb;
	
	// transfer data
	mat *= dFactor;
	mat += dOffset;
	
	// set data
	ml.SetInternalDataType(FSI_DOUBLE, 0);
	Matrix Mat(ml);
	Mat = mat;
}

//#define _SIGNIFICANT_BIG_ENDIAN

void FamosFile::setSignificantBuffer(vector<char>& vcBuf, int nSampleBytes, int nSignBits, short sMask)
{
#ifdef	_SIGNIFICANT_BIG_ENDIAN
	byte Mask[8] = { 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80}
	// bits { 11111111, 11111110, 11111100, 11111000, 11110000, 11100000, 11000000, 10000000}
#else // significant little endian
	byte Mask[8] = { 0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01}
	// bits { 11111111, 01111111, 00111111, 00011111, 00001111, 00000111, 00000011, 00000001}
#endif // _SIGNIFICANT_BIG_ENDIAN
	
	int nSampleBits = nSampleBytes * 8;
	if ( nSignBits > nSampleBits )
		return;

	// To get significant bits, just only clean invalid bits
	int nInvalidBits = nSampleBits - nSignBits;
	int nByteMultiples = nInvalidBits / 8;
	int nBitRemainder = nInvalidBits % 8;
	
	byte byteData;
	byte byteMask = Mask[nBitRemainder];
	int nNumSamples = vcBuf.GetSize() / nSampleBytes;
	LPVOID lpSample = vcBuf;
	// Significant bits shall affect each sample data in buffer.
	for ( int nIndexSample = 0; nIndexSample < nNumSamples; nIndexSample++ )
	{
		// if invalid bits is not multiple of 8 bits ( one bytes ).
		// Need clean invalid bits from two different position.
		
#ifdef	_SIGNIFICANT_BIG_ENDIAN
		// clean invalid bits for multiple of 8 bits
		byteData = 0;
		if ( nBitMultiple > 0 )
			memcpy(lpSample, &byteData, nByteMultiples);
				
		// clean invalid bits for remainder of 8 bits
		if ( nBitRemainder > 0)
		{
			int nPosRemainder = nByteMultiples;
			memcpy(&byteData, lpSample + nPosRemainder, 1);
			byteData &= byteMask;
			memcpy(lpSample + nPosRemainder, &byteData, 1);
		}
#else // significant little endian
		// clean invalid bits for multiple of 8 bits
		byteData = 0;
		if ( nByteMultiples > 0 )
		{
			int nPosMultiple = nSampleBytes - nByteMultiples;
			memcpy(lpSample + nPosMultiple, &byteData, nByteMultiples);
		}
				
		// clean invalid bits for remainder of 8 bits
		if ( nBitRemainder > 0)
		{
			int nPosRemainder = nSampleBytes - nByteMultiples - 1;
			memcpy(&byteData, lpSample + nPosRemainder, 1);
			byteData &= byteMask;
			memcpy(lpSample + nPosRemainder, &byteData, 1);
		}
#endif // _SIGNIFICANT_BIG_ENDIAN

		lpSample += nSampleBytes;
	}
	
	if ( 0 != sMask )
		warning_msg_box("Famos file with mask bits, Please contact with developer of famos.", false);
}

void FamosFile::filtrateBuffer(vector<char>& vcBuf, int nSampleBytes, int nOffset, int nIntervalByte)
{
	int nNumSample = ((vcBuf.GetSize() - nOffset) + nIntervalByte) / (nIntervalByte + nSampleBytes);
	
	vector<char> vcSample(nNumSample * nSampleBytes);
	LPVOID lpSample = vcSample;
	LPVOID lpBuf	= vcBuf;
	lpBuf += nOffset;
	for (int i = 0; i < nNumSample; i++ )
	{
		memcpy(lpSample, lpBuf, nSampleBytes);
		lpSample += nSampleBytes;
		lpBuf += (nSampleBytes + nIntervalByte);
	}
	vcBuf = vcSample;
}


int FamosFile::getBuffer(vector<char>& vc, int nBuffRef)
{
	TreeNode trCb0 = m_trFileInfo.GetNode("Cb0");

	vector<int> vPos;
	foreach(TreeNode trCb in trCb0.Children)
	{
		TreeNode trBufs = trCb.Bufs; // there are more than 1 bufs in Cb key, need search all bufs
		foreach(TreeNode trBuf in trBufs.Children)
		{
			if ( trBuf.nBufferRefence.nVal == nBuffRef )
			{
				int nDataPos = getDataPosition(trBuf.nIndexSamplesKey.nVal); // to search CS key
				if ( nDataPos < 0 )
					continue;
				int nOffsetBuf = trBuf.nOffsetBufferInSamplesKey.nVal;
				int nBufLenght = trBuf.nBufLength.nVal;
				int nOffsetFirstSample = trBuf.nOffsetFirstSampleInBuffer.nVal;
				int nFilledBytes = trBuf.nBufferFilledBytes.nVal;
				
				if ( nFilledBytes <= nBufLenght - nOffsetFirstSample)
				{
					int nOff, nLen;
					nOff = nDataPos + nOffsetBuf + nOffsetFirstSample;
					nLen = nFilledBytes;
					vPos.Add(nOff);
					vPos.Add(nLen);
				}
				else
				{
					// load the ring buffer datas
					int nOff1, nLen1, nOff2, nLen2;
					nOff1 = nDataPos + nOffsetBuf + nOffsetFirstSample;
					nLen1 = nBufLenght - nOffsetFirstSample;
					nOff2 = nDataPos + nOffsetBuf;
					nLen2 = nFilledBytes - nLen1;
					
					vPos.Add(nOff1);
					vPos.Add(nLen1);					
					vPos.Add(nOff2);
					vPos.Add(nLen2);
				}
			}
		}
	}
	
	if ( !m_BufMag.GetBuffer(vc, vPos) )// check buffer pool
	{	
		// read from file
		int nOff, nLen;
		int nOriginalSize;
		for (int i = 0; i < vPos.GetSize(); i += 2 )
		{
			nOff = vPos[i];
			nLen = vPos[i+1];
			
			nOriginalSize = vc.GetSize();
			vc.SetSize(nOriginalSize + nLen);
			LPVOID lpData = vc;
			lpData += nOriginalSize;

			Seek(nOff, file::begin);
			if( nLen != Read(lpData, nLen) )
				return -1; // faild to read, need better error message
		}
		
		m_BufMag.SetBuffer(vc, vPos);
	}
	
	return 0;
}

int FamosFile::getDataPosition(int nIndexSamplesKey)
{
	TreeNode trCS0 = m_trFileInfo.CS0;
	foreach(TreeNode trCS in trCS0.Children)
	{
		if ( trCS.para.nIndex.nVal == nIndexSamplesKey )
			return trCS.para.nDataPos.nVal;
	}
	return -1;
}

int FamosFile::setDataFormat(Column& col, int nNumberFormat, int nBytes)
{
	col.SetFormat(OKCOLTYPE_NUMERIC);
	col.SetInternalData(FamosDataType[nNumberFormat]);
	
	return 0;
}

int FamosFile::setDataFormat(MatrixLayer& ml, int nNumberFormat, int nBytes)
{
	ml.SetInternalDataType(FamosDataType[nNumberFormat], 0);
	
	return 0;
}

void FamosFile::addSingleText(TreeNode& trSingleText, const TreeNode& trCT)
{
	TreeNode trText = trSingleText.AddNode(trCT.para.strName.strVal);
	trText.Value.strVal = trCT.para.strValue.strVal;
	if ( !trCT.para.strComment.strVal.IsEmpty() )
		trText.Comment.strVal = trCT.para.strComment.strVal;
}

void FamosFile::addSingleValue(TreeNode& trSingleValue, const TreeNode& trCI)
{
	TreeNode trValue = trSingleValue.AddNode(trCI.para.strName.strVal);
	trValue.AddNode(trCI.para.Value);
	if ( !trCI.para.strComment.strVal.IsEmpty() )
		trValue.Comment.strVal = trCI.para.strComment.strVal;
	if ( !trCI.para.strUnit.strVal.IsEmpty() )
		trValue.Unit.strVal = trCI.para.strUnit.strVal;
}

int FamosFile::importDataMatrix(MatrixLayer& ml, TreeNode& trCC, TreeNode& trCZ, TreeNode& trCD)
{
	TreeNode trCP = trCC.CP;
	if ( !trCP )
		return -1; // need better error message
	TreeNode trCR = trCC.CR;
	TreeNode trCN = trCC.CN;
	
	int nBytesSample = trCP.para.nBytes.nVal;
	int nBuffRef = trCP.para.nBuffRef.nVal;
	vector<char> vc;
	getBuffer(vc, nBuffRef);
	if ( (0 != trCP.para.nOffset.nVal) || (0 != trCP.para.nIntervalByte.nVal) )
		filtrateBuffer(vc, nBytesSample, trCP.para.nOffset.nVal, trCP.para.nIntervalByte.nVal);	
	if ( (trCP.para.nSignBits.nVal < nBytesSample * 8) || (0 != trCP.para.sMask.nVal) )
		setSignificantBuffer(vc, nBytesSample, trCP.para.nSignBits.nVal, trCP.para.sMask.nVal);
	
	// setup column size
	int nSize = vc.GetSize() / nBytesSample;
	int nRows = trCZ.para.nSegmentLengh.nVal;
	/// Hong 03/01/10 QA80-14858 FIX_ORIGIN_RUNTIME_ERR_IMPORT_SOME_FAMOS_FILE
	// Hong, per document, in this case, only Z coordinate is valid, after talk with Max, just all import into one column as FlexPro
	if ( nRows <= 0 )
	{
		ASSERT(FALSE); /// Hong 03/01/10 QA80-14858-P5 ADDITIVE_REQUIRED_ALL_SINGLE_COLUMN_DATA_INTO_WKS
		if ( nSize > 0 )
			nRows = nSize;
		else
		{
			if ( trCN )
				ml.SetName(trCN.para.strName.strVal);
			return -1;
		}
	}
	/// end FIX_ORIGIN_RUNTIME_ERR_IMPORT_SOME_FAMOS_FILE
	int nCols = nSize / nRows;
	if ( nSize != nRows * nCols )
		return -1;

	// initialize the matrix format and size
	MatrixObject mi(ml, 0);
	setDataFormat(ml, trCP.para.nNumberFormat.nVal, nBytesSample);
	mi.SetSize(nCols, nRows, 0); // will transpose later
	
	// load data to matrix
	int nElementSize;				
	UINT nNumElements;				
	LPVOID lpDataMat = mi.GetInternalDataBuffer(&nElementSize, &nNumElements);
	LPVOID lpDataSource = vc;
	
	UINT nSizeToLoad = nElementSize * nNumElements;
	memcpy(lpDataMat, lpDataSource, nSizeToLoad);
	
	/// Hong 03/09/10 QA80-14858-P5 MATRIX_DATA_NO_NEED_TRANSPOSE_AFTER_READ_DATA_REQUIRED_ADDITIVE
	//// transpose matrix for view
	//matrixbase& mat = mi.GetDataObject();
	//mat.Transpose();
	/// end MATRIX_DATA_NO_NEED_TRANSPOSE_AFTER_READ_DATA_REQUIRED_ADDITIVE

	// set x-axis , z-axis value	
	double x0, dx;
	dx = trCD.para.dx.dVal;
	x0 = getX0FromBufDesc(trCD, nBuffRef);
	
	double z0, dz;
	z0 = trCZ.para.z0.dVal;
	dz = trCZ.para.dz.dVal;
	
	double xMin, xMax;
	xMin = x0;
	xMax = x0 + dx*(nRows - 1);
	
	double zMin, zMax;
	zMin = z0;
	/// Hong 03/09/10 QA80-14858-P5 FIX_WRONG_Y_AXES_SCALE
	//zMax = z0 + dx*(nCols - 1);
	zMax = z0 + dz*(nCols - 1);
	/// end FIX_WRONG_Y_AXES_SCALE
	
	mi.SetXY(xMin, zMin, xMax, zMax);
	
	//// set additional parameters
	if ( trCR )
	{
		if ( 1 == trCR.para.nTransformation.nVal )
			setColFactorAndOffset(ml, trCR.para.dFactor.dVal, trCR.para.dOffset.dVal);
		//col.SetUnits(trCR.para.strUnit.strVal);
	}
	
	if ( trCN )
	{
		ml.SetName(trCN.para.strName.strVal);
		//col.SetComments(trCN.para.strComment.strVal);
	}
	/// Sophy 5/04/2008 SHOW_WARNING_MESSAGE_WHEN_IMPORT_INVALID_DATA_FILE
	if( !bHasImportedData )
		bHasImportedData = true;
	/// End SHOW_WARNING_MESSAGE_WHEN_IMPORT_INVALID_DATA_FILE
	return 0;
}

int FamosFile::constructKeysInfo(TreeNode& trKeysArrange, const TreeNode& trKeysList)
{
	int nOrderCurKey, nOrderInsertKey;
	
	trKeysArrange.wID.nVal = 0; // means top of keys tree, temporary node
	TreeNode trCurKey = trKeysArrange;
	
	TreeNode trKey;
	trKey = trKeysList.FirstNode;
	while ( trKey.IsValid() )
	{
		nOrderInsertKey = getOrder(trKey);
		if ( nOrderInsertKey < 0 )
		{	// CS, Cb key, they can be placed anywhere on file, just put them to 1st level of tree
			insertKey(trKeysArrange, trKey);
		}
		else
		{
			
			nOrderCurKey = getOrder(trCurKey);
			// find a proper position to insert key to tree
			while(nOrderInsertKey <= nOrderCurKey)
			{
				trCurKey = trCurKey.Parent();
				nOrderCurKey = getOrder(trCurKey);
			}		
			// the inserted key is children of current key on tree
			trCurKey = insertKey(trCurKey, trKey);
		}
		
		trKey = trKey.NextNode;
	}
	
	trKeysArrange.RemoveChild("wID"); // delete temporary node
	
	return 0; // success
}

int FamosFile::getOrder(const TreeNode& trKey)
{
	if ( !trKey.wID )
	{
		return MAX_ORDER;
	}
	int nKeyID = trKey.wID.nVal;
	
	switch (nKeyID)
	{
		case 0: nKeyID = 0; break; // means top of keys tree
		case FAMOS_KEYID_CF: nKeyID = KEYID_CF; break;
		case FAMOS_KEYID_CK: nKeyID = KEYID_CK; break;  
		case FAMOS_KEYID_NO: nKeyID = KEYID_NO; break;
		case FAMOS_KEYID_CB: nKeyID = KEYID_CB; break;
		case FAMOS_KEYID_CT: nKeyID = KEYID_CT; break;
		case FAMOS_KEYID_CG: nKeyID = KEYID_CG; break;
		case FAMOS_KEYID_CD: nKeyID = KEYID_CD; break;
		case FAMOS_KEYID_NT: nKeyID = KEYID_NT; break;
		case FAMOS_KEYID_CZ: nKeyID = KEYID_CZ; break;
		case FAMOS_KEYID_CC: nKeyID = KEYID_CC; break;
		case FAMOS_KEYID_CP: nKeyID = KEYID_CP; break;
		case FAMOS_KEYID_Cb: nKeyID = KEYID_Cb; break;
		case FAMOS_KEYID_CR: nKeyID = KEYID_CR; break; 
		case FAMOS_KEYID_ND: nKeyID = KEYID_ND; break;
		case FAMOS_KEYID_CN: nKeyID = KEYID_CN; break;
		case FAMOS_KEYID_NU: nKeyID = KEYID_NU; break;
		case FAMOS_KEYID_CI: nKeyID = KEYID_CI; break;
	default:
		nKeyID = KEYID_UNKNOWN; break;
	}
	
	return KeyOrder[nKeyID];
}

#define KEY_CREATE_BRANCH(_tr, _trKey, _Name)/*, _KEYID) \*/ \
		_tr = _trKey.GetNode(_Name); \
		if ( !_tr ) \
		{ \
			_tr = _trKey.AddNode(_Name); \
			/* _tr.wID.nVal = _KEYID; */;\
		}

TreeNode FamosFile::insertKey(TreeNode& trCurKey, const TreeNode& trInsKey)
{
	TreeNode tr = trCurKey;

	string strName = trInsKey.tagName;
	if ( "CG" == strName || "CT" == strName || "CB" == strName || "CI" == strName
		|| "CC" == strName || "Cb" == strName || "CS" == strName || "NU" == strName)
	{
		KEY_CREATE_BRANCH(tr, trCurKey, strName+"0");//, trInsKey.wID.nVal);
	}
	
	tr.AddNode(trInsKey);
	return tr.LastNode;
}

///---Sim 09-25-2007 SHOW_MSG_FOR_UNSUPPORTED_VERSION
//int FamosFile::addNextKey(TreeNode& trParent, int* pnFromPos)
int FamosFile::addNextKey(TreeNode& trParent, TreeNode& trCurKey, int* pnFromPos)
///---END SHOW_MSG_FOR_UNSUPPORTED_VERSION
{
	int nRet = _KEYREAD_ERR_OK;
	
	int nParaPos;
	KeyHdr kyHdr;
	nRet = readKeyHdr(kyHdr, &nParaPos, *pnFromPos);
	if(nRet < 0) 
		return _KEYREAD_ERR_ENDFILE;
	
	char *ptmp = (char*) &kyHdr.wID;
	WORD WT;
    string strKeyName(ptmp, 2);//(char*)(&kyHdr.wID), 2);
	TreeNode trKey = trParent.AddNode(strKeyName);
	trKey = kyHdr;
	
	nRet = readKeyPara(trKey, nParaPos);
	if ( nRet < 0 ) 
		return _KEYREAD_ERR_ERR;
	
	*pnFromPos = nParaPos + trKey.nParaSize.nVal +1;
	//mabye need to cheke whether the end of the key is ';'
	trCurKey = trKey; ///---Sim 09-25-2007 SHOW_MSG_FOR_UNSUPPORTED_VERSION
	return _KEYREAD_ERR_OK;
}

int FamosFile::readKeyHdr(KeyHdr& kyHdr, int* pParaPos, int nFromPos)
{

	int nRet = seekToAfterChar('|', nFromPos);
	if(nRet < 0) 
		return nRet;
	
	READ_DATA(&kyHdr.wID, sizeof(WORD), -1);
	//Need to chekc ID here

	string strTemp;
	char cFinded; ///---Sim 09-25-2007 SHOW_MSG_FOR_UNSUPPORTED_VERSION

	seekToAfterChar(',');
	///---Sim 09-25-2007 SHOW_MSG_FOR_UNSUPPORTED_VERSION
	//readStringUntilFindAChar(strTemp, ",;");
	readStringUntilFindAChar(strTemp, ",;", &cFinded);
	///---END SHOW_MSG_FOR_UNSUPPORTED_VERSION
	kyHdr.nVer = atoi(strTemp);
	if(kyHdr.nVer<1 ||kyHdr.nVer > 2)
		return -1;
	
	///---Sim 09-25-2007 SHOW_MSG_FOR_UNSUPPORTED_VERSION
	if ( ';' == cFinded )
	{
		kyHdr.nParaSize = 0;
		*pParaPos = GetPosition() - 1;
		return 0
	}
	///---END SHOW_MSG_FOR_UNSUPPORTED_VERSION
	
	readStringUntilFindAChar(strTemp, ",;");
	kyHdr.nParaSize = atoi(strTemp);	
	if(kyHdr.nParaSize < 0) 
		return -1;
	
	*pParaPos = GetPosition();
	
	return 0;
}

int FamosFile::readKeyPara(TreeNode& trKey, int nParaPos)
{
	//int nParaSize = trKey.nParaSize.nVal;
	TreeNode trPara = trKey.AddNode("para");
	int nRet = 0;
	
	if(trKey.wID.nVal == FAMOS_KEYID_CS)
	{
		nRet = extractCSPara(nParaPos, trPara);   
		return 0;	
	}
	
	int nBufSize = trKey.nParaSize.nVal + 1;
	vector<char> vBuf(nBufSize);
	Seek(nParaPos, file::begin);
	if( Read(vBuf, nBufSize) < nBufSize) 
		return -1;
	// check ending character ';'
	//while ( ';' != vBuf[nBufSize-1] )
		//nBufSize--;
	if ( ';' != vBuf[nBufSize-1] )
		return -1;
	vBuf.SetSize(nBufSize - 1);
	//trKey.nParaSize.nVal = nBufSize - 1;
	
	switch(trKey.wID.nVal)
	{
		case FAMOS_KEYID_DF: ///---Sim 01-15-2007 SUPPORT_DEMO_FILE
		case FAMOS_KEYID_CF: 
			nRet = (extractCFPara(vBuf, trPara)) ? 0 : -1;
			break;
		case FAMOS_KEYID_CK:  
			nRet = (extractCKPara(vBuf, trPara)) ? 0 : -1;
			break;
		case FAMOS_KEYID_NO:  
			nRet = (extractNOPara(vBuf, trPara)) ? 0 : -1;
			break;
		case FAMOS_KEYID_CB:  
			nRet = (extractCBPara(vBuf, trPara)) ? 0 : -1;
			break;
		case FAMOS_KEYID_CT:  
			nRet = (extractCTPara(vBuf, trPara)) ? 0 : -1;   
			break;
		case FAMOS_KEYID_CG:  
			nRet = (extractCGPara(vBuf, trPara)) ? 0 : -1;
			break;
		case FAMOS_KEYID_CD:  
			nRet = (extractCDPara(vBuf, trPara)) ? 0 : -1;
			break;
		case FAMOS_KEYID_NT:  
			nRet = (extractNTPara(vBuf, trPara)) ? 0 : -1;
			break;
		case FAMOS_KEYID_CZ:  
			nRet = (extractCZPara(vBuf, trPara)) ? 0 : -1;
			break;
		case FAMOS_KEYID_CC:  
			nRet = (extractCCPara(vBuf, trPara)) ? 0 : -1;
			break;
		case FAMOS_KEYID_CP:  
			nRet = (extractCPPara(vBuf, trPara)) ? 0 : -1;
			break;
		case FAMOS_KEYID_Cb:  	 
			nRet = (extractCbPara(vBuf, trPara)) ? 0 : -1;   
			break;
		case FAMOS_KEYID_CR:  
			nRet = (extractCRPara(vBuf, trPara)) ? 0 : -1;
			break;
		case FAMOS_KEYID_ND:  
			nRet = (extractNDPara(vBuf, trPara)) ? 0 : -1;
			break;
		case FAMOS_KEYID_CN:  
			nRet = (extractCNPara(vBuf, trPara)) ? 0 : -1;
			break;
		case FAMOS_KEYID_NU: 
			nRet = (extractNUPara(vBuf, trPara)) ? 0 : -1;
			break;
		case FAMOS_KEYID_CI: 
			nRet = (extractCIPara(vBuf, trPara)) ? 0 : -1;   
			break;	
		/// Hong 07/08/10 ORG-499-P1 FIX_FAIL_IMPORT_SPECAIL_FAMOS_FILE_WITH_UNKOWN_KEY
		case FAMOS_KEYID_Cv:
		case FAMOS_KEYID_CV:
			nRet = 0;
			break;
		/// end FIX_FAIL_IMPORT_SPECAIL_FAMOS_FILE_WITH_UNKOWN_KEY
	default:
		nRet = -1;
	}
	
	return nRet;
}

int FamosFile::readStringUntilFindAChar(string& strDest, string strCharContainer, char *pchFound)
{
	strDest.Empty();
	char ch;
	READ_DATA(&ch, sizeof(char), -1);
	while ( -1 == strCharContainer.Find(ch)  )
	{
		strDest += ch;
		READ_DATA(&ch, sizeof(char), -1);
	}
	
	if(pchFound)
		*pchFound = ch;
	return 0;
}

int FamosFile::seekToAfterChar(char cEndChar, int iFromPos)
{
	if(!IsOpen())
		return -1;  //need more detail error
	
	if(iFromPos >= 0)
		Seek(iFromPos, file::begin);
	char ch;   
	do{
		READ_DATA(&ch, sizeof(char), -1);
	}while ( ch != cEndChar );
	
	return GetPosition(); 
}

bool FamosFile::extractCFPara(vector<char>& vBuf, TreeNode& trCFPara)
{
	CFPara ParaCF;
	int nStart = 0;
	ParaCF.nProcessor = readIntFromBuf(vBuf,  &nStart);//, ';');

	trCFPara = ParaCF;
	return true;
}
bool FamosFile::extractCKPara(vector<char>& vBuf, TreeNode& trCKPara)
{
	CKPara ParaCK;
	int nStart = 0;
	ParaCK.nCKResv = readIntFromBuf(vBuf,  &nStart);
	ParaCK.nFinished = readIntFromBuf(vBuf, &nStart);	
	
	trCKPara = ParaCK;
	return true;
}
bool FamosFile::extractNOPara(vector<char>& vBuf, TreeNode& trNOPara)
{
	NOPara ParaNO;
	int nStart = 0;
	ParaNO.nOrigin = readIntFromBuf(vBuf, &nStart);	
	ParaNO.strName = readStringFromBuf(vBuf, &nStart);
	ParaNO.strComment = readStringFromBuf(vBuf, &nStart);	
	
	trNOPara = ParaNO;
	return true;
}
bool FamosFile::extractCBPara(vector<char>& vBuf, TreeNode& trCBPara)
{
	CBPara ParaCB;
	int nStart = 0;
	ParaCB.nIndex = readIntFromBuf(vBuf, &nStart);
	ParaCB.strName = readStringFromBuf(vBuf, &nStart);
	ParaCB.strComment = readStringFromBuf(vBuf, &nStart);

	trCBPara = ParaCB;
	return true;
}
bool FamosFile::extractCTPara(vector<char>& vBuf, TreeNode& trCTPara)
{
	CTPara ParaCT;
	int nStart = 0;
	ParaCT.nGroup = readIntFromBuf(vBuf,  &nStart);	
	ParaCT.strName = readStringFromBuf(vBuf, &nStart);
	ParaCT.strValue = readStringFromBuf(vBuf, &nStart);
	ParaCT.strComment = readStringFromBuf(vBuf, &nStart);

	trCTPara = ParaCT;
	return true;
}
bool FamosFile::extractCGPara(vector<char>& vBuf, TreeNode& trCGPara)
{
	CGPara ParaCG;
	int nStart = 0;
	ParaCG.nNumComponents = readIntFromBuf(vBuf,  &nStart);	
	ParaCG.nFieldType = readIntFromBuf(vBuf,  &nStart);	
	ParaCG.nDimension = readIntFromBuf(vBuf,  &nStart);	
	
	trCGPara = ParaCG;
	return true;
}
bool FamosFile::extractCDPara(vector<char>& vBuf, TreeNode& trCDPara)
{
	CDPara ParaCD;
	int nStart = 0;
	ParaCD.dx = readDoubleFromBuf(vBuf,  &nStart);	
	ParaCD.nCalibrated = readIntFromBuf(vBuf,  &nStart);	
	ParaCD.strUnit = readStringFromBuf(vBuf,  &nStart);	
	ParaCD.nReduction = readIntFromBuf(vBuf,  &nStart);	
	ParaCD.nIsMultiEvents = readIntFromBuf(vBuf,  &nStart);	
	ParaCD.nSortBUffer = readIntFromBuf(vBuf,  &nStart);	
	ParaCD.x0 = readDoubleFromBuf(vBuf,  &nStart);	
	ParaCD.nPretriggerUse = readIntFromBuf(vBuf,  &nStart);	
	
	trCDPara = ParaCD;
	return true;
}
bool FamosFile::extractNTPara(vector<char>& vBuf, TreeNode& trNTPara)
{
	NTPara ParaNT;
	int nStart = 0;
	ParaNT.nDay = readIntFromBuf(vBuf,  &nStart);	
	ParaNT.nMonth = readIntFromBuf(vBuf,  &nStart);	
	ParaNT.nYear = readIntFromBuf(vBuf,  &nStart);	
	ParaNT.nHours = readIntFromBuf(vBuf,  &nStart);	
	ParaNT.nMinutes = readIntFromBuf(vBuf,  &nStart);	
	ParaNT.dSeconds = readDoubleFromBuf(vBuf,  &nStart);	
	
	trNTPara = ParaNT;
	return true;
}
bool FamosFile::extractCZPara(vector<char>& vBuf, TreeNode& trCZPara)
{
	CZPara ParaCZ;
	int nStart = 0;
	ParaCZ.dz = readDoubleFromBuf(vBuf,  &nStart);
	ParaCZ.ndzcali = readIntFromBuf(vBuf,  &nStart);	
	ParaCZ.z0 = readDoubleFromBuf(vBuf,  &nStart);
	ParaCZ.nz0cali = readIntFromBuf(vBuf,  &nStart);
	ParaCZ.strUnit = readStringFromBuf(vBuf,  &nStart);	
	ParaCZ.nSegmentLengh = readIntFromBuf(vBuf,  &nStart);

	trCZPara = ParaCZ;
	return true;
}
bool FamosFile::extractCCPara(vector<char>& vBuf, TreeNode& trCCPara)
{
	CCPara ParaCC;
	int nStart = 0;
	ParaCC.nComIndx = readIntFromBuf(vBuf,  &nStart);	
	ParaCC.nAnalogDigital = readIntFromBuf(vBuf,  &nStart);	
	
	trCCPara = ParaCC;
	return true;
}
bool FamosFile::extractCPPara(vector<char>& vBuf, TreeNode& trCPPara)
{
	CPPara ParaCP;
	int nStart = 0;
	ParaCP.nBuffRef = readIntFromBuf(vBuf,  &nStart);	
	ParaCP.nBytes = readIntFromBuf(vBuf,  &nStart);	
	ParaCP.nNumberFormat = readIntFromBuf(vBuf,  &nStart);	
	ParaCP.nSignBits = readIntFromBuf(vBuf,  &nStart);	
	ParaCP.sMask = readIntFromBuf(vBuf,  &nStart);	
	ParaCP.nOffset = readIntFromBuf(vBuf,  &nStart);	
	ParaCP.nDirectSequenceNumber = readIntFromBuf(vBuf,  &nStart);	
	ParaCP.nIntervalByte = readIntFromBuf(vBuf,  &nStart);	
	
	trCPPara = ParaCP;
	return true;
}

bool FamosFile::extractCbPara(vector<char>& vBuf, TreeNode& trCbPara)
{
	CbPara ParaCb;
	int nStart = 0;
	ParaCb.nNumberBufferInKey = readIntFromBuf(vBuf,  &nStart);	
	ParaCb.nByteInUserInfo = readIntFromBuf(vBuf,  &nStart);
	trCbPara = ParaCb;
	
	TreeNode trBufs = trCbPara.Parent().AddNode("bufs");
	for(int ii = 0; ii< ParaCb.nNumberBufferInKey; ii++)
	{
		CbBuff cbBuff;
		cbBuff.nBufferRefence = readIntFromBuf(vBuf,  &nStart);	
		cbBuff.nIndexSamplesKey = readIntFromBuf(vBuf,  &nStart);	
		cbBuff.nOffsetBufferInSamplesKey = readIntFromBuf(vBuf,  &nStart);	
		cbBuff.nBufLength = readIntFromBuf(vBuf,  &nStart);	
		cbBuff.nOffsetFirstSampleInBuffer = readIntFromBuf(vBuf,  &nStart);	
		cbBuff.nBufferFilledBytes = readIntFromBuf(vBuf,  &nStart);	
		cbBuff.nReserve = readIntFromBuf(vBuf,  &nStart);	
		cbBuff.x0 = readDoubleFromBuf(vBuf,  &nStart);	
		/// Hong 12/18/09 QA80-14858 FAMOS_NEED_TRIGGER_TIME
		//cbBuff.nAddTime = readIntFromBuf(vBuf,  &nStart);	
		cbBuff.dAddTime = readDoubleFromBuf(vBuf,  &nStart);	
		/// end FAMOS_NEED_TRIGGER_TIME
		nStart += ParaCb.nByteInUserInfo +1;  //skip user info
		
		TreeNode trBuf = trBufs.AddNode("buf");
		trBuf = cbBuff;
	}
	return true;
}
bool FamosFile::extractCRPara(vector<char>& vBuf, TreeNode& trCRPara)
{
	CRPara ParaCR;
	int nStart = 0;
	ParaCR.nTransformation = readIntFromBuf(vBuf,  &nStart);	
	ParaCR.dFactor = readDoubleFromBuf(vBuf,  &nStart);	
	ParaCR.dOffset = readDoubleFromBuf(vBuf,  &nStart);
	ParaCR.nCalibrated = readIntFromBuf(vBuf,  &nStart);
	ParaCR.strUnit = readStringFromBuf(vBuf,  &nStart);
	
	trCRPara = ParaCR;
	return true;
}
bool FamosFile::extractNDPara(vector<char>& vBuf, TreeNode& trNDPara)
{
	NDPara ParaND;
	int nStart = 0;
	ParaND.ColorR = readIntFromBuf(vBuf,  &nStart);	
	ParaND.ColorG = readIntFromBuf(vBuf,  &nStart);	
	ParaND.ColorB = readIntFromBuf(vBuf,  &nStart);	
	ParaND.yMin = readIntFromBuf(vBuf,  &nStart);	
	ParaND.yMax = readIntFromBuf(vBuf,  &nStart);	
	
	trNDPara = ParaND;
	return true;
}
bool FamosFile::extractCNPara(vector<char>& vBuf, TreeNode& trCNPara)
{
	CNPara ParaCN;
	int nStart = 0;
	ParaCN.nIndxGroup = readIntFromBuf(vBuf,  &nStart);	
	readIntFromBuf(vBuf,  &nStart); // hold parameter
	ParaCN.nIndxBit = readIntFromBuf(vBuf,  &nStart);
	ParaCN.strName = readStringFromBuf(vBuf,  &nStart);	
	ParaCN.strComment = readStringFromBuf(vBuf,  &nStart);	
	
	trCNPara = ParaCN;
	return true;
}
bool FamosFile::extractCSPara(int nParaPos, TreeNode& trCSPara)
{
	CSPara ParaCS;
	string strTemp;
	Seek(nParaPos, file::begin);
	readStringUntilFindAChar(strTemp, ",");
	ParaCS.nIndex = atoi(strTemp);
	ParaCS.nDataPos = GetPosition();
	
	trCSPara = ParaCS;
	return true;
}
bool FamosFile::extractNUPara(vector<char>& vBuf, TreeNode& trNUPara)
{
	NUPara ParaNU;
	int nStart = 0;
	ParaNU.nIdenLen = readIntFromBuf(vBuf,  &nStart);	
	ParaNU.strKeyword = readStringFromBuf(vBuf,  &nStart);	
	
	trNUPara = ParaNU;
	return true;
}
bool FamosFile::extractCIPara(vector<char>& vBuf, TreeNode& trCIPara)//CIPara& ParaCI)
{
	CIPara ParaCI;
	int nStart = 0;
	ParaCI.nBlockIndex = readIntFromBuf(vBuf,  &nStart);	
	ParaCI.nNumFormat = readIntFromBuf(vBuf,  &nStart);
	ParaCI.strName = readStringFromBuf(vBuf,  &nStart);
	
	// get data value
	Tree trValue;
	if ( !getValueFromBuf(trValue, vBuf, ParaCI.nNumFormat, &nStart) )
		return false;
	
	ParaCI.strComment = readIntFromBuf(vBuf,  &nStart);	
	ParaCI.strUnit = readIntFromBuf(vBuf,  &nStart);	
	
	// get time
	memcpy(&ParaCI.dTime, &vBuf[nStart], 8);
	ParaCI.dTime += 2444239; // the time in this file since 1980 year, but in origin it is not. The offset of 1980 year in Origin is 2444239.
	
	trCIPara = ParaCI;
	trCIPara.Value.Replace(trValue);
	trCIPara.dTime.ID = TRGP_DOUBLE;
	trCIPara.dTime.SetAttribute(STR_ATTRIB_NUMFMT, "D9");
	
	return true;
}

// get value by different data size
#define GET_VALUE_BY_DATA_TYPE(_DestVar, _VAR_TYPE) \
	_VAR_TYPE data; \
	nDataBytes = sizeof(_VAR_TYPE); \
	memcpy(&data, &vBuf[*pnStart], nDataBytes); \
	_DestVar = data; 
	
bool FamosFile::getValueFromBuf(TreeNode& trValue, vector<char>& vBuf, int nNumFormat, int* pnStart)
{
	int nDataBytes = 0;
	switch (nNumFormat)
	{
	case FAMOS_NUMTYPE_UBYTE:
		GET_VALUE_BY_DATA_TYPE(trValue.nVal, byte);
		break;		
	case FAMOS_NUMTYPE_BYTE:
		GET_VALUE_BY_DATA_TYPE(trValue.nVal, char);
		break;		
	case FAMOS_NUMTYPE_USHORT:
		GET_VALUE_BY_DATA_TYPE(trValue.nVal, ushort);
		break;		
	case FAMOS_NUMTYPE_SHORT:
		GET_VALUE_BY_DATA_TYPE(trValue.nVal, short);
		break;		
	case FAMOS_NUMTYPE_ULONG:
		GET_VALUE_BY_DATA_TYPE(trValue.nVal, uint);
		break;		
	case FAMOS_NUMTYPE_LONG:
		GET_VALUE_BY_DATA_TYPE(trValue.nVal, int);
		break;		
	case FAMOS_NUMTYPE_FLOAT:
		GET_VALUE_BY_DATA_TYPE(trValue.dVal, float);
		break;		
	case FAMOS_NUMTYPE_DOUBLE:
		GET_VALUE_BY_DATA_TYPE(trValue.dVal, double);
		break;
	case FAMOS_NUMTYPE_2BYTED:
		GET_VALUE_BY_DATA_TYPE(trValue.nVal, ushort); // need correct data type
		break;
	case FAMOS_NUMTYPE_ULONG48:
		nDataBytes = 6;
		break;
	default:
		return false;
	}
	
	*pnStart += nDataBytes;
	
	return true;
}

bool BufferManager::GetBuffer(vector<char>& vcBuf, const vector<int> &vPos)
{
	if ( IsSameVector(vPos, m_vPos) )
	{
		vcBuf = m_vcBuf;
		return true;
	}
	return false;
}
void BufferManager::SetBuffer(const vector<char>& vcBuf, const vector<int> &vPos)
{
	m_vPos = vPos;
	m_vcBuf = vcBuf;
}

bool BufferManager::IsSameVector(const vector<int> &v1, const vector<int> &v2)
{
	if ( v1.GetSize() != v2.GetSize() )
		return false;
	if ( 0 != memcmp(v1, v2, v1.GetSize()) )
		return false;
	return true;
}

// read value from string buffer
int readIntFromBuf(vector<char>& vBuf, int* pnStart, char chSeprator)
{
	chSeprator = ',';   //for bug
	for(int ii = *pnStart; ii< vBuf.GetSize() && vBuf[ii] != chSeprator; ii++)
	{}
	
	if(*pnStart >= vBuf.GetSize()) return 0;
	string strTemp(&vBuf[*pnStart] , ii - *pnStart);

	*pnStart = ii + 1;	
	return atoi(strTemp);
}
double readDoubleFromBuf(vector<char>& vBuf, int* pnStart, char chSeprator)
{
	chSeprator = ',';   //for bug
	for(int ii = *pnStart; ii< vBuf.GetSize() && vBuf[ii] != chSeprator; ii++)
	{}
	
	if(*pnStart >= vBuf.GetSize()) return 0.0;
	string strTemp(&vBuf[*pnStart] , ii - *pnStart);
	
	*pnStart = ii +1;	
	return atof(strTemp); 
}
string readStringFromBuf(vector<char>& vBuf, int* pnStart)
{
	int nLeng = readIntFromBuf(vBuf, pnStart);
	if(*pnStart >= vBuf.GetSize()) return NULL;
	string strTemp(&vBuf[*pnStart], nLeng);
	*pnStart += nLeng +1 ;
	return strTemp;
}

///////////////////////////////////////////////////////////////////////////////////////////
//// testing codes
//int testfamos(int nFileDlg = 0)
//{
	//int ddcError = 0;
	//string strFileName;
	//
	//if (nFileDlg)
	//strFileName = GetOpenBox("[*.dat] *.dat");
	//else
		//strFileName = "G:\\Sim\\Origin8 User Files\\famos\\greg\\Famos\\Samples\\Calib2.dat";
	//
	//Worksheet wks = Project.ActiveLayer();
	//
	//FamosFile famosFile;
	//famosFile.Open(strFileName, file::modeRead );
	//Tree trInfo;
	//if(famosFile.ReadInfo(trInfo) == -1)
	//{
		//printf("error or not support");
		//return 1;
	//}
	//Tree trFileInfo;
	//bool bSampleInterval;
	//if ( famosFile.Import(wks, trFileInfo, bSampleInterval) )
	//{
		//printf("failed to import");
		//return 1;
	//}
//
	//return 0;
//}