#include <origin.h>
#include <GetNBox.h>
#include <xfutils.h>
enum{
	insertDir_horizontal,
	insertDir_vertical,
};
enum{
	c2_none,
	c2_comments,
	c2_parameter1,
	c2_mean,
	c2_min,
	c2_max,
};
enum{
	c3_none,
	c3_comments,
	c3_parameter1,
	c3_mean,
	c3_min,
	c3_max,
};
enum{
	c4_none,
	c4_comments,
	c4_parameter1,
	c4_mean,
	c4_min,
	c4_max,
};
enum{
	c5_none,
	c5_comments,
	c5_parameter1,
	c5_mean,
	c5_min,
	c5_max,
};
enum{
	size_normal,
	size_double,
};
///Jake 04/19/07 ADD_SHOW_IN_HORIZONTAL_AND_SET_SCALE
//put additional include files here
#include <..\originlab\theme_utils.h>
#include <event_utils.h>
//put your own support static functions here
enum {
	ADDC_NAME = -1,
	ADDC_NONE = 0,
	ADDC_COMMENTS,
	ADDC_PARAM_1,
	ADDC_MEAN,
	ADDC_MIN,
	ADDC_MAX,
};
static double _get_col_stats(const Column& cc, int nType)
{
	vector vv(cc);
	if(vv.GetSize() < 1)
		return NANUM;
	
	if(ADDC_MEAN == nType)
	{
		double dSum;
		vv.Sum(dSum);
		return dSum / vv.GetSize();
	}
	double min, max;
	vv.GetMinMax(min, max);
	if(ADDC_MAX == nType)
		return max;
	else if(ADDC_MIN == nType)
		return min;
	
	return NANUM;
}

static string _get_label(Worksheet& wks, int nCol, int nType)
{
	string str;
	Column cc(wks, nCol);
	switch(nType)
	{
	case ADDC_NAME:
		{
			str = cc.GetLongName();
			if(str.IsEmpty())
				str = cc.GetName();
			return str;
		}
		break;
	case ADDC_COMMENTS:
		return cc.GetComments();
	case ADDC_PARAM_1:
	{
		vector<string> vsParams;
		cc.GetParameters(vsParams);
		if(vsParams.GetSize() > 0)
			return vsParams[0];
		return str;
	}
	case ADDC_MEAN:
	case ADDC_MAX:
	case ADDC_MIN:
		double dVal = _get_col_stats(cc, nType);
		str = ftoa(dVal);
		return str;
	}
	return "not ready";
}

//----Jake 04/19/07 ADD_SHOW_IN_HORIZONTAL_AND_SET_SCALE
static int _get_range_total(Range irng)
{
	int nCount = 0;
	int nIrng = irng.GetNumRanges();
	for(int ii = 0;ii < nIrng; ii++ )
	{
	 	Worksheet wksTemp;
		int sr1, sr2, sc1, sc2;
		irng.GetRange(ii, sr1, sc1, sr2, sc2, wksTemp);		
		if(!wksTemp)	
			XF_THROW(XFERR_INVALID_ARG)
		/// Hong 06/18/07 v8.0643 CLEAN_UP_CODE_AND_MORE_OPTION
		//for(int nC = sc1; nC <= sc2; nC++)nCount++;
		if ( sc2 < sc1 )
			nCount = wksTemp.GetNumCols() - sc1;
		else
			nCount = sc2 - sc1 + 1;
		/// end CLEAN_UP_CODE_AND_MORE_OPTION
	}
	return nCount;
}

static void _set_scale(Scale& x, Scale& y, double xfrom, double xto, double yfrom, double yto)
{
	if(xfrom != NANUM)x.From = xfrom;
	if(xto != NANUM)x.To = xto;
	if(yfrom != NANUM)y.From = yfrom;
	if(yto != NANUM)y.To = yto;
}

/// Hong 06/18/07 v8.0643 CLEAN_UP_CODE_AND_MORE_OPTION
/*
static void _show_vertical(Range irng,int name,int c2,int c3,int endpts, Range orng, DWORD dwCntrl,double xfrom, double xto, double yfrom, double yto)
{
	int nOrng;
	Worksheet wks;
	int dr1,dr2,dc1,dc2;
	if(!(nOrng = orng.GetNumRanges()))
		XF_THROW(XFERR_INVALID_ARG)
	orng.GetRange(0, dr1, dc1, dr2, dc2, wks);
	if(!wks)
		XF_THROW(XFERR_INVALID_ARG)
	int nIrng = irng.GetNumRanges();
	int nSparklineCol = name>0? dc1+1:dc1;
	int nNameCol = name>0? dc1:-1;
	int nMaxCol = nSparklineCol;
	if(c2 > ADDC_NONE)
		nMaxCol = nSparklineCol+1;
	if(c3 > ADDC_NONE)
		nMaxCol = nSparklineCol+2;
	int nMaxRow = dr1 + _get_range_total(irng);
	if(wks.GetNumRows() <= nMaxRow)
		wks.SetSize(nMaxRow, -1);
	if(wks.GetNumCols() <= nMaxCol)
		wks.SetSize(-1, nMaxCol+1);
	
	for(int ii = 0,nr = dr1;ii < nIrng;ii++, nr++)
	{
	 	Worksheet wksSrc;
		int sr1, sr2, sc1, sc2;
		irng.GetRange(ii, sr1, sc1, sr2, sc2, wksSrc);
		if(!wksSrc)	
			XF_THROW(XFERR_INVALID_ARG)
		for(int nC = sc1; nC <= sc2; nC++, nr++)
		{
			if(wksSrc.Columns(nC).GetType() != OKDATAOBJ_DESIGNATION_Y)
				continue;
			
			GraphPage gp;
			DataPlot dp = plot_col(wksSrc, nC, gp);
			GraphLayer gl(gp.GetName(),-1);
			Scale x(gl.X);
			Scale y(gl.Y);
			_set_scale(x, y, xfrom, xto, yfrom, yto);
			if(dp)
			{
				if(endpts) add_end_points(dp);
		
				if(nNameCol >=0)
					wks.SetCell(nr, nNameCol, _get_label(wksSrc, nC, ADDC_NAME));
				
				wks.EmbedGraph(nr, nSparklineCol, gp, dwCntrl);
				if(c2 > ADDC_NONE)
					wks.SetCell(nr, nSparklineCol+1, _get_label(wksSrc, nC, c2));
				if(c3 > ADDC_NONE)
					wks.SetCell(nr, nSparklineCol+2, _get_label(wksSrc, nC, c3));
			}
		}
		nr--;
	}
}



static void _show_horizontal(Range irng,int name,int c2,int c3,int endpts, Range orng, DWORD dwCntrl,double xfrom, double xto, double yfrom, double yto)
{
	int nOrng;
	Worksheet wks;
	int dr1,dr2,dc1,dc2;
	if(!(nOrng = orng.GetNumRanges()))
		XF_THROW(XFERR_INVALID_ARG)
	orng.GetRange(0, dr1, dc1, dr2, dc2, wks);
	if(!wks)
		XF_THROW(XFERR_INVALID_ARG)
	int nIrng = irng.GetNumRanges();
	int nSparklineRow = name>0? dr1+1:dr1;
	int nNameRow = name>0? dr1:-1;
	int nMaxRow = nSparklineRow;
	if(c2 > ADDC_NONE)
		nMaxRow = nSparklineRow + 1;
	if(c3 > ADDC_NONE)
		nMaxRow = nSparklineRow + 2;
	int nMaxCol = dc1 + _get_range_total(irng);
	if(wks.GetNumRows() <= nMaxRow)
		wks.SetSize(nMaxRow + 1, -1);
	if(wks.GetNumCols() <= nMaxCol)
		wks.SetSize(-1, nMaxCol);
	for(int ii = 0,nc = dc1;ii < nIrng;ii++, nc++)
	{
	 	Worksheet wksSrc;
		int sr1, sr2, sc1, sc2;
		irng.GetRange(ii, sr1, sc1, sr2, sc2, wksSrc);
		if(!wksSrc)	
			XF_THROW(XFERR_INVALID_ARG)
		for(int nC = sc1; nC <= sc2; nC++, nc++)
		{
			if(wksSrc.Columns(nC).GetType() != OKDATAOBJ_DESIGNATION_Y)
				continue;
			
			GraphPage gp;	
			DataPlot dp = plot_col(wksSrc, nC, gp);
			GraphLayer gl(gp.GetName(),-1);
			Scale x(gl.X);
			Scale y(gl.Y);
			_set_scale(x, y, xfrom, xto, yfrom, yto);
			if(dp)
			{
				if(endpts) add_end_points(dp);
		
				if(nNameRow >=0)
					wks.SetCell(nNameRow, nc, _get_label(wksSrc, nC, ADDC_NAME));
				
				wks.EmbedGraph(nSparklineRow, nc, gp, dwCntrl);
				if(c2 > ADDC_NONE)
					wks.SetCell(nSparklineRow + 1, nc, _get_label(wksSrc, nC, c2));
				if(c3 > ADDC_NONE)
					wks.SetCell(nSparklineRow + 2, nc, _get_label(wksSrc, nC, c3));
			}
		}
		nc--;
	}
	
}
*/
static bool _set_cell(Worksheet& wksDet, Worksheet& wksSrc, int& nRow, int& nCol, int nDataCol, int nCellType, bool bVertical)
{
	if ( !wksDet || !wksSrc )
		return false;
	
	if ( bVertical )
		nCol++;
	else
		nRow++;
	
	if ( nCellType > ADDC_NONE )
		wksDet.SetCell( nRow, nCol, _get_label(wksSrc, nDataCol, nCellType) );
		
	return true;
}

static int _show_sparklines_and_options(DataRange& irng, bool bUseLName, int nCell2, int nCell3, int nCell4, int nCell5, LPCSTR lpszTemplate, bool bAddEndPts, DataRange& orng, DWORD dwCntrl, double dXFrom, double dXTo, double dYFrom, double dYTo, bool bVertical)
{
	Worksheet wks;
	int nR1, nR2, nC1, nC2;
	if( orng.GetNumRanges() <= 0 )
		return XFERR_INVALID_RANGE;
	
	orng.GetRange(0, nR1, nC1, nR2, nC2, wks);
	if ( !wks )
		return CER_INVALID_WKS;
	
	int nSparklines, nName = -1;
	nSparklines = bVertical ? nC1 : nR1;
	
	if ( bUseLName )
	{
		nSparklines++;
		nName = bVertical ? nC1 : nR1; 
	}
	
	int nNumRange = irng.GetNumRanges();
	
	int nMaxCol, nMaxRow, nMaxRowCol = nSparklines;
	
	if ( nCell5 > ADDC_NONE )
		nMaxRowCol = nSparklines + 4;
	else if ( nCell4 > ADDC_NONE )
		nMaxRowCol = nSparklines + 3;
	else if ( nCell3 > ADDC_NONE )
		nMaxRowCol = nSparklines + 2;
	else if ( nCell2 > ADDC_NONE )
		nMaxRowCol = nSparklines + 1;
	
	if ( bVertical )
	{
		nMaxCol = nMaxRowCol + 1;
		nMaxRow = nR1 + _get_range_total(irng);
	}
	else
	{
		nMaxRow = nMaxRowCol + 1;
		nMaxCol = nC1 + _get_range_total(irng);
	}

	if(wks.GetNumRows() <= nMaxRow)
		wks.SetSize(nMaxRow, -1);
	if(wks.GetNumCols() <= nMaxCol)
		wks.SetSize(-1, nMaxCol); // ==>need confirm
	
	int nRowCol = bVertical ? nR1 : nC1;
	for (int ii = 0; ii < nNumRange; ii++)
	{
		Worksheet wksSrc;
		int r1, r2, c1, c2;
		irng.GetRange(ii, r1, c1, r2, c2, wksSrc);
		
		if ( !wksSrc )	
			return CER_INVALID_WKS;
		
		if ( -1 == c2 )
			c2 = wksSrc.GetNumCols() - 1;
		
		for (int nC = c1; nC <= c2; nC++, nRowCol++)
		{
			if(wksSrc.Columns(nC).GetType() != OKDATAOBJ_DESIGNATION_Y || is_col_all_text(wksSrc, nC) > 0)
				continue;
			
			GraphPage gp;	
			DataPlot dp = plot_col(wksSrc, nC, gp, IDM_PLOT_LINE, true, lpszTemplate);
			
			if ( !dp )
				continue;
			
			GraphLayer gl(gp.GetName(), -1);
			Scale sclX(gl.X);
			Scale sclY(gl.Y);
			_set_scale(sclX, sclY, dXFrom, dXTo, dYFrom, dYTo);							
			
			if ( bAddEndPts ) 
				add_end_points(dp);
			
			int nRow, nCol;

			if ( nName >= 0 )
			{
				if ( bVertical )
				{
					nRow = nRowCol;
					nCol = nName;
				}
				else
				{
					nRow = nName;
					nCol = nRowCol;
				}
				wks.SetCell(nRow, nCol, _get_label(wksSrc, nC, ADDC_NAME));
			}
			
			if ( bVertical )
			{
				nRow = nRowCol;
				nCol = nSparklines;
			}
			else
			{
				nRow = nSparklines;
				nCol = nRowCol;
			}
				
			wks.EmbedGraph(nRow, nCol, gp, dwCntrl);
			
			_set_cell(wks, wksSrc, nRow, nCol, nC, nCell2, bVertical);
			_set_cell(wks, wksSrc, nRow, nCol, nC, nCell3, bVertical);
			_set_cell(wks, wksSrc, nRow, nCol, nC, nCell4, bVertical);
			_set_cell(wks, wksSrc, nRow, nCol, nC, nCell5, bVertical);
		}
	}
	
	return 0;
}
/// end CLEAN_UP_CODE_AND_MORE_OPTION
//----end ADD_SHOW_IN_HORIZONTAL_AND_SET_SCALE


void insertSparklines(const Range& irng, const int& insertDir, const int& name, const int& c2, const int& c3, const int& c4, const int& c5, const string& template, const int& label, const int& keepAspect, const int& size, const int& endpts, Range& orng, const double& xfrom, const double& xto, const double& yfrom, const double& yto)
{
	
	//	Worksheet wksSrc;
	//	int sr1, sr2, sc1, sc2;
	//int nIrng,nOrng;//
	//if(!irng.GetNumRanges())
	//if(!(nIrng = irng.GetNumRanges()))
		//XF_THROW(XFERR_INVALID_ARG)
	//irng.GetRange(0, sr1, sc1, sr2, sc2, wksSrc);
	//if(!wksSrc)
		//XF_THROW(XFERR_INVALID_ARG)
	int nOrng;
	Worksheet wks;
	int dr1,dr2,dc1,dc2;
	if(!(nOrng = orng.GetNumRanges()))
		XF_THROW(XFERR_INVALID_RANGE);
	orng.GetRange(0, dr1, dc1, dr2, dc2, wks);
	if(!wks)
		XF_THROW(CER_INVALID_WKS);
	
	//BOOL keepAscpect = false;
	DWORD dwCntrl = EMBEDGRAPH_HIDE_AXES | EMBEDGRAPH_HIDE_LEGENDS | EMBEDGRAPH_HIDE_SPECTRUMS;
	if(label)
		dwCntrl |= EMBEDGRAPH_HIDE_TEXT_OBJS;
	
	if(keepAspect) dwCntrl |= EMBEDGRAPH_KEEP_ASPECT_RATIO;
	if(size) dwCntrl |= EMBEDGRAPH_SPARKLINE_LARGE;
	
	//----Jake 04/19/07 ADD_SHOW_IN_HORIZONTAL_AND_SET_SCALE
	/// Hong 06/18/07 v8.0643 CLEAN_UP_CODE_AND_MORE_OPTION
	//if(insertDir == insertDir_horizontal)
	//	_show_horizontal(irng,name,c2,c3,endpts,orng,dwCntrl,xfrom,xto,yfrom,yto);
	//else
	//	_show_vertical(irng,name,c2,c3,endpts,orng,dwCntrl,xfrom,xto,yfrom,yto);
	int nRet = 0;
	if ( nRet = _show_sparklines_and_options(irng, name, c2, c3, c4, c5, template, endpts, orng, dwCntrl, xfrom, xto, yfrom, yto, insertDir) )
		XF_THROW(nRet);
	/// end CLEAN_UP_CODE_AND_MORE_OPTION
	
	//int nSparklineCol = name>0? dc1+1:dc1;
	//int nNameCol = name>0? dc1:-1;
	//int nMaxCol = nSparklineCol;
	//if(c2 > ADDC_NONE)
		//nMaxCol = nSparklineCol+1;
	//if(c3 > ADDC_NONE)
		//nMaxCol = nSparklineCol+2;
		//
	//if(wks.GetNumCols() <= nMaxCol)
		//wks.SetSize(-1, nMaxCol+1);
	
	//for(int ii = 0,nr = dr1;ii < nIrng;ii++, nr++)
	//{
	 	//Worksheet wksSrc;
		//int sr1, sr2, sc1, sc2;
		//irng.GetRange(ii, sr1, sc1, sr2, sc2, wksSrc);
		//if(!wksSrc)	
			//XF_THROW(XFERR_INVALID_ARG)
		////for(int nC = sc1,nr = dr1; nC <= sc2; nC++, nr++)
		//for(int nC = sc1; nC <= sc2; nC++, nr++)
		//{
			//if(wksSrc.Columns(nC).GetType() != OKDATAOBJ_DESIGNATION_Y)
				//continue;
			//
			//GraphPage gp;
			//DataPlot dp = plot_col(wksSrc, nC, gp);
			//if(dp)
			//{
				//if(endpts) add_end_points(dp);
		//
				//if(nNameCol >=0)
					//wks.SetCell(nr, nNameCol, _get_label(wksSrc, nC, ADDC_NAME));
				//
				//wks.EmbedGraph(nr, nSparklineCol, gp, dwCntrl);
				//if(c2 > ADDC_NONE)
					//wks.SetCell(nr, nSparklineCol+1, _get_label(wksSrc, nC, c2));
				//if(c3 > ADDC_NONE)
					//wks.SetCell(nr, nSparklineCol+2, _get_label(wksSrc, nC, c3));
			//}
		//}
		//nr--;
	//}
	//----end ADD_SHOW_IN_HORIZONTAL_AND_SET_SCALE
}

//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 insertSparklines_event1(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	if( xf_is_extended_event(nEventID) )
		return insertSparklines_event1_ex(trGetN, nRow, nEventID, dwEnables, lpcszNodeName, DynaCntrlContainer, strAux, strErrMsg);
	DECLARE_BUTTON_ENABLES
	/// Max 6/18/07 MODIFY_ERROR_CHECK
	/*
	int nErr = check_1_cell(trGetN.orng);//.strVal);	///Jasmine 01/26/07 CHECK_1_CELL_MODIFICATION
	if(nErr != CER_NO_ERROR)
	{
		bOKEnable = false;
		strErrMsg = nErr;
		
		return true;
	}
	/// Hong 06/18/07 v8.0643 CLEAN_UP_CODE_AND_MORE_OPTION 
	if ( GETNE_ON_INIT == nEventID || GETNE_ON_THEME == nEventID )
	{
		bOKEnable = !trGetN.irng.strVal.IsEmpty();
		if( !bOKEnable )
			strErrMsg = XFERR_INVALID_RANGE;
	}
	
	if ( 0 == lstrcmp( lpcszNodeName, "irng") )
	{
		bOKEnable = !trGetN.irng.strVal.IsEmpty();
		if( !bOKEnable )
			strErrMsg = XFERR_INVALID_RANGE;
		
		return true;
	}
	/// end CLEAN_UP_CODE_AND_MORE_OPTION
	*/
	
	int nErr = CER_NO_ERROR;
	
	if(!(nErr = check_1_column(trGetN.irng, true)))
		nErr = check_1_cell(trGetN.orng);
	
	if(nErr != CER_NO_ERROR)
	{
		bOKEnable = false;
		strErrMsg = nErr;
		if(nErr == CER_COL_NUM_TOO_FEW_EX)
			strErrMsg += ":" + 1;
	}		
	/// END MODIFY_ERROR_CHECK
	return false;

}

int insertSparklines_make_tree(TreeNode& tr, LPCSTR lpcszVarName)
{
	return -1;
}
//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 insertSparklines_before_execute(TreeNode& trGetN, int nGetNDialog, int& nRet, int dwCntrl)
{

}
//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 insertSparklines_event1_ex(TreeNode& trGetN, int nRow, int nEventID, DWORD& dwEnables, LPCSTR lpcszNodeName, WndContainer& DynaCntrlContainer, string& strAux, string& strErrMsg)
{
	return false;
}
