/*------------------------------------------------------------------------------*
 * File Name: SomatSIE.c	 													*
 * Creation: Fisher																*
 * Purpose: Import nCode Somat SIE format										*
 * Copyright (c) ABCD Corp.	2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010		*
 * All Rights Reserved															*
 * 																				*
 * Modification Log:															*
 * 																				*
 *	AW 01/17/08 AW_IMPORT_SIE													*
 *	Fisher 1/22/08 SET_USER_PARAMETERS_DIM										*
 *	Fisher 1/22/08 SUPPORT_SMART_SPARKLINE										*
 *	Fisher 1/23/08 SET_USER_PARAMETERS_CHANNEL									*
 *------------------------------------------------------------------------------*/
 
////////////////////////////////////////////////////////////////////////////////////
// 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 "SomatSIE.h"
#include "fu_utils.h"   		/// AW 01/17/08 AW_IMPORT_SIE
////////////////////////////////////////////////////////////////////////////////////
// Start your functions here.

string _get_file_name_sie(string strPath)
{
	int nPos;
	nPos = strPath.ReverseFind('\\');
	
	if(nPos < 0) return "";

	return strPath.Mid(nPos+1, strlen(strPath)-nPos-1);
	
}
///--- AW 01/17/08 AW_IMPORT_SIE
// need provide current worksheert as standard import XF provide it
//int SIEFile::Import(TreeNode &trSelection=NULL)
int SIEFile::Import(TreeNode& trOption, TreeNode &trSelection, Worksheet& wks)
///--- END AW_IMPORT_SIE
{
	int nTestCount = 0, nSpiCount, nChannelCount, nSheetCount, nDimCount; 
	
	string str;
	TreeNode trCH, trTS;
	sie_Tag *ptag;
	sie_Test *ptest;
	/// AW 01/17/08 AW_IMPORT_SIE
	BOOL bSkip;
	Tree trInfo;
	/// END AW_IMPORT_SIE
	
	int nSparklines = 0;
	TreeNode trTemp = trOption.GetNode("Sparklines");
	ASSERT(trTemp);
	if(trTemp)
		nSparklines = trTemp.nVal;
	else
		ASSERT(false);
		
	if(!m_pfileSIE)
	{
        m_pexception = sie_get_exception(m_pcontext);
        printf("Something bad happened:\n  %s\n", sie_verbose_report(m_pexception));
		printf("Fail to load file : %s\n", m_strFileName);
		return IMPERR_FILE_OPEN;
	}
	
	// Support patrial import
	if(trSelection){
		str.Format("TS%d", nTestCount);
		trTS = trSelection.GetNode(str);
	}
	///--- AW 01/17/08 AW_IMPORT_SIE
	// get valid worksheet and page and set page name
	Page pg;
	if ( !wks )
	{
		pg = Project.Pages();
		wks = Project.ActiveLayer();	
	}
	else
	pg = wks.GetPage();
	nSheetCount = 0;
	///--- END AW_IMPORT_SIE


	// Iterator through all Test
	sie_Iterator *ptest_iterator = sie_get_tests(m_pfileSIE);
	while ((ptest = sie_iterator_next(ptest_iterator))) 
	{
		
		sie_Channel *pchannel;

		///--- AW 01/17/08 AW_IMPORT_SIE	
		/*
		// Support patrial import
		if (nTestCount++ > 0 && trSelection) trTS = trTS.NextNode;

		// Create new workbook if needed
		sie_uint32 id = sie_get_id(ptest);
		
		
		if(!trSelection){
			WorksheetPage wp;
			wp.Create("Origin");
		}else{
			int f = 0;
			foreach(trCH in trTS.Children){
				if(trCH.nVal == 1){f = 1;break;}
			}
			if(f){WorksheetPage wp; wp.Create("Origin");}
		}
		Page pg = Project.Pages();
		Worksheet wks = Project.ActiveLayer();
		
		nChannelCount = nSheetCount = 0;
		
		// Support patrial import
		str.Format("CH%d", nChannelCount);
		if(trSelection) trCH = trTS.GetNode(str);
		*/
		if(trSelection)
		{
			if ( trTS )
			{
				trCH = trTS.FirstNode;
			}
		}
		if(++nSheetCount > 1)
		{
			int nSheet = pg.AddLayer();
			wks = pg.Layers(nSheet);
		}

		string strName;
		trTS.GetAttribute(STR_LABEL_ATTRIB, strName);
		string strTmp;
		strTmp.Format("%s_%s", strName, _get_file_name_sie(m_strFileName));
		wks.SetName(strTmp);
		
		TreeNode trTestInfo = trInfo.AddTextNode(strName, trTS.tagName);
		trTestInfo.SetAttribute(STR_LABEL_ATTRIB, strName);
		ReadTags(ptest, trTestInfo);
		if ( trTS )
			trTS = trTS.NextNode;
		
		int nCol = 0;
		///--- END AW_IMPORT_SIE

		//Iterator through all Channel
		sie_Iterator *pchannel_iterator = sie_get_channels(ptest);
		while ((pchannel = sie_iterator_next(pchannel_iterator))) 
		{
			sie_Dimension *pdimension;
			sie_Output *poutput;
			
			//--- AW 01/17/08 AW_IMPORT_SIE
			/*
			// Support patrial import
			if (trSelection){
				if(nChannelCount > 1) trCH = trCH.NextNode;
				if(!trCH.nVal){++nChannelCount; continue;}
			}
			
			// Add worksheet if needed
			if(++nSheetCount > 1){
				int nSheet = pg.AddLayer();
				wks = pg.Layers(nSheet);
			}
			*/
			if ( trCH )
			{
				BOOL bSkip = (trCH.nVal == 0)? TRUE:FALSE;
				if( bSkip ){
					trCH = trCH.NextNode;
					continue;
				}
			}
			trCH.GetAttribute(STR_LABEL_ATTRIB, strName); 
			
			TreeNode trChannelInfo = trTestInfo.AddTextNode(strName, trCH.tagName);
			trChannelInfo.SetAttribute(STR_LABEL_ATTRIB, strName);
			ReadTags(pchannel, trChannelInfo);
			trCH = trCH.NextNode;
			
			int nRow = 0;
			TreeNode trSampleNum = trChannelInfo.GetNode("output_samples");
			if ( trSampleNum )
				nRow = trSampleNum.nVal;	

			//--- END AW_IMPORT_SIE
			
			///--- AW 01/17/08 AW_IMPORT_SIE

			double *pVec = NULL;
			int nRealRowCount, nType, spi_rows, dim;
			
			sie_Iterator *pdimension_iterator = sie_get_dimensions(pchannel);
			dim = 0;
			while ((pdimension = sie_iterator_next(pdimension_iterator)))
			{
				strName.Format("dim_%d", dim); 
				TreeNode trDimInfo = trChannelInfo.AddNode(strName);
				ReadTags(pdimension, trDimInfo);

				Column cc(wks, nCol);
				if ( !cc )
				{
					nCol = wks.AddCol();
					cc = wks.Columns(nCol);
				}
				
				++nCol;
				vector vdVals;
				vdVals.SetSize(nRow);
				nRealRowCount = 0;
				
				sie_Spigot *pspigot = sie_attach_spigot(pchannel);
				while ((poutput = sie_spigot_get(pspigot)))
				{
					spi_rows = sie_output_get_num_rows(poutput);
					nRealRowCount += spi_rows;
					sie_Output_Struct *pos = sie_output_get_struct(poutput);
					nType = pos->dim[dim].type;
					switch(nType)
					{
						case SIE_OUTPUT_FLOAT64:
							// For numerical data
							if (nRealRowCount > nRow ) 
								vdVals.SetSize(nRealRowCount);
							pVec = (double *)vdVals;
							pVec += nRealRowCount - spi_rows;
							memcpy(pVec, pos->dim[dim].float64, sizeof(double)*spi_rows);
							break;
						case SIE_OUTPUT_RAW:
							char cc[2];
							string strTmp;
							for(int row = nRealRowCount - spi_rows ; row < nRealRowCount; ++row){
								unsigned char *uchar_p = pos->dim[dim].raw[row].ptr;
								int nSize = pos->dim[dim].raw[row].size;
								if(nSize <= 252)	// MAX_WKS_CELL_LENGTH - 
								{
									strTmp = "";
									for (int bb = 0; bb < nSize; bb++){
										sprintf(cc, "%02x", uchar_p[bb]);
										strTmp += cc;
									}
								}
								else
									strTmp = "Raw data too long, Not supported";
								wks.SetCell(row, dim, strTmp);
							}
							//ASSERT(FALSE);
							break;
					}
					sie_release(pos);
				}
				sie_release(poutput);
				sie_release(pspigot);
				
				if(nType == SIE_OUTPUT_FLOAT64){
					vectorbase& vs = cc.GetDataObject();
					vs = vdVals;
				}

				// Set labels(long name)
				TreeNode trTemp = trDimInfo.GetNode("label");
				if ( trTemp ){
					strName = trTemp.strVal;
					if ( strName == "Time" )
						cc.SetType(OKDATAOBJ_DESIGNATION_X );
					cc.SetLongName(strName);
				}

				// Set units
				trTemp = trDimInfo.GetNode("units");
				if ( trTemp )
					cc.SetUnits(trTemp.strVal);

				// Set channel name
				StringArray vsNames, vsValues;
				vsNames.Add("Channel Name");
				strName = sie_get_name(pchannel);
				vsValues.Add(strName);

				// Fisher 1/23/08 SET_USER_PARAMETERS_CHANNEL
				trTemp = trOption.GetNode("UserParamChan");
				if(trTemp.nVal == true)
				{
					Tree trChannelTag;
					ReadTags(pchannel, trChannelTag);
					foreach(trTemp in trChannelTag.Children){
						vsNames.Add(trTemp.tagName);
						vsValues.Add(trTemp.strVal);
					}
				}

				// Fisher 1/22/08 SET_USER_PARAMETERS_DIM		
				trTemp = trOption.GetNode("UserParam");
				if(trTemp.nVal == true)
				{
					foreach(trTemp in trDimInfo.Children){
						if(trTemp.tagName != "units" && trTemp.tagName != "label"){
							vsNames.Add(trTemp.tagName);
							vsValues.Add(trTemp.strVal);
						}
					}
				}
				set_user_parameters(cc, vsNames, vsValues);

				dim++;
				
			}
			sie_release(pdimension_iterator);
		}

		// Fisher 1/22/08 SUPPORT_SMART_SPARKLINE
		update_sparkline(nSparklines, wks, 0, nCol);

		sie_release(pchannel);
		sie_release(pchannel_iterator);
	}
	sie_release(ptest);
    sie_release(ptest_iterator);
    
    ///--- AW 01/17/08 AW_IMPORT_SIE
    impinfo_AddFile(wks, m_strFileName, trInfo, ASCIMP_MODE_NEW_SHEETS, FILTER_TYPE_XFUNC); 
	return 0;
}


// Read the tags for sie object and store in tree
int SIEFile::ReadTags(void *pobject, TreeNode &trInfo)
{
	sie_Tag *ptag;
	int value_size;
	char *value = NULL;

	if(!pobject)
		return IMPERR_UNKNOW_TYPE;

	string strShortName;
	TreeNode trNode;
	// Iterator through all tags
	sie_Iterator *tag_iterator = sie_get_tags(pobject);
	while ((ptag = sie_iterator_next(tag_iterator)))
	{   
		string strName = sie_tag_get_id(ptag);
		// Add tags
		sie_tag_get_value_b(ptag, &value, &value_size);
		
		///--- AW 01/17/08 AW_IMPORT_SIE
		/*
		if( value_size <= SIE_MAX_VALUE_SIZE)
			trInfo.AddTextNode(value, name);
		else
			trInfo.AddTextNode("", name);
		*/
		strShortName = strName;
		int nPos = strShortName.Find(':');
		if ( nPos >= 0 )
			strShortName = strShortName.Right(strShortName.GetLength()- nPos -1);	
		if( value_size <= SIE_MAX_VALUE_SIZE)
			trNode = trInfo.AddTextNode(value, strShortName);
		else
			trNode = trInfo.AddTextNode(SIE_LONG_VALUE, strShortName);
		trNode.SetAttribute(STR_LABEL_ATTRIB, strName);

		sie_system_free(value);
		value = NULL;
		value_size = 0;
		///--- END AW_IMPORT_SIE
	}
	sie_release(tag_iterator);
	
	return 0;
}


//Read the structure for sie file
int SIEFile::ReadHeader(Tree& trInfo)
{
	int nTestCount, nChannelCount;
	TreeNode trTS, trCH, trTAG;
	sie_Test *ptest;
	string str;
	
	if(!m_pfileSIE)
	{
		printf("Fail to load file : %s\n", m_strFileName);
		return IMPERR_FILE_OPEN;
	}

	// Read the tags for file
	trInfo.AddNode("TAG");
	trTAG = trInfo.GetNode("TAG");
	ReadTags(m_pfileSIE, trTAG);

	// Iterator through all Test
	nTestCount = 0;
	trInfo.AddNode("TS");
	trTS = trInfo.GetNode("TS");
	sie_Iterator *ptest_iterator = sie_get_tests(m_pfileSIE);
	while ((ptest = sie_iterator_next(ptest_iterator)))
	{
		sie_Channel *pchannel;

		// Add a TreeNode for test
		str.Format("TS%d", nTestCount++);
		trTS.AddTextNode("", str);
		trCH = trTS.GetNode(str);

		// Read the tags for test
		trCH.AddNode("TAG");
		trTAG = trCH.GetNode("TAG");
		ReadTags(ptest, trTAG);

		//Iterator through all Channel
		nChannelCount = 0;
		trCH.AddNode("CH");
		trCH = trCH.GetNode("CH");
		sie_Iterator *pchannel_iterator = sie_get_channels(ptest);
		while ((pchannel = sie_iterator_next(pchannel_iterator))) 
		{
			// Add a TreeNode for channel
			str.Format("CH%d", nChannelCount++);
			string strName = sie_get_name(pchannel);
			trCH.AddTextNode(strName, str);
		}
		sie_release(pchannel);
		sie_release(pchannel_iterator);
	}
	sie_release(ptest);
    sie_release(ptest_iterator);
	
	return 0;
}


