#include <origin.h>
#include <GetNBox.h>
#include <xfutils.h>
//put additional include files here
#include <..\originlab\xfunctionex.h>

//put your own support static functions here
#define STR_FILE_EXT	".wiki"
#define STR_UPLOAD_FILE_LIST_NAME "Upload_FILELIST.txt"
#define STR_WIKI_TITLE_HEADER "{{DISPLAYTITLE:X-Function:%s}}\n\n[[category:P0]]\n"
#define STR_WIKI_FIRST_PART_FORMAT "== Menu Information ==\n%s\n\n== Brief Information ==\n%s%s\n%s\n"
#define STR_WIKI_END_PART_FORMAT "\n== Related X-Functions ==\n%s\n\n[[category:%s]]"
#define STR_VAR_TABLE_HEADER "\n== Variables ==\n\n{| class=\"xfvar\" \n!width=\"8%\"|Display<br>Name\n!width=\"8%\"|Variable<br>Name\n!width=\"8%\"|I/O<br>and<br>Type\n!width=\"8%\"|Default<br>Value\n!Description\n"
#define STR_VAR_ROW_FORMAT "|-\n|%s\n|%s\n|\n%s\n| <center>%s</center>\n| %s\n"
#define STR_COMBOLIST_FORMAT "*\'\'%s\'\'\n*:%s\n"
#define STR_RELATED_XF_LINK_FORMAT "[[X-Function:%s|%s]]"
#define STR_WIKI_MID_START "== Description"
#define STR_WIKI_MID_END "== Related"
#define STR_WIKI_NEW_CONTENTS "== Description ==\n\n\n== Algorithm ==\n\n\n== References ==\n\n\n"
#define STR_WIKI_ADD_INFO	"\n\n== Additional Information ==\n"
//#define STR_WIKI_NON_XF_DLG	"You can open the dialog with it's name in scrpt,but you can not run it in Labtalk for other purpose."
#define STR_WIKI_NON_XF_DLG	"It is not accessible from script."
#define STR_WIKI_NO_DLG	"X-Function not designed for Auto GetN Dialog."
#define STR_WIKI_NON_LABTALK	"It is not accessible from script."
#define STR_WIKI_PRO_ONLY	"This feature is for OriginPro only."
#define STR_WIKI_OVER_REQ	"Minimum Origin Version Required:"

enum{
	TYPE_NORMAL,
	TYPE_NON_XF_DLG,
	TYPE_NO_DLG,
	TYPE_NON_LABTALK = 101
};

string strCOmbolistHeader[3] = {"\n\nOption list:\n", "\n\nOption list:\n","\n\nOption list:\n"};


class XFWiki : public XFunction
{
public:
	XFWiki(LPCSTR strXFName, int nLang = 1, BOOL bNew = FALSE);
public:
	BOOL UpdateWikiFile(LPCSTR strDestFolder);
private:
	int GetVarTable(string &str);
	string Generate_Label(string strName);
private:
	string 	m_strXFName;
	int		m_nLang;
	int 	m_mType;
	BOOL		m_bNew;
	string	m_strPT;
};


XFWiki::XFWiki(LPCSTR strXFName, int nLang, BOOL bNew)
{
	m_strXFName = strXFName;
	m_nLang = nLang;
	m_bNew = bNew;
}	


BOOL XFWiki::UpdateWikiFile(LPCSTR strDestFolder)
{
	string strMenu, strBrief, strAddInfo, strUsage, strRelatedXF, strVars, strVarTable, strCat, strWiki1, strWiki2, strTemp, strWiki;
	if(okutil_find_file_from_map(&strTemp, SUPPORTFILE_XF, ORIGIN_PATH_UNDEF, m_strXFName, &strCat) == ORIGIN_PATH_UNDEF)
		return out_str("Cannot Find X-Function: "+m_strXFName);
	
	m_strXFName = GetFileName(strTemp, true);

	if(!Load(NULL, m_strXFName, 0, true, false, true))
	{
		out_str("Invalid XF Name "+m_strXFName);
		return false;
	}

//	m_strXFName = GetFunctionName();
	CheckMakePath(strDestFolder);
	strTemp = strDestFolder;
	string strFileName = m_strXFName;
	strFileName.Replace(' ', '_');
	strFileName = strTemp + strFileName + STR_FILE_EXT;
	
	strBrief = GetHelpText(IDV_HELP_DESCRIPTION, m_nLang);
	strUsage = GetHelpText(IDXF_SYNTAX, m_nLang);
//	strCat = GetHelpText(IDV_CATEGORY, m_nLang);
//	strRelatedXF = GetHelpText(IDV_HELP_RELATED_XF, m_nLang);
	TreeNode trXF = GetTree();
	TreeNode trInfo = trXF.category;
	if(trInfo)
	{
		strCat = trInfo.strVal;
	}
	strCat = strCat.Right(strCat.GetLength() - strCat.ReverseFind('\\') - 1);
	trInfo = trXF.relatedXF;
	if(trInfo)
	{
		strRelatedXF = trInfo.strVal;
	}
	StringArray saXFs;
	strRelatedXF.GetTokens(saXFs, ',');
	string strTemp2;
	for ( int ii = 0; ii < saXFs.GetSize(); ii++ )
	{
		strTemp = saXFs[ii];
		strTemp.TrimRight();
		strTemp.TrimLeft();
		
		if(okutil_find_file_from_map(&strTemp2, SUPPORTFILE_XF, ORIGIN_PATH_UNDEF, strTemp) == ORIGIN_PATH_UNDEF)
			1;
			//out_str("////BEGIN TRACE\nCannot Find related X-Function: "+strTemp+"\n////END TRACE\n");
		
		strTemp = GetFileName(strTemp2, true);

		strTemp.Format(STR_RELATED_XF_LINK_FORMAT, strTemp, strTemp);
		if ( ii == 0 )
			saXFs[ii] = strTemp;
		else
			saXFs[ii] = " " + strTemp;	
	}
	strRelatedXF.SetTokens(saXFs, ',');
//	if ( m_strXFName[0] <= 'z' && m_strXFName[0] >= 'a' )
//	{
//		strWiki1.Format(STR_WIKI_TITLE_HEADER, m_strXFName);	
//	}
	strWiki1.Format(STR_WIKI_TITLE_HEADER, m_strXFName);	
	strUsage.Replace("\n", "\n\n");
	
	//Echo === "Re: SR2 documentation plan " Tue 4/15/2008 3:06 PM
	if ( 1 != trXF.UsageCtxt.LabTalk.nVal)
	{
		m_mType = TYPE_NON_LABTALK;
	}
	
	strAddInfo = STR_WIKI_ADD_INFO;
	strAddInfo += STR_WIKI_OVER_REQ + "\n";
	
	int nVarCount = GetVarTable(strVarTable);
	if(0 == nVarCount){
		/*	
			Non-XF dialog such as mproperty, 
			Add an line in Additional Infomaton table, "You can open the dialog with it's name in scrpt,but you can not run it in Labtalk for other purpose."
 
			Condition to find these x-function: No variables. That is, such x-function has no any input/output variables. For example, when you open mproperty in X-Funciton builder, you will see nothing in Variable pane. 
		*/
		strAddInfo += STR_WIKI_NON_XF_DLG + "\n";
		m_mType = TYPE_NON_XF_DLG;
	}
	else if ( 1 == trXF.UsageCtxt.LabTalk.nVal )
	{
		if( 0 == trXF.UsageCtxt.mainmenu.GetN.nVal && nVarCount > 0){
			/*	
				XF has no dialog such as cd and lx
				Add an line in Additional Infomation table, "X-Function not designed for Auto GetN Dialog"
 
				Condition to find these x-function: In TreeView,  Labtalk is checked,  Auto GetN Dialog is set as None and it has at least 1 variables.
			*/
			strAddInfo += STR_WIKI_NO_DLG + "\n";
			m_mType = TYPE_NO_DLG;
		}
		else{
			// Normal case
			m_mType = TYPE_NORMAL;
		}
	}
	else
	{
		/* 	
			XF can not be run in Labtalk such as MR
			Move the line from Command Line Usage table to Additional Information table, "It is not accessible from script"
		*/
		strAddInfo += STR_WIKI_NON_LABTALK + "\n";
		m_mType = TYPE_NON_LABTALK;
		
	}
	
	// Pro Version Information
	if( "Pro" == trXF.module.strVal)
	{
		strAddInfo += " " + STR_WIKI_PRO_ONLY + "\n";
	}
	
	int nPos = strBrief.Find(":");
	//if(nPos>=0 && nPos<20){	// bug
	if(nPos>=0){
		strMenu = strBrief.Left(nPos);
		strBrief = strBrief.Right(strlen(strBrief)-nPos-1);
		
		strMenu.Replace("&", "");
	}
	strBrief.TrimLeft();
	
	if(TYPE_NON_LABTALK != m_mType)
		strUsage = "\n== Command Line Usage ==\n" + "<code>\n\n"+strUsage+"\n\n</code>";
	else
		strUsage = "";
	strTemp.Format(STR_WIKI_FIRST_PART_FORMAT, strMenu, strBrief, strAddInfo, strUsage);
	
	strWiki1 += m_strPT;
	if( TYPE_NON_XF_DLG == m_mType)
		strWiki1 +=strTemp;
	else if(TYPE_NON_LABTALK == m_mType)
	{
		strWiki1 += strTemp + "== Variables ==\n{| class=\"dialogcontroltable\n\n\n|}\n";
	}
	else
		strWiki1 +=strTemp + strVarTable;
	
	strWiki2.Format(STR_WIKI_END_PART_FORMAT, strRelatedXF, strCat);
	//out_str(strWiki1);
	//out_str(strWiki2);
	stdioFile  fwiki;
	BOOL bNotStart = true;
	if ( strFileName.IsFile() )
	{
		if ( fwiki.Open(strFileName, file::modeRead | file::shareDenyWrite  ) )
		{
			while(fwiki.ReadString(strTemp))
			{
				if ( strTemp.Find(STR_WIKI_MID_START) !=  0 && bNotStart) 
					continue;
				else
					bNotStart = false;
				if (  strTemp.Find(STR_WIKI_MID_END) == 0 || strTemp.Find("[[category") >= 0 || strTemp.Find("[[Category") >= 0 )
					break;
				strTemp.Replace("&nbsp;", "");
				strWiki += strTemp+"\n";
				//strWiki.Replace("&nbsp;", "");
			}
			fwiki.Close();
		}
		else
			out_str("Failed to open "+strFileName);
	}
	else
		strWiki = STR_WIKI_NEW_CONTENTS;
		
	if ( fwiki.Open(strFileName, file::modeWrite | file::modeCreate  ) )
	{
		strWiki = strWiki1 + strWiki + strWiki2;
		strWiki.Replace("&nbsp;", "");
		//out_str(strWiki);
		fwiki.WriteString(strWiki);
		fwiki.Close();
	}
	else
		out_str("Failed to write "+strFileName);
	return true;
}

string XFWiki::Generate_Label(string strName)
{
	int ii;
	ii = strName.Find("iy")*strName.Find("y")*strName.Find("iz")*strName.Find("z")*strName.Find("ix")*strName.Find("x")*strName.Find("irng")*strName.Find("rng");
	if (0==ii)
		return "Input";
	ii = strName.Find("oy")*strName.Find("oz")*strName.Find("ox")*strName.Find("orng");
	if (0==ii)
		return "Output";
	ii = strName.Find("im")*strName.Find("ims")*strName.Find("iml")*strName.Find("imp");
	if (0==ii)
		return "Input Matrix";
	ii = strName.Find("om")*strName.Find("oms")*strName.Find("oml")*strName.Find("omp");
	if (0==ii)
		return "Output Matrix";
	ii = strName.Find("m")*strName.Find("ms")*strName.Find("ml")*strName.Find("mp");
	if (0==ii)
		return "Matrix";
	ii = strName.Find("iw")*strName.Find("iwp");
	if (0==ii)
		return "Input Worksheet";
	ii = strName.Find("ow")*strName.Find("owp");
	if (0==ii)
		return "Output Worksheet";
	ii = strName.Find("w")*strName.Find("wp");
	if (0==ii)
		return "Worksheet";
	if (0==strName.Find("img"))
		return "Input Image";
	if (0==strName.Find("oimg"))
		return "Output Image";
	ii = strName.Find("igl")*strName.Find("igp");
	if (0==ii)
		return "Input Graph";
	ii = strName.Find("ogl")*strName.Find("ogp");
	if (0==ii)
		return "Output Graph";
	ii = strName.Find("gl")*strName.Find("gp");
	if (0==ii)
		return "Graph";
	if (0==strName.Find("icol"))
		return "Input Column";
	if (0==strName.Find("ocol"))
		return "Output Column";
	if (0==strName.Find("col"))
		return "Column";
	if (0==strName.Find("ipg"))
		return "Input Page";
	if (0==strName.Find("opg"))
		return "Output Page";
	if (0==strName.Find("pg"))
		return "Page";
	return "";
}


int XFWiki::GetVarTable(string &strVarTable)
{
	vector<string> vsVarNames, vsVarDefaultVals, vsVarTypes;
	vector<int> vnIO;
	Tree trRuntime;
	TreeNode trVarTreeNodes = trRuntime.AddNode("TreeNode_Details");
	TreeNode trVars, trVhelp;
	TreeNode trTemp = GetTree();
	okutil_xft_GetVarsNode(&trVars, &trTemp, NULL);
	string strIOType[3] = {"Input", "Output", "Input/Output"};
	

	int nTrees = GetVariables(vsVarNames, vsVarDefaultVals, vsVarTypes, false, vnIO, trVarTreeNodes, XF_GET_SIMPLE_DEFAULT_VALUE);
	
	string strDescription, strLabel, strCombo, strTemp;;
	int nIndex = 0;
	vector<string> vsComboList, vsComboDesc;
	
	strVarTable = STR_VAR_TABLE_HEADER;
	foreach(TreeNode trV in trVars.Children)
	{
//		if(octree_find_node(&trV, &trVhelp, STR_DATAID_ATTRIB, IDV_VAR_LOCAL_HELP_BRANCH, false, 0, m_nLang))
		trVhelp = trV.help;
		if ( trVhelp )
		{
			//TreeNode trDesc = tree_find_node_by_dataID(trVhelp, IDV_VAR_HELP_DESCRIPTION, IDV_VAR_LOCAL_HELP_BRANCH, m_nLang);
			TreeNode trDesc = trVhelp.remark;
			strDescription = trDesc.strVal;
			//GetVarLabel(vsVarNames[nIndex], strLabel, m_nLang);
			strLabel = trVhelp.description.strVal;
			if ( strLabel.IsEmpty() )
			//strLabel = "Input";	
			{
				strLabel = Generate_Label(trV.name.strVal);
			}
			
			strCombo = trV.comboString.strVal;
			strCombo.TrimLeft();
			if ( !strCombo.IsEmpty() )
			{
				string strTmp = strCombo;
				strTmp.MakeLower();
				if (strTmp.Find('|')>0 && strTmp!="0|1" && strTmp.Find("slider:")!=0)
				{
					strCombo.GetTokens(vsComboList, '|');
					vsComboDesc.SetSize(0);
					TreeNode trComboDesc = trVhelp.comboDescription;
					try
					{
						vsComboDesc=trComboDesc.strVals;
					}
					catch(int nError)
					{
						out_int("_get_combolist_text err = ", nError);
					}
					strCombo = strCOmbolistHeader[m_nLang-1];
					int nComboSize = vsComboList.GetSize();
					
					if(nComboSize > 0 && vsComboList[0].Left(6) == "Radio:")
						vsComboList[0] = vsComboList[0].Right(strlen(vsComboList[0])-6);
					
					for (int nn = 0; nn < nComboSize; nn++ )
					{
						strTemp = vsComboDesc[nn];
						//out_str(strTemp);
						strTemp.TrimLeft();
						strTemp.Replace("\r", "\n\n:");
						//out_str(strTemp);		
						
						strTemp.Format(STR_COMBOLIST_FORMAT, vsComboList[nn], strTemp);	
						strCombo += strTemp;
					}
				}
				else
					strCombo = "";
			}
			strDescription += strCombo;
			if(nIndex < vsVarDefaultVals.GetSize() )
			{
				if (vsVarDefaultVals[nIndex]=="")
					vsVarDefaultVals[nIndex] = "&nbsp;";
				strTemp.Format(STR_VAR_ROW_FORMAT, strLabel, vsVarNames[nIndex], strIOType[vnIO[nIndex]]+"\n\n"+vsVarTypes[nIndex], vsVarDefaultVals[nIndex], strDescription);
				//out_str(strTemp);
				strVarTable += strTemp;
			}
		}
		else
			out_str("error to get trLang"+m_strXFName);
		nIndex++;
	}
	strVarTable += "\n|}\n\n";
	//out_str(strVarTable);
	return nIndex;
}



void xf2wiki(const string& xfname, const string& category, const string& path)
{
	XFWiki myWiki(xfname);
	myWiki.UpdateWikiFile(path);
}

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

}

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