/*------------------------------------------------------------------------------*
 * File Name:				 													*
 * Creation: 																	*
 * Purpose: OriginC Source C file												*
 * Copyright (c) ABCD Corp.	2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007		*
 * All Rights Reserved															*
 * 																				*
 * Modification Log:															*
 *	Hong 02/16/09 QA80-13120 ROLL_BACK_OLD_CODE_TO_SPEEDUP_SET_PAGE_VAIRABLE_INFO
 *------------------------------------------------------------------------------*/
 
////////////////////////////////////////////////////////////////////////////////////
// you can include just this typical header file for most Origin built-in functions and classes
// and it takes a reasonable amount of time to compile, 
#include <origin.h>
// this file include most of the other header files except the NAG header, which takes longer to compile
// NAG routines
//#include <OC_nag.h> // this contains all the NAG headers, 

////////////////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////////////////
// start your functions here
#include "PrincetonInstruments.h"

//--------------------------------------------------------------------------
// tree2str
//
//--------------------------------------------------------------------------
static bool tree2str(TreeNode& tr, string& str, int nLevel = 0)
{
	if(NULL==tr)
		return false;
	
	for(int ii = 0; ii < nLevel; ii++)
		str +="  ";
	
	if(tr.GetNodeCount() > 0) // branch node
	{
		str +=tr.tagName + "\n";
		foreach(TreeNode cNode in tr.Children)
			tree2str(cNode, str, nLevel+1);
	}
	else // leaf node
	{
		string strTemp;
		strTemp.Format("%s = %s\n", tr.tagName, tr.Text);
		str += strTemp;
	}

	return true;
}

//--------------------------------------------------------------------------
// spe_HeaderToNotes
//
//--------------------------------------------------------------------------
/// SY 05/16/2005 QA70-6147 IMPORT_PRINCETON_INSTRUMENTS_ROPER_SCI
///	int spe_HeaderToNotes(SPEHEADER& spehdr, LPCSTR lpcszFile)
int spe_HeaderToNotes(Page& pg, SPEHEADER& spehdr, LPCSTR lpcszFile)
/// end IMPORT_PRINCETON_INSTRUMENTS_ROPER_SCI
{
	Tree tr;
	tr = spehdr;
		
	/// SY 05/16/2005 QA70-6147 IMPORT_PRINCETON_INSTRUMENTS_ROPER_SCI
	/// Hong 02/16/09 QA80-13120 ROLL_BACK_OLD_CODE_TO_SPEEDUP_SET_PAGE_VAIRABLE_INFO
	/// Hong 06/26/08 v.80891e CENTRALIZE_CODE
	pg.Info.Add("User");
	pg.Info.User.AddSection("Variables");
	
	using var = pg.Info.User.Variables;    
	foreach( TreeNode tn in tr.Children )
	{
		if( is_numeric(tn.Text) )
			var.AddDouble(tn.tagName, tn.dVal);
		else
			var.AddString(tn.tagName, tn.Text);
	}
	/*
	foreach ( TreeNode tn in tr.Children )
	{
		page_set_info_var_value(pg, tn.tagName, tn.strVal);
	}
	/// end CENTRALIZE_CODE
	*/
	/// end ROLL_BACK_OLD_CODE_TO_SPEEDUP_SET_PAGE_VAIRABLE_INFO
	/// end IMPORT_PRINCETON_INSTRUMENTS_ROPER_SCI
	
	string str;
	if( false == tree2str(tr, str) )
		return SPE_ERR_TREE2STR;
	
	// Create Note Window
	Note noteWnd;
	if( !noteWnd.Create() )
		return SPE_ERR_CREATE_NOTE_PAGE;
	
	string strFilename = GetFileName(lpcszFile);
	noteWnd.Rename(strFilename);
	
	string strLabel;
	strLabel.Format("File Information for %s", strFilename);
	noteWnd.Label = strLabel;
	noteWnd.TitleShow = WIN_TITLE_SHOW_LABEL;

	strLabel.Format("File Information for %s\n\n", lpcszFile);
	noteWnd.Text = strLabel + str;

	return 0;
}

//--------------------------------------------------------------------------
// spe_SetPageNameAndLabel
//
//--------------------------------------------------------------------------
static void spe_SetPageNameAndLabel(Page& pg, SPEHEADER& spehdr, LPCSTR lpcszFile)
{
	if( pg && pg.IsValid() )
	{
		// Target worksheet page name and label
		string strFilename = GetFileName(lpcszFile);
		pg.Rename(strFilename);
		
		string strLabel;
		strLabel.Format("%s (%d X %d X %d)", strFilename, spehdr.xdim, spehdr.ydim, spehdr.NumFrames ? spehdr.NumFrames : 1);
		pg.Label = strLabel;
		pg.TitleShow = WIN_TITLE_SHOW_LABEL;
	}
}

//--------------------------------------------------------------------------
// spe_GetBytesPerFrame
//
//--------------------------------------------------------------------------
static int spe_GetBytesPerFrame(int& nBytesPerFrame, SPEHEADER& spehdr)
{
	if( spehdr.datatype < 0 || spehdr.datatype > 3 )
		return SPE_ERR_DATA_TYPE;

	int nDataTypeSize[] = {4, 4, 4, 2};
	int nBytesPerElement = nDataTypeSize[spehdr.datatype];
	int nElementsPerFrame = spehdr.xdim * spehdr.ydim;
	
	nBytesPerFrame = nElementsPerFrame * nBytesPerElement;
	return SPE_ERR_NONE;
}

//--------------------------------------------------------------------------
// spe_SeekToFrameData
//
//--------------------------------------------------------------------------
static int spe_SeekToFrameData(file& filSrc, SPEHEADER& spehdr, int nFrame)
{
	if( nFrame == 0 || nFrame == 1 )
		return SPE_ERR_NONE;

	if( nFrame < 0 || nFrame > spehdr.NumFrames )
		return SPE_ERR_FRAME_NUMBER;
	
	nFrame--; // our frame number is zero based
	
	// Get number of bytes per frame
	int nBytesPerFrame;
	int iRet = spe_GetBytesPerFrame(nBytesPerFrame, spehdr);
	if( SPE_ERR_NONE != iRet )
		return iRet;

	try
	{
		filSrc.Seek(sizeof(SPEHEADER) + (nBytesPerFrame * nFrame), file::begin);
		iRet = SPE_ERR_NONE;
	}
	catch(int nErr)
	{
		iRet = SPE_ERR_SEEK_DATA;
	}
	
	return iRet;
}

//--------------------------------------------------------------------------
// spe_DataToMatrix
//
//--------------------------------------------------------------------------
static int spe_DataToMatrix(Matrix& mat, file& filSrc, SPEHEADER& spehdr)
{
	int nBytesPerFrame;
	int iRet;
	if( iRet = spe_GetBytesPerFrame(nBytesPerFrame, spehdr) )
		return iRet;
	
	int nRows, nCols;
	int nBytesToRead;
	if( 1 == spehdr.ydim )
	{
		// For a 1 dimensional file we read in all frames
		nRows = spehdr.NumFrames;
		nCols = spehdr.xdim;
		nBytesToRead = nBytesPerFrame * spehdr.NumFrames;
	}
	else // more than 1 dimension
	{
		nRows = spehdr.ydim;
		nCols = spehdr.xdim;
		nBytesToRead = nBytesPerFrame;
	}
	
	int nBytesRead = 0;
	switch( spehdr.datatype )
	{
	case SPE_DATATYPE_FLOAT:
		{
			matrix<float> mm(nRows, nCols);
			float *lp = mm;
			nBytesRead = filSrc.Read(lp, nBytesToRead);
			mat = mm;
		}
		break;
	case SPE_DATATYPE_LONG:
		{
			matrix<long> mm(nRows, nCols);
			long *lp = mm;
			nBytesRead = filSrc.Read(lp, nBytesToRead);
			mat = mm;
		}
		break;
	case SPE_DATATYPE_INT:
		{
			matrix<int> mm(nRows, nCols);
			int *lp = mm;
			nBytesRead = filSrc.Read(lp, nBytesToRead);
			mat = mm;
		}
		break;
	case SPE_DATATYPE_UINT:
		{
			matrix<ushort> mm(nRows, nCols);
			ushort *lp = mm;
			nBytesRead = filSrc.Read(lp, nBytesToRead);
			mat = mm;
		}
		break;
	default:
		return SPE_ERR_DATA_TYPE;
	}

	if( nBytesRead != nBytesToRead )
		return SPE_ERR_READ_DATA;
	return SPE_ERR_NONE;
}

//--------------------------------------------------------------------------
// Import1DimToPage
//
// Import 1 dimensional data to the specified page.
// If the page is not a worksheet then a new worksheet is created.
// A temporary matrix is always created.  Data is imported into the temporary
// matrix, transposed, and then copied into the target worksheet.
//--------------------------------------------------------------------------
static int Import1DimToPage(Page& pgTarget, file& filSrc, SPEHEADER& spehdr)
{
	// Create a temporary matrix page
	MatrixPage mp;
	mp.Create("origin.otm", CREATE_HIDDEN);
	if( !mp )
		return SPE_ERR_CREATE_TEMP_MATRIX_PAGE;

	// Get temporary matrix
	Matrix matTmp(mp.GetName());
	if( !matTmp )
		return SPE_ERR_CREATE_TEMP_MATRIX;
	
	// Import data into temporary matrix
	int i = spe_DataToMatrix(matTmp, filSrc, spehdr);
	if( SPE_ERR_NONE != i )
		return i;
	
	// Transpose temporary matrix
	matTmp.Transpose();

	// Get target worksheet page
	WorksheetPage wpTarget;
	if( pgTarget && EXIST_WKS == pgTarget.GetType() )
	{
		wpTarget = pgTarget;
	}
	else
	{
		// Create a new worksheet page
		wpTarget.Create("Origin.otw");
		if( !wpTarget.IsValid() )
			return SPE_ERR_CREATE_WKS_PAGE;
		
		pgTarget = wpTarget;
	}
	
	// Get target worksheet
	Worksheet wks(wpTarget.GetName());
	if( !wks.IsValid() )
		return SPE_ERR_CREATE_WKS;

	// Setup worksheet
	wks.SetSize(spehdr.xdim, spehdr.NumFrames, TRUE);
	wks.SetColDesignations("Y");
	
	// Copy temporary matrix into target worksheet
	matTmp.CopyTo(wks, 0, 0, spehdr.xdim - 1, spehdr.NumFrames - 1);

	// Destroy temporary matrix page
	mp.Destroy();
	
	return SPE_ERR_NONE;
}

//--------------------------------------------------------------------------
// Import2DimToPage
//
// Import 2 dimensional data to the specified page
// If the specified page is not a matrix page then a new matrix page is
// created.
//--------------------------------------------------------------------------
static int Import2DimToPage(Page& pgTarget, file& filSrc, SPEHEADER& spehdr, int nFrame = 0)
{
	// Get target matrix page
	MatrixPage mpTarget;
	if( pgTarget && EXIST_MATRIX == pgTarget.GetType() )
		mpTarget = pgTarget;
	else
	{
		// Create a new matrix page
		if( spehdr.NumFrames > 1 )
		{
			mpTarget.Create("PrincetonInstruments.otm");
			string str;
			for( int i = 1; i <= spehdr.NumFrames; i++ )
			{
				str.Format("%s!Frame.V%d=%d", mpTarget.GetName(), i, i);
				LT_execute(str);
			}
			str.Format("%s!Frame.Choice=%d", mpTarget.GetName(), nFrame + 1);
			LT_execute(str);
		}
		else
		{
			mpTarget.Create("origin.otm");
		}
		if( !mpTarget.IsValid() )
			return SPE_ERR_CREATE_MATRIX_PAGE;
		
		pgTarget = mpTarget;
	}
	
	// Get target matrix
	Matrix matTarget(mpTarget.GetName());
	if( !matTarget )
		return SPE_ERR_CREATE_MATRIX;

	// Import the specified frame
	int i = spe_SeekToFrameData(filSrc, spehdr, nFrame);
	if( SPE_ERR_NONE != i )
		return i;
	
	// Import data into target matrix
	i = spe_DataToMatrix(matTarget, filSrc, spehdr);
	if( SPE_ERR_NONE != i )
		return i;

	// Set target matrix view mode to Image
	MatrixLayer ml(mpTarget.GetName());
	if( ml )
		ml.SetViewImage();
	
	return SPE_ERR_NONE;
}

//--------------------------------------------------------------------------
// ImportFileToPage
//
// Imports an SPE file into the specified page.
//--------------------------------------------------------------------------
static int ImportFileToPage(Page& pgTarget, LPCSTR lpcszFile, int nFile)
{
	// Open data file
	file filSrc;
	if( !filSrc.Open(lpcszFile, file::modeRead | file::typeBinary | file::shareDenyWrite) )
		return SPE_ERR_FILE_OPEN;

	// Read header
	SPEHEADER spehdr;
	int iRet = filSrc.Read(&spehdr, sizeof(SPEHEADER));
	if( sizeof(SPEHEADER) == iRet )
	{
		// Read data into page
		if( 1 == spehdr.ydim )
			iRet = Import1DimToPage(pgTarget, filSrc, spehdr);
		else
			iRet = Import2DimToPage(pgTarget, filSrc, spehdr);

		spe_SetPageNameAndLabel(pgTarget, spehdr, lpcszFile);
		
		// Output header to Notes window
		if( !iRet )
			/// SY 05/16/2005 QA70-6147 IMPORT_PRINCETON_INSTRUMENTS_ROPER_SCI
			///	iRet = spe_HeaderToNotes(spehdr, lpcszFile);
			iRet = spe_HeaderToNotes(pgTarget, spehdr, lpcszFile);
			/// end IMPORT_PRINCETON_INSTRUMENTS_ROPER_SCI
	}
	else
		iRet = SPE_ERR_READ_HEADER;

	// Close data file
	filSrc.Close();

	return iRet;
}

//--------------------------------------------------------------------------
// ImportPrincetonInstrumentsFile
//
// This function is called by Origin's Import Wizard.
//
// Return:
//	zero for success
//	non-zero for error
//--------------------------------------------------------------------------
int ImportPrincetonInstrumentsFile(Page &pgTarget, TreeNode &trFilter, LPCSTR lpcszFile, int nFile)
{
	if( trFilter.Type.nVal != FILTER_TYPE_USERDEFINED )
		return SPE_ERR_FILTER_TYPE;
	return ImportFileToPage(pgTarget, lpcszFile, nFile);
}

//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
int ImportSPEFrame(string lpcszMatrix, int nFrame)
{
	MatrixPage pg(lpcszMatrix);
	
	// get file path from page.info.system.import.filepath$
	string strFile;
	page_get_info_var_value(pg, "filepath", strFile, "system.import");
		
	// Open data file
	file filSrc;
	if( !filSrc.Open(strFile, file::modeRead | file::typeBinary | file::shareDenyWrite) )
		return SPE_ERR_FILE_OPEN;
	
	// Read header
	SPEHEADER spehdr;
	int i = filSrc.Read(&spehdr, sizeof(SPEHEADER));
	
	if( sizeof(SPEHEADER) == i )
		i = Import2DimToPage(pg, filSrc, spehdr, nFrame);  
	else
		i = SPE_ERR_READ_HEADER;
	
	filSrc.Close();
	
	return i;
}
