 /*------------------------------------------------------------------------------*
 * File Name: ExtractWksData 													*
 * Creation : Sim 04-13-2009													*
 * Purpose: OriginC Source C file												*
 * Copyright (c) Originlab Corp.	2006										*
 * All Rights Reserved															*
 * 																				*
 * Modification Log:															*
 * Sophy 8/7/2009 v8.1088 EXTRACT_WKS_DATA_SAVE_RECALCULATE_MODE_TO_SOURCE_SHEET*
 * Sim 10-13-2009 FIX_WRONG_ROWS_WHEN_RUN_EXTRACT_WKS_FROM_LT					*
 * Sim 10-14-2009 FIX_WRONG_COLS_WHEN_RUN_EXTRACT_WKS_FROM_LT					*
 *	Folger 10/14/2010 ORG-1259-P1 EXTRACT_WKS_DATA_SHOULD_NOT_ACTIVE_OUTPUT_SHEET_WHEN_RECALCULATE
 *	Folger 10/15/2010 ORG-1258 ADD_SELECT_OPTION_IN_WORKSHEET_QUERY				*
 *------------------------------------------------------------------------------*/
 
#include <Origin.h>
#include <ocu.h>
#include <XFBase.h>
#include "ExtractWksData.h"
#include <GetNBox.h>

enum
{
	DIRTY_CONDITION		= 0x0001,
	DIRTY_VAR_DEF		= 0x0002,
	DIRTY_ROW_RANGE		= 0x0004,
};

#define DIRTY_NEED_RESEL_ROW	(DIRTY_CONDITION | DIRTY_VAR_DEF)
#define DIRTY_ALL 				(DIRTY_CONDITION | DIRTY_VAR_DEF | DIRTY_ROW_RANGE)


string ExtractWksDataAlias::GetAliasLTScript()
{
	string strLTScript;
	if( vnCols.GetSize() != vsAliasNames.GetSize() )
		return strLTScript;
	
	strLTScript = "const null=0/0;const nul=0/0;const NANUM=0/0;";//--- CPY 6/15/06 DEFINE_NULL_TO_ALLOW_MISSING_VALUE_TEST
	
	for( int ii = 0; ii < vsAliasNames.GetSize(); ii++ )
	{
		string strAlias;
		strAlias.Format("range %s = %d;", vsAliasNames[ii], vnCols[ii]);
		//strAlias.Format("range %s = %d;", vsAliasNames[ii], _0_offset_index_to_lt_index(vnCols[ii]));
		strLTScript += strAlias;
	}
	return strLTScript;
}


#define STR_NEXT_LINE_SEP "\r\n"
//#define STR_FORMAT_ALIAS	"%s= %d\r\n"
#define CHAR_ALIAS_SEP	'='

string ExtractWksDataAlias::GetAliasLines()
{
	ASSERT( vsAliasNames.GetSize() == vnCols.GetSize() );

	vector<string> vsAliases;
	int nSizeAlias = vsAliasNames.GetSize();
	for( int ii = 0; ii < nSizeAlias; ii++ )
	{
		string strRow;
		strRow.Format("%s%c %d", vsAliasNames[ii], CHAR_ALIAS_SEP, vnCols[ii]);
		vsAliases.Add(strRow);
	}
	
	//string strAliases;
	//strAliases.SetTokens(vsAliases, STR_NEXT_LINE_SEP);	
	string strAliases = str_combine(vsAliases, STR_NEXT_LINE_SEP);

	return strAliases;
}

bool ExtractWksDataAlias::SetAliasLines(LPCSTR lpcszAliases)
{
	vsAliasNames.SetSize(0);
	vnCols.SetSize(0);
	
	string strAliases(lpcszAliases);
	vector<string> vsAliases;
	str_separate(strAliases, STR_NEXT_LINE_SEP, vsAliases);
	int nSizeAlias = vsAliases.GetSize();
	for( int ii = 0; ii < nSizeAlias; ii++ )
	{
		string strRow(vsAliases[ii]);
		strRow.TrimLeft(); strRow.TrimRight();
		
		int nPosition;

		// invalid
		if(strRow.IsEmpty())
			continue;
		nPosition = strRow.Find("=");
		if ( nPosition < 0 )
			continue;
		
		string strAliasName = strRow.Left(nPosition); 
		strAliasName.TrimLeft(); strAliasName.TrimRight();
		
		string strColIndex = strRow.Mid(nPosition + 1);	
		strColIndex.TrimLeft(); strColIndex.TrimRight();
		
		nPosition = strColIndex.Find(" ");
		if ( nPosition >= 0 ) // only deal with first param, sec param is long name or none
			strColIndex = strColIndex.Left(nPosition);
			
		int nColIndex = atoi(strColIndex);

		vsAliasNames.Add(strAliasName);
		vnCols.Add(nColIndex);
	}

	return true;
}

bool ExtractWksDataAlias::GetTree(TreeNode& tr)
{
	if(!tr)
		return false;
	//tr.Reset();
	//
	//GETN_USE(tr)
	//vector<int> vnTempCols;				//convert_int_vector_to_string_vector requires vector<int>
	//vnTempCols = vnCols;
	//vector<string> vsAliasCols;
	//convert_int_vector_to_string_vector(vnTempCols, vsAliasCols);
	//string strAliasCols;
	//strAliasCols.SetTokens(vsAliasCols, '|');
	//GETN_STR(Cols, "Cols", strAliasCols)								GETN_ID(EXT_WKS_DATA_ALIAS_COLUMNS_ID)
	//
	//string strAliasNames;
	//strAliasNames.SetTokens(vsAliasNames, '|');
	//GETN_STR(AliasNames, "AliasNames", strAliasNames)			GETN_ID(EXT_WKS_DATA_ALIAS_NAMES_ID)
	vector<int> vnTempCols;				//convert_int_vector_to_string_vector requires vector<int>
	vnTempCols = vnCols;
	vector<string> vsAliasCols;
	convert_int_vector_to_string_vector(vnTempCols, vsAliasCols);
	string strAliasCols;
	strAliasCols.SetTokens(vsAliasCols, '|');
	//tr.Cols.strVal = strAliasCols;
	TreeNode trCols = tree_check_get_node_by_dataid(tr, "Cols", EXT_WKS_DATA_ALIAS_COLUMNS_ID);
	trCols.strVal = strAliasCols;
	
	string strAliasNames;
	strAliasNames.SetTokens(vsAliasNames, '|');
	//tr.AliasNames.strVal = strAliasNames;
	TreeNode trAliasNames = tree_check_get_node_by_dataid(tr, "AliasNames", EXT_WKS_DATA_ALIAS_NAMES_ID);
	trAliasNames.strVal = strAliasNames;

	return true;
}

bool ExtractWksDataAlias::SetTree(const TreeNode& tr)
{
	if(!tr)
		return false;
	
	vector<string> vsTempNames;
	TreeNode trCols = tree_get_node_by_id(tr, EXT_WKS_DATA_ALIAS_COLUMNS_ID);
	if(trCols)
	{
		vector<int> vnTempCols;
		string strVal = trCols.strVal;
		vector<string> vsCols;
		strVal.GetTokens(vsCols, '|');
		convert_string_vector_to_int_vector(vsCols, vnTempCols);
		
		vnCols = vnTempCols;
	}
	
	TreeNode trAliasNames = tree_get_node_by_id(tr, EXT_WKS_DATA_ALIAS_NAMES_ID);
	if(trAliasNames)
	{
		string strVal = trAliasNames.strVal;
		strVal.GetTokens(vsAliasNames, '|');
	}
	
	if(vsAliasNames.GetSize() > vnCols.GetSize())
		vsAliasNames.SetSize(vnCols.GetSize());
	else if(vsAliasNames.GetSize() < vnCols.GetSize())
		vnCols.SetSize(vsAliasNames.GetSize());

	return true;
}

bool ExtractWksDataCondition::GetTree(TreeNode& tr)
{
	if(!tr)
		return false;
	//tr.Reset();
	//
	//GETN_USE(tr)
	//GETN_STR(Condition, "Condition", strCondition)									GETN_ID(EXT_WKS_DATA_CONDITION_ID)
	//GETN_STR(BeforeLoop, "BeforeLoop", strBeforeLoop)								GETN_ID(EXT_WKS_DATA_BEFORELOOP_ID)
	//GETN_STR(BeforeIfCondition, "BeforeIfCondition", strBeforeIfCondition)			GETN_ID(EXT_WKS_DATA_BEFOREIFCONDITION_ID)
	//tr.Condition.strVal = strCondition;
	//tr.BeforeLoop.strVal = strBeforeLoop;
	//tr.BeforeIfCondition.strVal = strBeforeIfCondition;
	TreeNode trCondition = tree_check_get_node_by_dataid(tr, "Condition", EXT_WKS_DATA_CONDITION_ID);
	trCondition.strVal = strCondition;

	TreeNode trBeforeLoop = tree_check_get_node_by_dataid(tr, "BeforeLoop", EXT_WKS_DATA_BEFORELOOP_ID);
	trBeforeLoop.strVal = strBeforeLoop;

	TreeNode trBeforeIfCondition = tree_check_get_node_by_dataid(tr, "BeforeIfCondition", EXT_WKS_DATA_BEFOREIFCONDITION_ID);
	trBeforeIfCondition.strVal = strBeforeIfCondition;

	return true;
}
bool ExtractWksDataCondition::SetTree(const TreeNode& tr)
{
	if(!tr)
		return false;
	
	TreeNode trCondition = tree_get_node_by_id(tr, EXT_WKS_DATA_CONDITION_ID);
	if(trCondition)
		strCondition = trCondition.strVal;

	TreeNode trBeforeLoop = tree_get_node_by_id(tr, EXT_WKS_DATA_BEFORELOOP_ID);
	if(trBeforeLoop)
		strBeforeLoop = trBeforeLoop.strVal;

	TreeNode trBeforeIfCondition = tree_get_node_by_id(tr, EXT_WKS_DATA_BEFOREIFCONDITION_ID);
	if(trBeforeIfCondition)
		strBeforeIfCondition = trBeforeIfCondition.strVal;

	return true;
}

bool ExtractWksDataMethod::GetTree(TreeNode tr)
{
	if(!tr)
		return false;
	
	//tr.Reset();
	//
	//GETN_USE(tr)
	//GETN_NUM(Method, "Method", nMethod)								GETN_ID(EXT_WKS_DATA_METHOD_ID)
	//GETN_NUM(ColFilter, "ColFilter", nColFilter)					GETN_ID(EXT_WKS_DATA_COL_FILTER_ID)
	//GETN_STR(WksSpecified, "WksSpecified", strWksSpecified)			GETN_ID(EXT_WKS_DATA_WKS_SPECIFIED_ID)
	//GETN_NUM(ColFrom, "ColFrom", nColFrom)							GETN_ID(EXT_WKS_DATA_COL_FROM_ID)
	//GETN_NUM(ColTo, "ColTo", nColTo)								GETN_ID(EXT_WKS_DATA_COL_TO_ID)
	//GETN_NUM(Color, "Color", nColor)								GETN_ID(EXT_WKS_DATA_COLOR_ID)
	TreeNode trMethod = tree_check_get_node_by_dataid(tr, "Method", EXT_WKS_DATA_METHOD_ID);
	trMethod.nVal = nMethod;

	TreeNode trColFilter = tree_check_get_node_by_dataid(tr, "ColFilter", EXT_WKS_DATA_COL_FILTER_ID);
	trColFilter.nVal = nColFilter;

	TreeNode trWksSpecified = tree_check_get_node_by_dataid(tr, "WksSpecified", EXT_WKS_DATA_WKS_SPECIFIED_ID);
	trWksSpecified.strVal = strWksSpecified;

	TreeNode trColFrom = tree_check_get_node_by_dataid(tr, "ColFrom", EXT_WKS_DATA_COL_FROM_ID);
	trColFrom.nVal = nColFrom;

	TreeNode trColTo = tree_check_get_node_by_dataid(tr, "ColTo", EXT_WKS_DATA_COL_TO_ID);
	trColTo.nVal = nColTo;

	TreeNode trColor = tree_check_get_node_by_dataid(tr, "Color", EXT_WKS_DATA_COLOR_ID);
	trColor.nVal = nColor;

	return true;
}
	
bool ExtractWksDataMethod::SetTree(const TreeNode& tr)
{
	if(!tr)
		return false;
	TreeNode trMethod = tree_get_node_by_id(tr, EXT_WKS_DATA_METHOD_ID);
	if(trMethod)
		nMethod = trMethod.nVal;
	TreeNode trColFilter = tree_get_node_by_id(tr, EXT_WKS_DATA_COL_FILTER_ID);
	if(trColFilter)
		nColFilter = trColFilter.nVal;
	TreeNode trWksSpecified = tree_get_node_by_id(tr, EXT_WKS_DATA_WKS_SPECIFIED_ID);
	if(trWksSpecified)
		strWksSpecified = trWksSpecified.strVal;
	TreeNode trColFrom = tree_get_node_by_id(tr, EXT_WKS_DATA_COL_FROM_ID);
	if(trColFrom)
		nColFrom = trColFrom.nVal;
	TreeNode trColTo = tree_get_node_by_id(tr, EXT_WKS_DATA_COL_TO_ID);
	if(trColTo)
		nColTo = trColTo.nVal;
	TreeNode trColor = tree_get_node_by_id(tr, EXT_WKS_DATA_COLOR_ID);
	if(trColor)
		nColor = trColor.nVal;
	return true;
}

bool ExtractWksRowRange::GetTree(TreeNode& tr)
{
	if(!tr)
		return false;

	TreeNode trRowFrom = tree_check_get_node_by_dataid(tr, "RowFrom", EXT_WKS_DATA_ROW_RANGE_FROM_ID);
	trRowFrom.nVal = nRowFrom;
	
	TreeNode trRowTo = tree_check_get_node_by_dataid(tr, "RowTo", EXT_WKS_DATA_ROW_RANGE_TO_ID);
	trRowTo.nVal = nRowTo;

	return true;
}

bool ExtractWksRowRange::SetTree(const TreeNode& tr)
{
	if(!tr)
		return false;
	TreeNode trRowFrom = tree_get_node_by_id(tr, EXT_WKS_DATA_ROW_RANGE_FROM_ID);
	if(trRowFrom)
		nRowFrom = trRowFrom.nVal;
	
	TreeNode trRowTo = tree_get_node_by_id(tr, EXT_WKS_DATA_ROW_RANGE_TO_ID);
	if(trRowTo)
		nRowTo = trRowTo.nVal;
	return true;
}

///------ Folger 10/15/2010 ORG-1258 ADD_SELECT_OPTION_IN_WORKSHEET_QUERY
ExtractWksDataSettings::ExtractWksDataSettings()
{
	stRecalculate.nEnable = ENABLE;
}
///------ End ORG-1258 ADD_SELECT_OPTION_IN_WORKSHEET_QUERY

bool ExtractWksDataSettings::GetTree(TreeNode& tr)
{
	if(!tr)
		return false;
	//tr.Reset();
//
	//GETN_USE(tr)
	//
//
	//GETN_BEGIN_BRANCH(stAlias, "stAlias")					GETN_ID(EXT_WKS_DATA_ALIAS_BRANCH_ID)
		//stAlias.GetTree(_tmpSubNode);
	//GETN_END_BRANCH(stAlias)
//
	//GETN_BEGIN_BRANCH(stCondition, "stCondition")			GETN_ID(EXT_WKS_DATA_CONDITION_BRANCH_ID)
		//stCondition.GetTree(_tmpSubNode);
	//GETN_END_BRANCH(stCondition)
//
	//GETN_BEGIN_BRANCH(stMethod, "stMethod")					GETN_ID(EXT_WKS_DATA_METHOD_BRANCH_ID)
		//stMethod.GetTree(_tmpSubNode);
	//GETN_END_BRANCH(stMethod)
//
	//vector<int> vnTempCols;				// convert_int_vector_to_string_vector requires vector<int>
	//vnTempCols = vnCols;
	//vector<string> vsCols;
	//convert_int_vector_to_string_vector(vnTempCols, vsCols);
	//string strCols;
	//strCols.SetTokens(vsCols, '|');
	//GETN_STR(Cols, "Cols", strCols)							GETN_ID(EXT_WKS_DATA_COLUMNS_ID)
//
	//GETN_BEGIN_BRANCH(stRowRange, "stRowRange")				GETN_ID(EXT_WKS_DATA_ROW_RANGE_BRANCH_ID)
		//stRowRange.GetTree(_tmpSubNode);
	//GETN_END_BRANCH(stRowRange)
//
	TreeNode trAlias = tree_check_get_node_by_dataid(tr, "stAlias", EXT_WKS_DATA_ALIAS_BRANCH_ID);
	stAlias.GetTree(trAlias);

	TreeNode trCondition = tree_check_get_node_by_dataid(tr, "stCondition", EXT_WKS_DATA_CONDITION_BRANCH_ID);
	stCondition.GetTree(trCondition);

	TreeNode trMethod = tree_check_get_node_by_dataid(tr, "stMethod", EXT_WKS_DATA_METHOD_BRANCH_ID);
	stMethod.GetTree(trMethod);

	vector<int> vnTempCols;				// convert_int_vector_to_string_vector requires vector<int>
	vnTempCols = vnCols;
	vector<string> vsCols;
	convert_int_vector_to_string_vector(vnTempCols, vsCols);
	string strCols;
	strCols.SetTokens(vsCols, '|');
	TreeNode trCols = tree_check_get_node_by_dataid(tr, "Cols", EXT_WKS_DATA_COLUMNS_ID);
	trCols.strVal = strCols;

	TreeNode trRowRange = tree_check_get_node_by_dataid(tr, "stRowRange", EXT_WKS_DATA_ROW_RANGE_BRANCH_ID);
	stRowRange.GetTree(trRowRange);

	///Sophy 8/7/2009 v8.1088 EXTRACT_WKS_DATA_SAVE_RECALCULATE_MODE_TO_SOURCE_SHEET
	TreeNode trRecalMode = tree_check_get_node_by_dataid(tr, "RecalMode", EXT_WKS_DATA_RECAL_MODE_ID);
	///------ Folger 10/15/2010 ORG-1258 ADD_SELECT_OPTION_IN_WORKSHEET_QUERY
	//trRecalMode.nVal = nRecalMode;
	trRecalMode.nVal = stRecalculate.nMode;
	trRecalMode.Enable = stRecalculate.nEnable;
	///------ End ADD_SELECT_OPTION_IN_WORKSHEET_QUERY
	///end EXTRACT_WKS_DATA_SAVE_RECALCULATE_MODE_TO_SOURCE_SHEET
	return true;
}
bool ExtractWksDataSettings::SetTree(const TreeNode& tr)
{
	if(!tr)
		return false;

	TreeNode trAlias = tree_get_node_by_id(tr, EXT_WKS_DATA_ALIAS_BRANCH_ID);
	if(trAlias)
		stAlias.SetTree(trAlias);

	TreeNode trCondition = tree_get_node_by_id(tr, EXT_WKS_DATA_CONDITION_BRANCH_ID);
	if(trCondition)
		stCondition.SetTree(trCondition);

	TreeNode trMethod = tree_get_node_by_id(tr, EXT_WKS_DATA_METHOD_BRANCH_ID);
	if(trMethod)
		stMethod.SetTree(trMethod);

	TreeNode trCols = tree_get_node_by_id(tr, EXT_WKS_DATA_COLUMNS_ID);
	if(trCols)
	{
		vector<int> vnTempCols;
		string strVal = trCols.strVal;
		vector<string> vsCols;
		strVal.GetTokens(vsCols, '|');
		convert_string_vector_to_int_vector(vsCols, vnTempCols);

		vnCols = vnTempCols;
	}
	
	TreeNode trRowRange = tree_get_node_by_id(tr, EXT_WKS_DATA_ROW_RANGE_BRANCH_ID);
	if(trRowRange)
		stRowRange.SetTree(trRowRange);

	///Sophy 8/7/2009 v8.1088 EXTRACT_WKS_DATA_SAVE_RECALCULATE_MODE_TO_SOURCE_SHEET
	TreeNode trRecalMode = tree_get_node_by_id(tr, EXT_WKS_DATA_RECAL_MODE_ID);
	if ( trRecalMode )
	///------ Folger 10/15/2010 ORG-1258 ADD_SELECT_OPTION_IN_WORKSHEET_QUERY
		//nRecalMode = trRecalMode.nVal;
	{
		stRecalculate.nMode = trRecalMode.nVal;
		stRecalculate.nEnable = trRecalMode.Enable;
	}
	///------ End ADD_SELECT_OPTION_IN_WORKSHEET_QUERY
	///end EXTRACT_WKS_DATA_SAVE_RECALCULATE_MODE_TO_SOURCE_SHEET
	return true;
}



////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//#define REF_COL_ROW_SECTIONS(_vnColIndices_, _vnRowIndices_) \
	//const vector<uint>& _vnColIndices_ = m_settings.stAlias.vnCols; \
	//const vector<uint>& _vnRowIndices_ = m_settings.vnCols;
#define REF_COL_ROW_SECTIONS(_vnColIndices_, _vnRowIndices_) \
	const vector<uint>& _vnColIndices_ = m_settings.vnCols; \
	vector<uint>& _vnRowIndices_ = m_vnRowIndices;

void ExtractWksData::ScrollResultToView(Worksheet& wks)
{
	REF_COL_ROW_SECTIONS(vnColIndices, vnRowIndices)
	
	vector<uint> vuRowBegin, vuRowEnd, vuColBegin, vuColEnd;	
	
	int nRowRange = find_contiguous_range(vnRowIndices, vuRowBegin, vuRowEnd);
	if(nRowRange <= 0)
		return;
	
	int nColRange = find_contiguous_range(vnColIndices, vuColBegin, vuColEnd);
	if(nColRange <= 0)
		return;
	
	int r1 = vuRowBegin[0], r2 = vuRowEnd[0], c1 = vuColBegin[0], c2 = vuColEnd[0];
	
	ds_scroll_into_view(wks, r1, r2, c1, c2);
}

	
bool ExtractWksData::ShowSelection(Worksheet& wksSource)
{
	REF_COL_ROW_SECTIONS(vnColIndices, vnRowIndices)
		
	Grid gg;
	if(gg.Attach(wksSource))
	{
		// SetSelection require vector<int> reference, convert vector<uint> to vector<int>
		vector<int> vnRows, vnCols;
		vnRows = vnRowIndices;
		vnCols = vnColIndices;

		bool bClearSelection = ( vnRows.GetSize() <= 0 );
		//return gg.SetSelection(bClearSelection ? NULL : vnRows, bClearSelection ? NULL : vnCols); //==> runtime error
		if ( bClearSelection )
			return gg.SetSelection(NULL, NULL);
		else
			return gg.SetSelection(vnRows, vnCols);
	}
	return false;
}

bool ExtractWksData::ShowMask(Worksheet& wksSource)
{
	if( !ShowSelection(wksSource) )
		return false;
	
	return wksSource.LT_execute("mark -w1");
}

bool ExtractWksData::ShowColor(Worksheet& wksSource)
{
	REF_COL_ROW_SECTIONS(vnColIndices, vnRowIndices)
		
	vector<uint> vuRowBegin, vuRowEnd, vuColBegin, vuColEnd;
	DataRange dr;
	
	int nRowRange = find_contiguous_range(vnRowIndices, vuRowBegin, vuRowEnd);
	int nColRange = find_contiguous_range(vnColIndices, vuColBegin, vuColEnd);
	
	for (int ii=0; ii<nRowRange; ii++)
	{
		for (int jj=0; jj<nColRange; jj++)
		{
			dr.Add("X", wksSource, vuRowBegin[ii], vuColBegin[jj], vuRowEnd[ii], vuColEnd[jj]);
		}
	}
	
	if(!dr)
		return false;
	
	XFBase xf;
	//TreeNode trXF;
	if(!xf.Load("wcellcolor", LTXF_USE_FAST_ACCESS))
		return false;
	
	int nColor = okutil_ocolor_LT_color_convert(m_settings.stMethod.nColor, true);
	xf.SetArg("irng", dr);
	xf.SetArg("type", 0);
	xf.SetArg("color", nColor);
	
	int nErr;
	if ( xf.ExecuteLabTalk(NULL, NULL, NULL, 0, &nErr, 0) != 0 )
		return false;
	return true;
}

bool ExtractWksData::NewCol(Worksheet& wksSource, const int* pnC1)// = NULL
{
	REF_COL_ROW_SECTIONS(vnColIndices, vnRowIndices)

	Column colFilter;
	
	int& nColFilter = m_settings.stMethod.nColFilter;
	///---Sim 10-14-2009 FIX_WRONG_COLS_WHEN_RUN_EXTRACT_WKS_FROM_LT
	//if ( pnC1 )
	if ( pnC1 && *pnC1 > -1 )
	///---END FIX_WRONG_COLS_WHEN_RUN_EXTRACT_WKS_FROM_LT
		nColFilter = *pnC1;
	if ( nColFilter >= 0 )
	{
		colFilter.Attach(wksSource, nColFilter);
	}
	
	if ( !colFilter )
	{
		nColFilter = wksSource.AddCol();
		colFilter = wksSource.Columns(nColFilter);
		//colFilter.SetName("Filter", OCD_ENUM_NEXT);
		colFilter.SetLongName(_L("Filter"));
	}
	
	Dataset dsIndex(wksSource, nColFilter);
	if ( !dsIndex )
		return false;
	int nR1, nR2;
	wksSource.GetBounds(nR1, 0, nR2, -1);
	dsIndex.SetSize(nR2 + 1);
	dsIndex = 0;
	for( int ii = 0; ii < vnRowIndices.GetSize(); ii++ )
	{
		dsIndex[vnRowIndices[ii]] = 1;
	}
	
	return true;	
}

bool ExtractWksData::prepareBeforeSelectRows(	const Worksheet& wksSource, int& nRowFrom, int& nRowTo,
												string& strCondition, string& strBeforeLoop, string& strBeforeIfCondition)
{
	nRowFrom = m_settings.stRowRange.nRowFrom;
	nRowTo = m_settings.stRowRange.nRowTo;

	int nNumWksRows = wksSource.GetNumRows();
	if(nRowFrom < 0 || nRowFrom >= nNumWksRows)
		return false;
	if(nRowTo < nRowFrom || nRowTo >= nNumWksRows)
		///---Sim 10-13-2009 FIX_WRONG_ROWS_WHEN_RUN_EXTRACT_WKS_FROM_LT
		//nRowTo = nNumWksRows;
		nRowTo = nNumWksRows - 1;
		///---END FIX_WRONG_ROWS_WHEN_RUN_EXTRACT_WKS_FROM_LT

	if ( !m_settings.stCondition.strCondition.IsEmpty() )
	{
		if( !ocu_get_correct_LT_expression(m_settings.stCondition.strCondition, &strCondition) )
			return error_report("Error in convert input condition to correct LT expression");
	}

	string strVariabeDef = m_settings.stAlias.GetAliasLTScript();
	//if( strVariabeDef.IsEmpty() )
		//return error_report("Error in getting before looping script!");
	strBeforeLoop = strVariabeDef + m_settings.stCondition.strBeforeLoop;

	strBeforeIfCondition = m_settings.stCondition.strBeforeIfCondition;

	return true;
}

bool ExtractWksData::SelectRows(const Worksheet& wksSource)
{
	if(!m_dwDirtyBits)		// nothing to do
		return true;

	REF_COL_ROW_SECTIONS(vnColIndices, vnRowIndices)

	int nRowFrom, nRowTo;
	string strCondition, strBeforeLoop, strBeforeIfCondition;
	if(!prepareBeforeSelectRows(wksSource, nRowFrom, nRowTo, strCondition, strBeforeLoop, strBeforeIfCondition))
		return false;

	int nLastRowFrom = m_stLastExtRowRange.nRowFrom,
		nLastRowTo = m_stLastExtRowRange.nRowTo;

	bool bRet;
	//if((m_dwDirtyBits&(~DIRTY_ROW_RANGE)) || nLastRowFrom < 0)			// dirty settings, reselect all
	if ( DIRTY_NEED_RESEL_ROW & m_dwDirtyBits )
	{
		// reselect all row
		vnRowIndices.SetSize(0);
		int nRet = wksSource.SelectRows(strCondition, vnRowIndices, nRowFrom, nRowTo, -1, strBeforeLoop, strBeforeIfCondition);
		bRet = ( nRet >= 0 );
	}
	else
	if ( DIRTY_ROW_RANGE & m_dwDirtyBits )
	{
		if( nRowFrom > nLastRowTo || nRowTo < nLastRowFrom )
		{
			//vnRowIndices.SetSize(0);
			bRet = ( 0 <= wksSource.SelectRows(strCondition, vnRowIndices, nRowFrom, nRowTo, -1, strBeforeLoop, strBeforeIfCondition) );
		}
		else
		{
			bRet = true;
			vector<uint> vnIndices;
			
			// remove rows outside the new row range
			vector<int> vnIndicesToRemove;
			if ( nRowFrom > nLastRowFrom )
			{
				if( 0 < vnRowIndices.Find(vnIndices, nLastRowFrom, nRowFrom-1) )
					vnIndicesToRemove.Append(vnIndices);
			}
			if ( nRowTo < nLastRowTo )
			{
				if( 0 < vnRowIndices.Find(vnIndices, nRowTo+1, nLastRowTo) )
					vnIndicesToRemove.Append(vnIndices);
			}
			
			// select rows outside the old row range
			vector<uint> vnRowsToAdd;
			if( nRowFrom < nLastRowFrom )
			{
				if ( 0 <= wksSource.SelectRows(strCondition, vnIndices, nRowFrom, nLastRowFrom-1, -1, strBeforeLoop, strBeforeIfCondition) )
					vnRowsToAdd.Append(vnIndices);
				else
					bRet = false;
				
			}
			if( nRowTo > nLastRowTo )
			{
				if( 0 <= wksSource.SelectRows(strCondition, vnIndices, nLastRowTo+1, nRowTo, -1, strBeforeLoop, strBeforeIfCondition) )
					vnRowsToAdd.Append(vnIndices);
				else
					bRet = false;
			}

			if ( bRet )
			{
				if( vnIndicesToRemove.GetSize() > 0 )
					vnRowIndices.RemoveAt(vnIndicesToRemove);
				if ( vnRowsToAdd.GetSize() > 0 )
					vnRowIndices.Append(vnRowsToAdd);					
			}		
		}
		
	}
	
	if(bRet)
	{
		m_dwDirtyBits = 0;
		m_stLastExtRowRange.nRowFrom = nRowFrom;
		m_stLastExtRowRange.nRowTo = nRowTo;
	}
	else
	{
		ClearCache();
	}
	
	return bRet;
}

void ExtractWksData::setAlias(const ExtractWksDataAlias& stAliasSrc, ExtractWksDataAlias& stAliasDest)
{
	vector<uint> 	&vnColsSrc = stAliasSrc.vnCols,
					&vnColsDest = stAliasDest.vnCols;
	vector<string> 	&vsAliasNamesSrc = stAliasSrc.vsAliasNames,
					&vsAliasNamesDest = stAliasDest.vsAliasNames;
	
	bool bChanged = vnColsSrc.GetSize() != vnColsDest.GetSize();
	for( int ii = 0; !bChanged && ii < vnColsSrc.GetSize(); ii++ )
		bChanged = ( vnColsSrc[ii] != vnColsDest[ii] ) || ( 0 != vsAliasNamesSrc[ii].Compare(vsAliasNamesDest[ii]) );
	
	if(bChanged)
	{
		stAliasDest = stAliasSrc;
		m_dwDirtyBits |= DIRTY_VAR_DEF;
	}
}

void ExtractWksData::setCondition(const ExtractWksDataCondition& stConditionSrc, ExtractWksDataCondition& stConditionDest)
{
	bool bChanged = 0 != stConditionSrc.strCondition.Compare(stConditionDest.strCondition) || 
					0 != stConditionSrc.strBeforeLoop.Compare(stConditionDest.strBeforeLoop) ||
					0 != stConditionSrc.strBeforeIfCondition.Compare(stConditionDest.strBeforeIfCondition);
	if(bChanged)
	{
		m_dwDirtyBits |= DIRTY_CONDITION;
		stConditionDest = stConditionSrc;
	}
}

void ExtractWksData::setMethod(const ExtractWksDataMethod& stMethodSrc, ExtractWksDataMethod& stMethodDest)
{
	stMethodDest = stMethodSrc;
}

void ExtractWksData::setRowRange(const ExtractWksRowRange& stRowRangeSrc, ExtractWksRowRange& stRowRangeDest)
{
	if(stRowRangeSrc.nRowFrom != stRowRangeDest.nRowFrom || stRowRangeSrc.nRowTo != stRowRangeDest.nRowTo)
	{
		m_dwDirtyBits |= DIRTY_ROW_RANGE;
		stRowRangeDest = stRowRangeSrc;
	}
}

void ExtractWksData::SetSettings(const ExtractWksDataSettings& settings)
{
	setAlias(settings.stAlias, m_settings.stAlias);
	setCondition(settings.stCondition, m_settings.stCondition);
	setMethod(settings.stMethod, m_settings.stMethod);
	setRowRange(settings.stRowRange, m_settings.stRowRange);

	m_settings.vnCols = settings.vnCols;
}
void ExtractWksData::GetSettings(ExtractWksDataSettings& settings)
{
	settings = m_settings;
}

void	ExtractWksData::ClearCache()
{
	//ExtractWksDataSettings	m_settings;
	
	m_vnRowIndices.SetSize(0);
	m_dwDirtyBits = DIRTY_ALL;

	
	m_stLastExtRowRange.nRowFrom = -1;
	m_stLastExtRowRange.nRowTo = -1;
}

class SelfReplaceHelper
{
public:
	SelfReplaceHelper(bool bSelfReplaced, Worksheet& wksFrom, Worksheet& wksTo)
	{
		m_bSelfReplaced = bSelfReplaced;
		if ( m_bSelfReplaced )
		{
			if ( wksBuffer.CreateCopy(wksFrom, CREATE_HIDDEN, DCTRL_COPY_DATA) )
			{
				wksTo = wksFrom;
				wksFrom = wksBuffer;
			}		
		}
	}
	~SelfReplaceHelper()
	{
		if ( m_bSelfReplaced && wksBuffer )
			wksBuffer.Destroy();
	}

protected:
	bool m_bSelfReplaced;
	Worksheet wksBuffer;
};


///------ Folger 10/14/2010 ORG-1259-P1 EXTRACT_WKS_DATA_SHOULD_NOT_ACTIVE_OUTPUT_SHEET_WHEN_RECALCULATE
//bool ExtractWksData::Extract(Worksheet& wksSource, Worksheet& wksDestination/* = NULL */, int* pnC1/* = NULL */, int* pnC2/* = NULL */)
bool ExtractWksData::Extract(Worksheet& wksSource, Worksheet& wksDestination/* = NULL */, int* pnC1/* = NULL */, int* pnC2/* = NULL */, DWORD dwOptions/* = 0*/)
///------ End EXTRACT_WKS_DATA_SHOULD_NOT_ACTIVE_OUTPUT_SHEET_WHEN_RECALCULATE
{
	if ( !SelectRows(wksSource) )
		return false;
	
	REF_COL_ROW_SECTIONS(vnColIndices, vnRowIndices)
	
	bool	bRet;
	int nMethod = m_settings.stMethod.nMethod;
	///------ Folger 10/15/2010 ORG-1258 ADD_SELECT_OPTION_IN_WORKSHEET_QUERY
	if ( EXD_TEST_EX == nMethod )
		nMethod = EXD_TEST;
	///------ End ADD_SELECT_OPTION_IN_WORKSHEET_QUERY
	switch(nMethod)
	{
	case EXD_TEST:
		bRet = ShowSelection(wksSource);
		break;
	
	case EXD_MASK:
		bRet = ShowMask(wksSource);
		break;
		
	case EXD_ADD_ROW_INDEX:
		bRet = NewCol(wksSource, pnC1);
		if ( bRet )
		{
			if ( NULL != wksDestination )
				wksDestination = wksSource;
			if ( pnC1 )
				*pnC1 = m_settings.stMethod.nColFilter;
			if ( pnC2 )
				*pnC2 = *pnC1;
		}
		break;
	
	case EXD_REPLACE:
	case EXD_NEW_LAYER:
	case EXD_NEW_PAGE:
		Worksheet wksFrom(wksSource);
		Worksheet wksTo(wksDestination);
		string& strNew = m_settings.stMethod.strWksSpecified;
		
		if ( !wksTo )
		{
			switch(nMethod)
			{
			case EXD_REPLACE:
				/*
				if ( strNew.IsEmpty() )
				{
					wksTo = wksFrom;
				}
				else
				{
					///Folger 04/16/07 MODIFY_FUNCTION
					if ( !attach_or_create_sheet(wksTo, strNew, CREATE_VISIBLE|CREATE_LOAD_1ST_LAYER_ONLY) )
					{
						string strPage = Project.ActiveLayer().GetPage().GetName();
						strNew = "[" + strPage + "]" + strNew;
						attach_or_create_sheet(wksTo, strNew, CREATE_VISIBLE|CREATE_LOAD_1ST_LAYER_ONLY);
					}
					///End Folger 04/16/07 MODIFY_FUNCTION
				}
				*/
				get_dest_wks(wksTo, get_completed_book_sheet_name(strNew), wksFrom);
				
				break;
				
			case EXD_NEW_LAYER:
				int nLayer = wksFrom.GetPage().AddLayer();
				wksTo = wksFrom.GetPage().Layers(nLayer);
				if ( wksTo )
					wksTo.SetName(STR_EXTRACTED_FROM + wksFrom.GetName(), OCD_ENUM_NEXT );
				break;
			case EXD_NEW_PAGE:
				wksTo.Create();
				if ( wksTo )
					wksTo.GetPage().SetLongName(STR_EXTRACTED_FROM + okutil_make_book_sheet_string(wksFrom.GetPage().GetName(), wksFrom.GetName()));
				break;
			}
			
			if ( !wksTo )
			{
				ASSERT(FALSE);
				return false;
			}
		}
		
		bool bSelfReplaced = ( wks_get_book_sheet_name(wksFrom) == wks_get_book_sheet_name(wksTo) );
		SelfReplaceHelper srhelper(bSelfReplaced, wksFrom, wksTo);
		
		/*
		int nC1 = m_settings.stMethod.nColFrom;
		int nC2 = m_settings.stMethod.nColTo;
		if ( pnC1 )
			nC1 = *pnC1;
		if ( pnC2 )
			nC2 = *pnC2;
		
		if ( nC1 < 0 )
		{
			nC1 = wks_find_empty_column(wksTo);
			if ( nC1 < 0 )
				nC1 = wksTo.GetNumCols();
		}
		if ( nC1 < 0 )
		{
			nC1 = 0;
		}
		//Sim, always auto fit
		//if ( nC2 < 0 )
			nC2 = nC1 + vnColIndices.GetSize() - 1;
		*/
		int nC1, nC2;
		get_specified_col_index(nC1, nC2, m_settings, wksTo, pnC1, pnC2);

		///------ Folger 10/14/2010 ORG-1259-P1 EXTRACT_WKS_DATA_SHOULD_NOT_ACTIVE_OUTPUT_SHEET_WHEN_RECALCULATE
		//DWORD dwCntrl = DCTRL_COPY_MAKE_ACTIVATE | DCTRL_COPY_KEEP_SHEET_NAME;
		DWORD dwCntrl = DCTRL_COPY_KEEP_SHEET_NAME;
		O_SET_BIT(dwCntrl, DCTRL_COPY_MAKE_ACTIVATE, !O_QUERY_BOOL(dwOptions, EXTRACT_NOT_ACTIVE_OUTPUT_SHEET));
		///------ End EXTRACT_WKS_DATA_SHOULD_NOT_ACTIVE_OUTPUT_SHEET_WHEN_RECALCULATE
		bRet = wksFrom.Extract(wksTo, vnRowIndices, vnColIndices, dwCntrl, nC1, nC2);
		if ( bRet )
		{
			// clear existing setting in new wks
			if ( !bSelfReplaced )
			{
				Tree trEmpty;
				save_extract_settings_to_wks_storage(wksTo, trEmpty);
			}
			
			strNew = wks_get_book_sheet_name(wksTo); // update actual value
			
			if ( NULL != wksDestination )
				wksDestination = wksTo;
			if ( pnC1 )
				*pnC1 = nC1;
			if ( pnC2 )
				*pnC2 = nC2;
		}
		break;
	
	case EXD_COLOR:
		bRet = ShowColor(wksSource);
		break;
		
	default:
		bRet = false;
		break;
	}
	
	if(!bRet)
		return error_report("Fail to extract data!");
	
	///Jasmine 11/24/08 v978d QA80-12652 DATASHEET_SCROLL_RANGE_INTO_VIEW  
	if(EXD_TEST == nMethod || EXD_MASK == nMethod || EXD_ADD_ROW_INDEX == nMethod || EXD_COLOR == nMethod)
		ScrollResultToView(wksSource);
	///End DATASHEET_SCROLL_RANGE_INTO_VIEW
	
	return true;
}

int ExtractWksData::GetNumRows()
{
	REF_COL_ROW_SECTIONS(vnColIndices, vnRowIndices)

	return vnRowIndices.GetSize();	
}


/////////////////////////////////////////////////////////////////////////////////////////
// utilities function
/////////////////////////////////////////////////////////////////////////////////////////
#define	STR_WKS_EXD_SETTINGS		"ExtractDataSettting"

bool save_extract_settings_to_wks_storage(Worksheet &wks, const TreeNode& tr)
{
	if ( !wks || !tr )
		return false;
	
	return wks.PutBinaryStorage(STR_WKS_EXD_SETTINGS, tr);
	
}
bool load_extract_settings_to_wks_storage(const Worksheet &wks, TreeNode& tr)
{
	if ( !wks || !tr )
		return false;
	
	return ( wks.GetBinaryStorage(STR_WKS_EXD_SETTINGS, tr) && !tr.IsEmpty() );
}

string get_completed_book_sheet_name(LPCSTR lpcszSpecifiedWksName)
{
	string strBooksheet = lpcszSpecifiedWksName;
	if ( !strBooksheet.IsEmpty() )
	{
		string strBook, strSheet;
		if( !get_book_sheet_names(strBooksheet, strBook, strSheet) )
		{
			strBook = Project.Pages().GetName();
			strBooksheet = make_book_sheet_name(strBook, strBooksheet);
		}
	}
	
	return strBooksheet;
}

bool get_dest_wks(Worksheet &wksDest, LPCSTR lpcszSpecifiedWksName, const Worksheet &wksSrc)
{
	//string strBookSheet = _get_completed_book_sheet_name(lpcszSpecifiedWksName);
	string strBookSheet = lpcszSpecifiedWksName;
	if ( strBookSheet.IsEmpty() )
	{
		wksDest = wksSrc;
		return true;
	}
	
	return attach_or_create_sheet(wksDest, strBookSheet, CREATE_VISIBLE|CREATE_LOAD_1ST_LAYER_ONLY);
}

void get_specified_col_index(int &nC1, int &nC2, const ExtractWksDataSettings& settings, const Worksheet &wks, const int *pnC1, const int *pnC2) // = NULL, NULL
{
	nC1 = settings.stMethod.nColFrom;
	nC2 = settings.stMethod.nColTo;
	///---Sim 10-14-2009 FIX_WRONG_COLS_WHEN_RUN_EXTRACT_WKS_FROM_LT
	//if ( pnC1 )
	if ( pnC1 && *pnC1 > -1 )
		nC1 = *pnC1;
	//if ( pnC2 )
	if ( pnC2 && *pnC2 > -1 )
		nC2 = *pnC2;
	///---END FIX_WRONG_COLS_WHEN_RUN_EXTRACT_WKS_FROM_LT
	
	if ( nC1 < 0 && wks )
	{
		nC1 = wks_find_empty_column(wks);
		if ( nC1 < 0 )
			nC1 = wks.GetNumCols();
	}
	if ( nC1 < 0 )
	{
		nC1 = 0;
	}
	//Sim, always auto fit
	//if ( nC2 < 0 )
		nC2 = nC1 + settings.vnCols.GetSize() - 1;
}