 /*-----------------------------------------------------------------------------*
 * File Name: ReportTreeBase.h		 											*
 * Creation:																	*
 * Purpose: OriginC Source C file												*
 * Copyright (c) ABCD Corp.	2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010		*
 * All Rights Reserved															*
 * 																				*
 * Modification Log:															*
 * 																				*
 *------------------------------------------------------------------------------*/

#ifndef	_REPORTTREEBASE_H
#define _REPORTTREEBASE_H

#define		STR_WKS_PAGE_NAME					"Report"
#define 	STR_CALCULATION_TABLE_PREFIX		"Table"

#define		STR_BRANCH_TAG_NAME_PRE				"Level"

static int	m_snIDs=0;


//to hold the tables in ReportTreeBase
class ReportTable : public TreeNode
{
public:
	ReportTable()
	{
		
		checkValid();
		
	}
	
	ReportTable(TreeNode& trTable) : TreeNode(trTable)
	{
		
		checkValid();
	}
	
	void AddRow(vector& vec, LPCSTR strRowLabel = NULL, vector<string>& vsColLabels = NULL)
	{
		TreeNode 	trTable = *this;
		
		int			nRowID = getNewID();
		TreeNode	trRow = check_add_enumerated_node(trTable, CALCULATION_PARAMETER_PREFIX, m_nRow++, nRowID, STR_LABEL_ATTRIB, strRowLabel);
		
		if(vsColLabels)
		{
			int nColID = 100;
			for(int ii=0; ii<vec.GetSize(); ii++)
			{			
				string strColLabel = " "; //if not label for this column, then let it empty
				if( vsColLabels && ii < vsColLabels.GetSize())
					strColLabel = vsColLabels[ii];
				
				TreeNode	trCol = tree_check_get_node(trRow, "Column"+ii, nColID, STR_LABEL_ATTRIB, strColLabel);
				trCol.dVal = vec[ii];
				
				nColID++;
			}
		}
		else
			trRow.dVals = vec; //no need column label for this data
	}
	
	ReportTable GetTable(LPCSTR lpcszTagName)
	{
		TreeNode 	trNode = this->GetNode(lpcszTagName);
		
		ReportTable rtTable(trNode);
		return rtTable;
	}
	
	TreeNode& GetTree()
	{
		TreeNode 	trTable = *this;
		return trTable;
	}
	
	void SetupTable(vector<string>& vsLabels = NULL)
	{
		TreeNode 	trTable = *this;
		
		int index = 0;
		foreach(TreeNode trN in trTable.Children)
		{	
			//add DataID auto for each row
			int nRowID = getNewID();
			trN.SetAttribute(STR_DATAID_ATTRIB, nRowID);
				
			//add label for each row
			if( vsLabels && index< vsLabels.GetSize() )
				trN.SetAttribute(STR_LABEL_ATTRIB, vsLabels[index] );
				
			index++;		
		}
	}
	
	//bSetup: true, to setup DataID and Label(if vsLabels is not NULL)  of each row in table
	void UpdateTable(TreeNode& trN, bool bSetup = true, vector<string>& vsLabels = NULL)
	{		
		TreeNode 	trTable = *this;
	
		foreach(TreeNode trSub in trN.Children)
		{
			trTable.AddNode(trSub);
		}
		
		if(bSetup)
			SetupTable(vsLabels);
	}
	
	int	GetTableID()
	{
		TreeNode 	trTable = *this;
		
		int			nTableID;
		trTable.GetAttribute(STR_DATAID_ATTRIB, nTableID);
		
		return nTableID;
	}
	
	bool IsValid()
	{
		return m_nIsValid;
	}
private:
	void checkValid()
	{
		TreeNode 	trTable = *this;
		m_nIsValid = false;
		if( trTable )
			m_nIsValid = true;
	}
	
	int	getNewID()
	{
		return ++m_snIDs;
	}
	
private:
//	static int	m_snRowIDs;
	int			m_nRow;
	
	bool		m_nIsValid;
	
	
};
//class ReportTable :: m_snRowIDs = 0;


//can hold one or multiple report table
class ReportTreeBase : public TreeNode
{
public:
	ReportTreeBase(TreeNode &tr): TreeNode(tr)
	{	
		
		m_nTable = -1;
		m_nTableID = 10000;
		m_nTableFormat = 0;
		
		m_bIsValid = false;
		TreeNode trThis = *this;
		if( trThis )
		{
			m_bIsValid = true;
		
			int	nDataID = ++m_nTableID;
			if( !trThis.GetAttribute(STR_DATAID_ATTRIB, nDataID) )
			{
				trThis.SetAttribute(STR_DATAID_ATTRIB, nDataID);
			}
			trThis.SetAttribute(TREE_Table, GetTableFormat(true, false));
		}
	}
	
	bool IsValid()
	{
		return m_bIsValid;
	}
	
	void SetReportingTableFormat(int nFormat/*, bool bHasSubTables = false*/)
	{
		m_nTableFormat = nFormat;
	}
	
	virtual bool Report(Worksheet& wksOutput)
	{
		
		TreeNode trThis = *this;
		if( trThis )
		{
			//Worksheet 	wksOutput;
			PrepareOutputWindow(wksOutput);
			if( !wksOutput )
				return false;

			wksOutput.SetReportTree(trThis);
			autosize_rowcol(wksOutput); //auto resize table
			
			return true;
		}
		 
		return false;
		
	}	
	
	ReportTable& GetTable(int index)
	{
		TreeNode 	trThis = *this;		
		
		int 		nTableID = m_vnTableIDs[index];		
		TreeNode 	trTemp = tree_get_node_by_dataid(trThis, nTableID);		
		ReportTable rtTable(trTemp);		
		
		return rtTable;
	}
	
	ReportTable& CreateTable(LPCSTR lpcszLabel, LPCSTR lpcszTagName = NULL)
	{
		TreeNode 	trThis = *this;	
		
		string		strTagName(lpcszTagName);
		if( strTagName.IsEmpty() )
			strTagName = STR_CALCULATION_TABLE_PREFIX + m_nTable;
			
		int			nTableID = ++m_nTableID;
		TreeNode 	trTable = tree_check_get_node(trThis, strTagName, nTableID, STR_LABEL_ATTRIB, lpcszLabel);
		updateReportingTableFormat(trTable);
		m_nTable++;		
		m_vnTableIDs.Add(nTableID);
		

		ReportTable reportTable(trTable);
		
		return reportTable;
	}
	
	ReportTable& AddTable(TreeNode& trN, LPCSTR lpcszLabel = NULL, const vector<string>& vsLabels = NULL)
	{	
		string strName(lpcszLabel);
		if(strName.IsEmpty())
			strName = trN.tagName;
		
		ReportTable reportTable = CreateTable(strName, trN.tagName);
		foreach(TreeNode trSub in trN.Children)
		{
			reportTable.AddNode(trSub);
			updateReportingTableFormat(trSub);
		}
		reportTable.SetupTable(vsLabels);		
		
		return reportTable;	
		
	}
	
	ReportTreeBase& AddOneLevel(LPCSTR lpcszLabel) 
	{
		TreeNode	trLevel =  *this;
		TreeNode 	trSubLevel;
		
		int 		nID = getNewID();
		TreeNodeCollection	trColl(trLevel, STR_BRANCH_TAG_NAME_PRE);
		int			nNode = trColl.Count();
		
		trSubLevel = check_add_enumerated_node(trLevel, STR_BRANCH_TAG_NAME_PRE, nNode, nID, STR_LABEL_ATTRIB, lpcszLabel);
		trSubLevel.SetAttribute(TREE_Table, GetTableFormat(true, false));
		
		ReportTreeBase rtSub(trSubLevel);		
		return rtSub;
	}
	
	//the default format for reporting table
	int GetTableFormat(bool bOpen = true, bool bTranspose = true, bool bColHeadings = false, bool bAutoWidth = true,
		bool bRowHeadingHide = true, bool bWritable = false)
	{
		uint nn = GETNBRANCH_RESIZE;
		
		if( bOpen )
			nn |= GETNBRANCH_OPEN;
			
		if( bTranspose )
			nn |= GETNBRANCH_TRANSPOSE;
		
		if(!bColHeadings)
			nn |= GETNBRANCH_HIDE_COL_HEADINGS;
		
		if( bAutoWidth )
			nn |= GETNBRANCH_FIT_COL_WIDTH | GETNBRANCH_FIT_ROW_HEIGHT;
		
		if( bRowHeadingHide )
			nn |= GETNBRANCH_HIDE_ROW_HEADINGS;
		
		if ( bWritable )
			nn |= GETNBRANCH_WRITABLE;		

		return nn;
	}	
	
	//int InsertTable(const ReportTable& trBefore, ReportTable& rtTable)
	//{
		//TreeNode 	trThis = *this;
		//
		//string 		strTemp = "Temp";
		//TreeNode 	trNode = trThis.InsertNode(trBefore, strTemp);
		//trNode.Replace(rtTable);
		//
		//int			nFind; 		 //finding count of before table IDs
		//int			nTableIndex; //the inserted table index
		//int			nBeforeTableID; 
		//vector<uint> vecIndex;
		//nFind = m_vnTableIDs.Find(vecIndex, trBefore.GetTableID(), trBefore.GetTableID() );
		//if( -1 != nFind )
		//{
			//nTableIndex = vecIndex[0];
			//m_vnTableIDs.InsertAt(nTableIndex, rtTable.GetTableID());
		//}
		//
		//return nTableIndex;
	//}
protected:	
	virtual void PrepareOutputWindow(Worksheet& wksOutput)
	{		
		prepareOutputPage(wksOutput);
		
		SetupOutputSheet(wksOutput);
	}
	
	//prepare output worksheet sheet
	void SetupOutputSheet(Worksheet& wksOutput)
	{
		if( !wksOutput )
			return;
		
		DWORD 	dwOptions = GETNBRANCH_HIDE_COL_LABELS;	
		dwOptions |= GETNBRANCH_FIT_COL_WIDTH | GETNBRANCH_FIT_ROW_HEIGHT;
		
		DWORD 	dwCntrl = WP_SHEET_HIERARCHY | CREATE_NO_DEFAULT_TEMPLATE | WP_SHEET_THIN_COL_HEADERS | WP_SHEET_MAIN_NAN_AS_BLANK;
		
		WorksheetPage 	wksPage;
		string 			strSheetName = wksOutput.GetName();
		wksOutput.GetParent(wksPage);
		
		int 	index = wksPage.AddLayer("Temp", dwCntrl, NULL, dwOptions );
		wksOutput = wksPage.Layers(index);
		
		if( index > 0) // there was already another sheet, 
		{
			Worksheet wksJunk = wksPage.Layers(strSheetName);
			wksJunk.Destroy();
			wksOutput.SetName(strSheetName);
		}

		if(wksOutput.GetNumCols() > 0)
		{
			wksOutput.SetSize(-1, 0);
			error_report("Report worksheet not empty when inserted");
		}
		
		// report sheet has one col on the main sheet and all other info
		// are in tables with their own cols			
		int nCol = wksOutput.AddCol("comments");
		Column cc(wksOutput, nCol);
		cc.SetWidth(40);// make the main col wide enough to show info
		cc.SetJustify(COL_JUSTIFY_LEFT);
		cc.SetType(OKDATAOBJ_DESIGNATION_NONE);
	}
private:
	bool tr_to_vec(TreeNode& tr, vector& vec, vector<string>& vsLabels = NULL)
	{
		if(tr.GetNodeCount()==0)
			return false;
		
		vec.SetSize(0);
		if(vsLabels)
			vsLabels.SetSize(0);
		foreach(TreeNode trN in tr.Children)
		{
			vec.Add(trN.dVal);
			if(vsLabels)
			{
				string strLabel;
				if(!trN.GetAttribute(STR_LABEL_ATTRIB, strLabel))
					strLabel = trN.tagName;
				vsLabels.Add(strLabel);
			}
		}
		
		return true;
	}
	//need setup report table format
	void updateReportingTableFormat(TreeNode& trTable)
	{
		if(!trTable.IsValid())
			return;
		
		if( 0 == m_nTableFormat)
			m_nTableFormat = GetTableFormat(true, false);
		
		trTable.SetAttribute(TREE_Table, m_nTableFormat);
	}
	
	
	//prepare output worksheet page, maybe output to source page, new page, special page...
	void prepareOutputPage(Worksheet& wksOutput)
	{
		// only support create a new worksheetpage now
		if( !wksOutput.IsValid() )
		{	
			wksOutput.Create("Origin");
			wksOutput.GetPage().Rename(STR_WKS_PAGE_NAME, FALSE);
		}
	}
	
	int	getNewID()
	{
		return ++m_snIDs;
	}

	
private:	
	int						m_nTableFormat;
	//bool					m_bHasSubTables;
	
	int						m_nTableID;
	int						m_nTable;
	vector<uint>			m_vnTableIDs;
	
	bool					m_bIsValid;
	
};


//XFunction report tree class

/// YuI 11/09/05 QA70-8279 REPORT_TREE_AND_REPORT_DATA_XVARIABLES
/*
class XVReportTree : public ReportTreeBase
{
public:
	XVReportTree(TreeNode &tr): ReportTreeBase(tr)
	{	
	}
	
	void SetVariableTree(TreeNode& trVar)
	{
		m_trVar = trVar;
	}
protected:
	virtual void PrepareOutputWindow(Worksheet& wksOutput)
	{	
		//if( !checkIsNewData() )
		//	return;
		
		WorksheetPage wp;
		if( perpareOutputPage(wp) )	
		{
			perpareOutputSheet(wp, wksOutput);	
			SetupOutputSheet(wksOutput);
		}
		
	}
	
private:
	bool 	perpareOutputPage(WorksheetPage& wp)
	{
		string 	strBook;
		int 	nBookType = cvt_str_to_predefined_type(m_trVar.Data.Book.strVal);
		switch(nBookType)
		{
		case PDS_NEW:
			wp.Create("origin");
			strBook = wp.GetName();
			return true;
		case PDS_SAME:
			getBookSheetInfo("Book", strBook);
			break;
		default:
			strBook = m_trVar.Data.Book.strVal;
			break;
		}
		wp = Project.WorksheetPages(strBook);
		if( !wp )
		{
			error_report("fail to get book object in PrepareOutputWindow");
			return false;
		}
		wp.SetShow();
		return true;
	}
	
	bool 	perpareOutputSheet(WorksheetPage& wp, Worksheet& wksOutput)
	{
		string 	strSheet;
		int 	nSheetType = cvt_str_to_predefined_type(m_trVar.Data.Sheet.strVal);
		switch(nSheetType)
		{
		case PDS_NEW:
			int nn = wp.AddLayer();
			wksOutput = wp.Layers(nn);			
			return true;
		case PDS_SAME:
			getBookSheetInfo("Sheet", strSheet);
			break;
		default:
			strSheet = m_trVar.Data.Book.strVal;
			break;
		}		
		wksOutput = wp.Layers(strSheet);
		
		if( !wksOutput )
			return false;
		
		return true;
	}	
	
	BOOL	checkIsNewData()
	{
		return PDS_NEW == convertToPredefinedType();	
	}

	bool getBookSheetInfo(LPCSTR lpcszNode, string& strBookSheet)
	{
		TreeNode trTemp = m_trVar.Data.Temp;
		if( !trTemp )
			return false;
	
		TreeNode trNode = trTemp.GetNode(lpcszNode);
		if( trNode )
		{
			strBookSheet = trNode.strVal;			
		}		
		return true;
		
	}
	
	int convertToPredefinedType()
	{
		string str;
		if(m_trVar.valdata.GetNodeCount() > 0) // is Branch
			str = m_trVar.valdata.X.strVal;
		else
			str = m_trVar.valdata.strVal;
		
		//if(pstr)
		//	*pstr = strVal;
		return cvt_str_to_predefined_type(str);
	}	
	
private:
	TreeNode		m_trVar;

};
*/

class ReportTree	:	public	ReportTreeBase
{
public:
	ReportTree(TreeNode& tr)	:	ReportTreeBase(tr)
	{
	}
};
/// end REPORT_TREE_AND_REPORT_DATA_XVARIABLES


////////////////////Test code to check if ReportTreeBase class wprked
/*
#include "ReportTreeBase.h"
struct stTest
{
	int n;
	double d;
};

void testReportTreeBase()
{	
	int nSize = 3;
	//Prepare data
	vector v1;
	v1.Data(1,nSize,1);
	
	vector v2(nSize);
	for(int ii=0; ii<v2.GetSize(); ii++)
		v2[ii]= rnd();
	
	stTest st;
	st.n = 1;
	st.d = 0.5;
	
	
	Tree tr;
	TreeNode trGUI = tr.AddNode("GUI");	
	TreeNode trOut = tr.AddNode("Calculation");	
	ReportTreeBase trReport(trOut);
	if( !trReport.IsValid() )
		return;
	
	//add the Table includeing vector data
	ReportTreeBase& rtBranch = trReport.AddOneLevel("Level 1");
	ReportTreeBase& rtBranch2 = rtBranch.AddOneLevel("Level 2");
	
	ReportTable rtTable = rtBranch2.CreateTable(_L("Descriptive Statistics"), _L("DescStat"));
	
	vector<string> vsColLabels = {"a", "test 1", "prob"};
	if( rtTable.IsValid() )
	{
		rtTable.AddRow(v1, _L("Data1"), vsColLabels);
		rtTable.AddRow(v2, _L("Data2"), vsColLabels);
	}
	
	//add the Table includeing struct	
	Tree 		trTemp;
	TreeNode 	trN = trTemp.AddNode("test");
	trN += st;	
	ReportTreeBase& rtBranch3 = rtBranch.AddOneLevel("Level 3");
	rtBranch3.AddTable(trN, _L("Add Table from struct"));
	
	//report....
	WorksheetPage wkPage = Project.Pages();
	if(!wkPage)
		return;
	Worksheet wks = wkPage.Layers(0);
	trReport.Report(wks);
	
}
*/
#endif //_REPORTTREEBASE_H