#include <origin.h>
#include <GetNBox.h>
#include <xfutils.h>

#include <..\Originlab\CDFManager.h> 
#include <..\originlab\file_utils.h>
#include <..\originlab\fu_utils.h>	

#define TREENODE_DATA_SELECTION "DataSelection" 
static bool s_bFileValid = true;
#define OK_SURE(_OK_ENABLE) _OK_ENABLE = s_bFileValid; //also can be _OK_ENABLE = s_bFileValid && s_bSetting

static void _construct_branch(TreeNode& trGUI, TreeNode& trVar, string& strTagName, bool bOpen)
{
	TreeNode trVarNode;
	trVarNode = trGUI.AddNode(strTagName, TRGP_BRANCH);
	///Sophy 9/8/2009 QA80-14271 DISPLAY_VARIABLE_INFO_IN_ORGANIZER	
	//trVarNode.SetAttribute(STR_LABEL_ATTRIB, strTagName);
	string strLabel;
	if ( !trVar.GetAttribute(STR_LABEL_ATTRIB, strLabel) ) //if label not exist, set as tagName
		strLabel = strTagName;
	
	trVarNode.SetAttribute(STR_LABEL_ATTRIB, strLabel);
	///end DISPLAY_VARIABLE_INFO_IN_ORGANIZER
	int nBranchStyle = GETNBRANCH_CHECK_CONTROL | GETNBRANCH_CHECK_CONTROL_ONE_EVENT; 
	if(bOpen)			//expand the hightest dimension
		nBranchStyle |= GETNBRANCH_OPEN;
	trVarNode.SetAttribute(STR_ATTRIB_BRANCH, nBranchStyle);		
	
	foreach(TreeNode trStr in trVar.Children)		//make label and tip
	{	
		string strTip, strLabel;
		strLabel = trStr.tagName;
		TreeNode trStrNode = trVarNode.AddNumericNode(1, strLabel, TRGP_CHECK);
		
		foreach(TreeNode trTip in trStr.Children)
		{
			string strTipName;
			strTipName = trTip.tagName;
			if(strTipName.CompareNoCase("Type") == 0)
			{
				strLabel += " (";
				strLabel += trTip.strVal;
				strLabel += ") ";
			}
			///Sophy 7/27/2009 QA80-13988-P1 HIDE_DESCRIPTION_WHEN_IT_IS_THE_SAME_AS_DATAASET_NAME
			//if ( (strTipName.CompareNoCase(STR_VAR_DESCRIPT) == 0) && (strTipName.CompareNoCase(trStr.tagName) != 0) )
			//{
				//strLabel += trTip.strVal;
			//}
			if ( strTipName.CompareNoCase(STR_VAR_DESCRIPT) == 0 )
			{
				///Sophy 9/9/2009 QA80-14271 DISPLAY_VARIABLE_INFO_IN_ORGANIZER
				//string strDescript = trTip.strVal;
				string strDescript = trTip.FirstNode ? trTip.FirstNode.strVal : trTip.strVal;
				///end DISPLAY_VARIABLE_INFO_IN_ORGANIZER
				if ( strDescript.CompareNoCase(trStr.tagName) != 0 )
					strLabel += strDescript;
			}
			///end HIDE_DESCRIPTION_WHEN_IT_IS_THE_SAME_AS_DATAASET_NAME
			
			strTipName += " = ";
			///Sophy 9/9/2009 QA80-14271 DISPLAY_VARIABLE_INFO_IN_ORGANIZER
			//strTipName += trTip.strVal;
			strTipName += trTip.FirstNode ? trTip.FirstNode.strVal : trTip.strVal;
			///end DISPLAY_VARIABLE_INFO_IN_ORGANIZER
			strTip += strTipName;
			strTip += ", ";
		}
		
		if(strLabel.GetLength() > 60)			//cut to 60 char if strTip is too long
		{
			strLabel = strLabel.Left(57);
			strLabel += "...";
		}
		
		trStrNode.SetAttribute(STR_LABEL_ATTRIB, strLabel);
		trStrNode.SetAttribute(STR_TIPS_ATTRIB, strTip);
		if( 0 == trVar.tagName.Compare("Var1D") )
		{
			string strVarName, strDimName;
			strVarName = trStr.tagName;
			strDimName = trStr.Dims.strVal;
			strDimName.Delete(0);
			strDimName.Delete(strDimName.GetLength() - 1);
			if( strVarName == strDimName )
				trStrNode.Show = 0;
		}
		
	}
}

static bool _construct_GUI_tree(TreeNode& trGUI, TreeNode& trInfo)
{
	string strTagName;
	bool bOpen = true; 			//branch to expand or not
	
	for(int nn=4; nn>0; nn--)	//suppose tagName to be Var%dD, %d = 1,2,3,4
	{
		TreeNode trVar;
		strTagName.Format("Var%dD", nn);
		trVar = trInfo.GetNode(strTagName, false);
		if(trVar.IsValid())
		{
			_construct_branch(trGUI, trVar, strTagName, bOpen);	
			bOpen = false;
		}
	}
	
	if(trGUI.IsEmpty())
		return false;
	trGUI.SetAttribute(STR_ATTRIB_BRANCH, GETNBRANCH_OPEN);
	return true;
}

static BOOL construct_tree_FileInfo(string strFileName, TreeNode& trInfo)
{
		if ( !strFileName.IsFile() )
			return false;
		string strInfo;
		strInfo.Format("File Size: %s ", GetFileSize(strFileName));
		trInfo.strVal = strInfo;
		trInfo.Enable = 0;
		return true;
}

static bool construct_tree_setting(StringArray& vsFileNames, TreeNode& trNode)
{
	Tree trFileVarInfo;
	TreeNode trFile; 
	string strFileName;
	string strTag; 
	
	trNode.RemoveChildrenWithPrefix();
	int nSize = vsFileNames.GetSize(); 
	for(int index = 0; index < nSize; index++)
	{
		strFileName = GetFileName(vsFileNames[index], true);
		strTag.Format("file%d", index+1);
		trFile = trNode.AddNode(strTag); 
		trFile.SetAttribute(STR_LABEL_ATTRIB, strFileName);
		TreeNode trFileInfo;
		trFileInfo = trFile.AddNode("FileInfo");
		trFileInfo.SetAttribute(STR_LABEL_ATTRIB, STR_FILE_INFO);	///Sophy 9/21/2009 SET_LABEL_ON_GUI_FOR_TRANSLATION
		if ( !construct_tree_FileInfo(vsFileNames[index], trFileInfo) )
			return false;
		

		CDF	cdf;
		if ( CDF_OK != cdf.Open(vsFileNames[index]) )
			return false;
		trFileVarInfo.Reset();
		cdf.GetVarsInfo(trFileVarInfo);
		cdf.Close();
		
		TreeNode trGUI = trFile.AddNode(TREENODE_DATA_SELECTION);
		trGUI.SetAttribute(STR_LABEL_ATTRIB, STR_DATA_SELECTION);	///Sophy 9/21/2009 SET_LABEL_ON_GUI_FOR_TRANSLATION
		if(!_construct_GUI_tree(trGUI, trFileVarInfo))
		{
			return false;
		}
	}
	trNode.SetAttribute(STR_ATTRIB_BRANCH, GETNBRANCH_OPEN);	
	return true;
}

static bool file_name_event(TreeNode& trGetN, string& strErrMsg)
{
	string strFileName = trGetN.fname.strVal;
	TreeNode trNode = trGetN.trfiles;
	
	// clean the trFiles on GUI
	trNode.RemoveChildrenWithPrefix();
	
	if ( !check_imported_file_name(strFileName, strErrMsg) )
		return false;
	
	StringArray vsFileNames;
	separate_multiline_files(strFileName, vsFileNames);
	if ( !construct_tree_setting(vsFileNames, trNode) )
	{
		// clean the trFiles on GUI
		trNode.RemoveChildrenWithPrefix();
		strErrMsg = CER_INVALID_IMPORT_DATA_FILE;
		return false;
	}
	
	return true;
}

class CDFFile : public BinFile
{
public:
	CDFFile(LPCSTR lpcszFileName, BOOL bImport = true) 
	:BinFile(bImport)
	{
		m_strFileName = lpcszFileName;
	}
	~CDFFile()
	{
		m_CDF.Close();
	}
public:
	int Import(MatrixPage& mp, TreeNode& trFileInfo, TreeNode& trSetting)
	{
		int nRet; 
		if ( nRet = ReadHeader(trFileInfo ) )
			return nRet;

		Tree trUsingSetting;
		if ( trSetting && trSetting.IsValid() )
			trUsingSetting = trSetting;
		return ReadData(mp, trUsingSetting, trFileInfo);

	}

private:
	CDF	m_CDF;
private:
	int ReadHeader(TreeNode& trFileInfo)
	{
		if ( CDF_OK != m_CDF.Open(m_strFileName) )
			return IMPERR_FAILED_OPEN; 
		
		m_CDF.GetVarsInfo(trFileInfo);
		return CER_NO_ERROR;
	}
	int ReadData(MatrixPage& mp, TreeNode& trGUI, TreeNode& trFileInfo)
	{
		vector<uint>	vnDim;
		int ii, nVarDims, nWrittenRecs = 0, nMaxRecNum = 0, nIndex = 0, nMat = 0;
		string strVar, str;
		int nLayers = mp.Layers.Count();
		MatrixLayer matLayer;
		int nType;
		byte mv[9];
		
		foreach(TreeNode trVar in trGUI.Children)
		{
			WorksheetPage wp;
			Worksheet wks;
			int nCol = 0;
			string strTemp = trVar.tagName;
			if( 0 == strTemp.Compare("Var1D") )
			{
				int nYNum = 0;
				foreach(TreeNode tn in trVar.Children)
				{
					if(1 == tn.nVal)
					{
						nCol++;
						if ( tn.Show != 0 )
							nYNum++;
					}
				}
				if ( nYNum > 0 )
				{
					if( nCol > 0 )
					{
						wp.Create("origin");
						wks = wp.Layers();
						wks.SetSize(-1, nCol);
						m_orng.Add(wks, 0, STR_RANGE_STR, nCol - 1); 
						wp.SetName(m_strFileName, OCD_KEEP_SN | OCD_LONG_NAME | OCD_ENUM_NEXT);
						wp.TitleShow = WIN_TITLE_SHOW_BOTH;
					}
				}
			}
			nCol = 0;
			foreach(TreeNode trStr in trVar.Children)
			{
				if(1 == trStr.nVal)
				{
					strVar = trStr.tagName;
					m_CDF.GetOneVarInfo(strVar, vnDim, &nType, &nWrittenRecs, &nMaxRecNum);
					nVarDims = vnDim.GetSize();
					if(nVarDims < 0)
					{
						string strMsg;
						strMsg.Format("%d: %s is not a valid variable\n", nIndex, strVar);
						warning_msg_box(strMsg, false);
						continue;
					}
					nIndex++;
					if(vnDim.GetSize() > 1 && vnDim[0] == 1) // if highest dim has only one value, then we should lower the dim size by one
						nVarDims--;
					
					// 1D should read into worksheet
					if( wks )
					{
						m_CDF.ImportOneCol(strVar, wks, nCol++);
						wks.SetName(strVar, OCD_ENUM_NEXT);
					}
					if( nVarDims >= 1 )
					{
						switch(nVarDims)
						{
						case 1:
							// add other special code for 1 D data here
							break;

						case 2:
						case 3:
						case 4:
							
							CDFstatus status;
							///Sophy 9/6/2010 ORG-1000 IMPORT_MULTI_DIMS_TEXT_DATA_INTO_WORKSHEET_COLUMN
							if ( FSI_CHAR == nType )
							{
								WorksheetPage wpText;
								wpText.Create("Origin");
								Worksheet wksText = wpText.Layers();
								wksText.SetSize(-1, nMaxRecNum + 1);
								for ( int iRecNum = 0; iRecNum <= nMaxRecNum; iRecNum++ )
								{
									status = m_CDF.ImportOneVarRecord(strVar, iRecNum, wksText);
								}
								wksText.SetName(strVar, OCD_ENUM_NEXT);
							}
							else
							{
							///end IMPORT_MULTI_DIMS_TEXT_DATA_INTO_WORKSHEET_COLUMN
								for ( int iRecNum = 0; iRecNum <= nMaxRecNum; iRecNum++ )
								{
									if ( nMat >= nLayers )
										mp.AddLayer("");
									matLayer = mp.Layers(nMat);
									///Sophy 7/22/2009 STOP_IMPORTING_WHEN_FAIL_TO_CREATE_MORE_LAYER_FOR_IMPORT_DATA
									if ( !matLayer )
									{
										return CER_INVALID_MATRIX;
									}
									///end STOP_IMPORTING_WHEN_FAIL_TO_CREATE_MORE_LAYER_FOR_IMPORT_DATA
									status = m_CDF.ImportOneVarRecord(strVar, iRecNum, matLayer);
									if ( status == CDF_OK )
									{
										nMat++;
										matLayer.SetViewImage();
										string	strLayerName;
										strLayerName.Format(STR_VAR_REC_LABEL_FMT, strVar, iRecNum);
										matLayer.SetName(strLayerName, OCD_ENUM_NEXT);
										m_orng.Add(matLayer, 0, STR_RANGE_STR);
									}
								}
							}
							
							break;

						default:
							string	strMsg = "Should never come here.";
							warning_msg_box(strMsg, false);
							continue;
						}
						if ( mv[0] && nVarDims >= 2 )
							matLayer.SetMissingValue(nType, &mv[1]);	
					}
					else if (nVarDims < 0) 
					{
						warning_msg_box("unknown variable dimension in cdf file.", false);
					}
				}
			}
		}
		m_CDF.UpdateFileInfo(mp);	///Sophy 9/9/2009 QA80-14271 DISPLAY_VARIABLE_INFO_IN_ORGANIZER
		mp.SetName(m_strFileName, OCD_KEEP_SN | OCD_LONG_NAME | OCD_ENUM_NEXT);
		mp.TitleShow = WIN_TITLE_SHOW_BOTH;
		return CER_NO_ERROR;
	}
};

void impCDF(const string& fname, const TreeNode& trfiles, Range& orng, TreeNode& trheader, const TreeNode& trFilter)
{
	
	int nRet = 0; 
	
	Tree trBaseInfo; 
	
	Tree tnUsingFilter;
	int nVer;
	if ( fuGetDouble(trFilter, IDE_DISP_IMP_ORIGINVER, nVer) )
		tnUsingFilter = trFilter;
	
	if ( tnUsingFilter.GetNodeCount() <= 0 )
	{
		fuPrepareDefault(tnUsingFilter, FILTER_TYPE_XFUNC);
		fuSetTargetPage(tnUsingFilter, EXIST_MATRIX);
		tree_set_attribute_to_all_nodes(tnUsingFilter, "Show", "0");		
		fuSet1stImportMode(tnUsingFilter, ASCIMP_MODE_NEW_BOOKS);
		fuSetImportMode(tnUsingFilter, ASCIMP_MODE_NEW_BOOKS);
	}
	
	fuSetXFunctionName(tnUsingFilter, "impCDF");
	// design refer to /// AW 02/28/07 8/0272c ADD_NEW_MATRIX_PAGE_WHEN_ACTIVE_WINDOW_IS_WKS
	if ( EXIST_WKS == fuGetTargetPage(tnUsingFilter) )
		fuSetTargetPage(tnUsingFilter, EXIST_MATRIX);
	
	int c1,c2; 
	Datasheet lyTarget;
	MatrixPage mpgTarget;
	if ( !GetRangeInfo(orng, lyTarget, mpgTarget, c1, c2) )
		XF_THROW(XFERR_INVALID_RANGE);
	MatrixLayer mlTarget(lyTarget);
	if(!mlTarget.IsValid())
	{
		MatrixPage MatPg;
		MatPg.Create("Origin");
		mlTarget = MatPg.Layers(0);
		
		if ( orng.IsValid() )
		{
			orng.Reset();
			orng.Add(mlTarget, 0);
		}
	}
	
	mlTarget.GetParent(mpgTarget);
	StringArray vsFileNames;
	separate_multiline_files(fname, vsFileNames); 
	
	if ( trfiles.IsEmpty() && !fname.IsEmpty() )
	{
		if ( !construct_tree_setting(vsFileNames, trfiles) )
		{
			XF_THROW(CER_INVALID_IMPORT_DATA_FILE);
			return ;
		}
	}
	
	if( trfiles.IsEmpty())//trSetting was constructed by file
		XF_THROW(CER_INVALID_IMPORT_DATA_FILE);
	
	string strFileName;
	int nFileCount = vsFileNames.GetSize();
	if ( nFileCount <= 0 )
		XF_THROW(CER_INVALID_FILENAME);
	int nIndexLayer = mpgTarget.Layers.Count() - 1;
	int nFileIndex = 0;
	foreach(TreeNode trFileNode in trfiles.Children )
	{
		strFileName = vsFileNames[nFileIndex];
		
		CDFFile cdfFile(strFileName);
	
		mlTarget = GetTargetLayer(mpgTarget, nIndexLayer, nFileIndex, tnUsingFilter, true, orng, ASCIMP_MODE_NEW_BOOKS);
		string strFile;
		strFile.Format("File%d", nFileIndex + 1); // file index to be 1
		TreeNode trInfo = trBaseInfo.AddNode(strFile);
		TreeNode trFileSetting = trFileNode.GetNode(TREENODE_DATA_SELECTION);
		if ( nRet = cdfFile.Import(mpgTarget, trInfo, trFileSetting) )
		{
			XF_THROW_EX(nRet, GetFileName(strFileName, false));
		}
		else
		{
			DataRange drImported;
			drImported = cdfFile.GetDataRange();
			Tree trDataRange;		
			getRangeInfo(trDataRange, drImported);
			impinfo_AddFile(mlTarget, strFileName, trInfo, ASCIMP_MODE_NEW_BOOKS, FILTER_TYPE_XFUNC, tnUsingFilter, nFileIndex + 1, trDataRange);
		}
	
		nFileIndex++;
	}
}

//nEventID < 0 on event, like GETNE_ON_INIT, GETNE_ON_OK etc, >0 on change from control
//return 0 to do nothing, return PEVENT_GETN_RET_TO_CLOSE to close dialog
//dwEnables = bOKEnable, bBTN1Enable, bBTN2Enable, bBTN3Enable, , can set to false to disable OK/Apply buttons
//lpcszNodeName = the trGetN TreeNode tag name that generates the event, or is  if GETNE_ON_OK etc
//strAux = optional string for XF Wizard Bar, like DLG_NEED_CHANGE_GRID etc, it will be invalid if from internal node value change event
//strErrMsg = allowing messages to be shown
int impCDF_event1(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	if( xf_is_extended_event(nEventID) )
		return impCDF_event1_ex(trGetN, nRow, nEventID, dwEnables, lpcszNodeName, DynaCntrlContainer, strAux, strErrMsg);
	DECLARE_BUTTON_ENABLES
	
	OK_SURE(bOKEnable); 
	if ( GETNE_ON_INIT == nEventID || GETNE_ON_THEME == nEventID )
	{
		s_bFileValid = file_name_event(trGetN, strErrMsg);
		OK_SURE(bOKEnable);
		
		return true;
	}
	
	if ( 0 == lstrcmp(lpcszNodeName, "fname") )
	{
		s_bFileValid = file_name_event(trGetN, strErrMsg);
		OK_SURE(bOKEnable);
		return true;
	}

}

int impCDF_make_tree(TreeNode& tr, LPCSTR lpcszVarName)
{
	return false;
}
//nGetNDialog = 0,1,2, corresponding to the XF GetN dropdown, 0 = dialog is not used
//you can change nRet to be one of XFEVT_PROCEED (defualt), XFEVT_ABORT, XFEVT_PROCEED_NO_DLG or XFEVT_PROCEED_WITH_DLG(when nGetNDialog = 0)
//nGetNDialog = -1 when Ok on GetN dialog to allow handler to preocess <auto> etc variables
//dwCntrl is combination of bits
//LTXF_FROM_GUI_MENU, LTXF_FROM_GUI_PROMPT, LTXF_FROM_AUTO_UPDATE, LTXF_FROM_FUNCTION, LTXF_THEME_USED, LTXF_CHANGE_PARAM
void impCDF_before_execute(TreeNode& trGetN, int nGetNDialog, int& nRet, int dwCntrl)
{
	
	if(nGetNDialog > 0)
	{
		trGetN.AutoUpdate.Show = 0;
		trGetN.trheader.Show = 0;
		trGetN.trFilter.Show = 0;
	}
	if(nGetNDialog > -1)
	{
		string strFileName = trGetN.fname.strVal;
		
		if ( LTXF_FROM_GUI_MENU & dwCntrl ) // if from menu, ignore default value fname$
			strFileName = "";
		
		if(is_empty_or_unassigned(strFileName))
		{			
			int nFilesRet;
			if ( 0 != nGetNDialog )
			{
				int nShowOptionsDlg = 1;
				nFilesRet = get_open_box_by_file_group(strFileName, "CDF", NULL,
					OPENBOX_FLAG_MULTIFILES, NULL, NULL, STR_SHOW_OPT_DLG, &nShowOptionsDlg);
				nRet = (nShowOptionsDlg ? XFEVT_PROCEED : XFEVT_PROCEED_NO_DLG);
			}
			else
			{
				nFilesRet = get_open_box_by_file_group(strFileName, "CDF", NULL, true);
			}
			if ( 0 == nFilesRet )
			{
				nRet = XFEVT_ABORT;
				return;
			}
			trGetN.fname.strVal = strFileName;
			string strErrMsg;
			if( !file_name_event(trGetN, strErrMsg) )
			{
				int nErrMsg = atoi(strErrMsg);
				nRet = XFEVT_ABORT;
				warning_msg_box(nErrMsg, false, 'E'); // should pass an int
				return;
			}
		}
	}
}
//nEventID < 0 on event, like GETNE_ON_INIT, GETNE_ON_OK etc, >0 on change from control
//return 0 to do nothing, return PEVENT_GETN_RET_TO_CLOSE to close dialog
//dwEnables = bOKEnable, bBTN1Enable, bBTN2Enable, bBTN3Enable, , can set to false to disable OK/Apply buttons
//lpcszNodeName = the trGetN TreeNode tag name that generates the event, or is  if GETNE_ON_OK etc
//strAux = optional string for XF Wizard Bar, like DLG_NEED_CHANGE_GRID etc, it will be invalid if from internal node value change event
//strErrMsg = allowing messages to be shown
int impCDF_event1_ex(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	return false;
}
