/*------------------------------------------------------------------------------*
 * File Name: Loose Dataset Editor	 											*
 * Creation: CPY 07/01/2005														*
 * Purpose: Loose Dataset viewing and deleting									*
 * Copyright (c) Originlab Corp.	2005, 2006, 2007, 2008, 2009, 2010			*
 * All Rights Reserved															*
 * 																				*
 * Modification Log:															*
 *------------------------------------------------------------------------------*/
 
#include <Origin.h>
#include "DialogEx.h"
#define BASE_WINDOW ResizeDialog
#include "TreeEditEvents.h"

#define STR_LD_EDIT_DLG_NAME						"LooseDatasetEditor"
#define STR_SEPERATE_OF_DATASET_PLOT_INFO			", "

//enum {LDE_NAME, LDE_SIZE, LDE_TYPE};
enum {LDE_NAME, LDE_SIZE, LDE_TYPE, LDE_PLOT_INFO};
	
class LooseDatasetEditDlg;
static LooseDatasetEditDlg* s_pLooseDatasetEditDlg;

class LooseDatasetEditDlg : public TreeEditDlg
{
public:
	LooseDatasetEditDlg(BOOL bDeleteOnDestroy = true) : TreeEditDlg(IDD_RESIZE_GRID, "ODlg8" )
	{
		m_bDeleteOnDestroy = bDeleteOnDestroy;
		vector<uint> vnTemp = {IDCANCEL, IDC_RG_BUTTON1, 0};
		m_vnButtons = vnTemp;
		//enum {LDE_NAME, LDE_SIZE, LDE_TYPE};
		//vector<string> vnTitles = {"Name", "Size", "Type"};
		//enum {LDE_NAME, LDE_SIZE, LDE_TYPE, LDE_PLOT_INFO};
		vector<string> vnTitles = {"Name", "Size", "Type", "Plot Info"};
		m_vsColTitles = vnTitles;
	}
	DWORD	DoModalEx(HWND hParent)
	{
		InitMsgMap();// will be called from internal later
		int nRet = DoModal(hParent);
		if(IDOK == nRet)
		{
			return 1;
		}
		return 0;
	}
	virtual int  Create(HWND hParent = NULL)
	{
		InitMsgMap();
		//Launch the modeless dialog
		int nRet = TreeEditDlg::Create(hParent);
		
		return nRet;
	}
	void BeforeUpdate()
	{
		m_treeEditCntrl.SetReady(false);
	}
	void AfterUpdate(bool bResizeCols = true)
	{
		if(bResizeCols)
		{
			SetColAlignments();
			m_treeEditCntrl.ResizeCols(0, 3, 7);
		}
		m_treeEditCntrl.SetReady(true);
	}
	void SetDirectUpdate()
	{
		m_treeEditCntrl.SetRedraw(flexRDDirect);
	}
	void ResetRows()
	{
		m_treeEditCntrl.SetRows(0, true);
	}
	bool SetColumn(int nCol, const vector<string>& vsVals)
	{
		return m_treeEditCntrl.SetColValues(nCol, vsVals, 0, true);
	}
	bool SetColHeading(int nCol, LPCSTR lpcsz)
	{
		return m_treeEditCntrl.SetColHeading(nCol, lpcsz, true);
	}
	void SetColAlignments()
	{
		m_treeEditCntrl.SetFixedColAlignment(-1, flexAlignCenterCenter);
		m_treeEditCntrl.SetColAlignment(-1, flexAlignLeftCenter);//flexAlignGeneral);
	}
	/*
	void Reset()
	{
		BeforeUpdate();
		m_treeEditCntrl.SetupRowsCols(1);
		ResetRows();
		AfterUpdate(false);
	}
	*/

	void Update(LPCSTR lpcszMsg = NULL)
	{
		if(lpcszMsg) // debug message
			printf("dialog update from %s\n", lpcszMsg);
		
		BeforeUpdate();
		ResetRows();
		loadDatasets();
		AfterUpdate(false);
	}
protected:
	
	EVENTS_BEGIN
		ON_INIT( OnInitDialog )
		ON_READY(OnReady)
		ON_DESTROY(OnDestroy)
		ON_SIZE(OnDlgResize)		
		//ON_GETNDLG_MSGS(IDC_GRID)		
		//ON_GRID_ROW_COL_CHANGE(IDC_GRID, OnRowColChange)
		//ON_GRID_BEFORE_MOUSE_DOWN(IDC_GRID, OnBeforeMouseDown)
		ON_GRID_SEL_CHANGE(IDC_GRID, OnSelsChange)
		
		ON_SYSCOMMAND(OnSystemCommand)

		ON_BN_CLICKED(IDC_RG_BUTTON1, OnDelete)
	
		ON_ORIGIN_MSG(SN_LOOSE_DATASET_CHANGE, OnLooseDatasetChange)
	EVENTS_END
	
protected:
	BOOL OnInitDialog()
	{
		ResizeDialog::OnInitDialog(0, STR_LD_EDIT_DLG_NAME);
		// move grid to top left
		SetControlGap(4);
		m_treeEditCntrl.Init(IDC_GRID, false, true, NULL, *this);
		m_treeEditCntrl.SetGridLines(flexGridInset);//flexGridInsetVert);
		//uint dwColor = RGB(215, 225, 225);
		//m_treeEditCntrl.SetAlternateRowColors(dwColor);
		//m_bnDelete		= GetItem(IDC_RG_BUTTON1);		
		m_wndDlg.Text = STR_LD_EDIT_DLG_NAME;		
		m_treeEditCntrl.SetExplorerBar(flexExSortShow);
		m_treeEditCntrl.SetAllowSelection(true);	///If false , support single selete; else multi seletion
		m_treeEditCntrl.SetSelection( flexSelectionListBox );
		m_treeEditCntrl.SetEditable( );
		return TRUE;
	}
	// this is after dialog is moved into last remembered position/size
	// so a better place to properly position and show controls
	BOOL OnReady()
	{
		PositionControl(IDC_GRID, 3, 3);
		//IDD_RESIZE_GRID is a generic dialog for many purpose, it has two checks (hidden) and 3 buttons (only Cancel visible)
		for(int ii = 0; ii < m_vnButtons.GetSize(); ii++)
		{
			Control cc = GetItem(m_vnButtons[ii]);
			if(cc)
				cc.Visible = true;
		}
		InitButtons();
		updateButtonState(false);
		//---- init grid
		m_treeEditCntrl.SetupRowsCols(1);
		for(ii = 0; ii < m_vsColTitles.GetSize(); ii++)
			SetColHeading(ii, m_vsColTitles[ii]);
		//----
		Update();
		SetInitReady();
		return true;
	}
	BOOL OnDestroy(void)
	{
		TreeEditDlg::OnDestroy();
		if(m_bDeleteOnDestroy)
		{
			delete this;
			s_pLooseDatasetEditDlg = NULL;
		}
		return true;
	}
	BOOL	OnLooseDatasetChange(int wParam, int lParam)
	{
		Update();
		//out_int("dialog OnLooseDatasetChange", wParam);
		return true;
	}
	BOOL OnDlgResize(int nType, int cx, int cy)
	{
		if(!IsInitReady())
			return TRUE;

		ArrangeMainItemAndControls(m_vnButtons, IDC_GRID, NULL, true);
		return TRUE;
	}	
	bool 	OnDelete(Control ctrl)
	{
		vector<string> vsSels;
		if(!m_treeEditCntrl.GetSelItems(LDE_NAME, vsSels))
			return false;
		
		for(int nSelIndex = 0; nSelIndex < vsSels.GetSize(); nSelIndex++)
		{
			//m_treeEditCntrl.DeleteRow(vnRows[nSelIndex]);
			deleteDataset(vsSels[nSelIndex]);
		}
		
		//updateButtonState(false);
		Update(); // somehow this is still needed as del message not always come in in time
		return true;		
	}
	
	void OnSelsChange(Control cntrl)
	{
		if(m_treeEditCntrl.IsReady())
		{
			//printf("m_bReady and OnPageSelChange\n");
			//vector<string> vsSelPages;
			vector<uint>	vnSels;
			if(m_treeEditCntrl.GetSelRows(vnSels) && vnSels.GetSize() > 0)
				updateButtonState(true);
			else
				updateButtonState(false);
		}
	}
	/*
	void OnRowColChange(Control cntrl)
	{
		return;
		
		if(!IsInitReady())
			return;
		TreeEditDlg::OnRowColChange(cntrl);
	}	
	void OnBeforeMouseDown(Control flxControl, short nButton, short nShift, float X, float Y, BOOL* pCancel) // listCols arg not used for now, maybe needed later
	{
		int nRow, nCol, nx, ny;
		bool bIsInsideGrid = m_treeEditCntrl.GetMousePixel(X, Y, nRow, nCol, nx, ny);
		
		if(m_treeEditCntrl.CheckSelRow(nRow, false))
		{
			*pCancel= TRUE;
			if(nRow < 0)
				updateButtonState( IDC_RG_BUTTON1, false);
			else
				updateButtonState( IDC_RG_BUTTON1, true);				
		}
	}
	*/
protected:
	//CPY the following is not needed and causing runtime erro
	/*
	bool GetSelItems(vector<string>& vsWksNames, vector<uint> &vnRows)
	{
		//vector<uint> vnRows;
		vsWksNames.SetSize(0);
		string strDatasetName, strLongName;
		string strItemType;
		if(m_treeEditCntrl.GetSelRows(vnRows))
		{
			vnRows.Sort(SORT_DESCENDING);
			//for(int ii = 1; ii < vnRows.GetSize(); ii++)
			for(int ii = 0; ii < vnRows.GetSize(); ii++)
			{
				//strDatasetName = m_treeEditCntrl.GetCell(vnRows[ii], 0);
				strDatasetName = m_treeEditCntrl.GetCell(vnRows[ii], LDE_NAME);
				if(strDatasetName.IsEmpty())
					strDatasetName = strLongName.MakeValidCName();
				
				vsWksNames.Add(strDatasetName);
			}
			return true;
		}
		return false;
	}
	*/
private:
	bool deleteDataset(LPCSTR lpcszName)
	{
		string strLT ;
		//---- CPY QA70-7860 7/6/05 DEL_S_ALLOW_NOT_DEL_DEPEND_OWNERS
		//strLT.Format("delete %s",lpcszName);
		strLT.Format("del -SD %s",lpcszName);// del without del of linked datasets
		//---
		return LT_execute(strLT);
	}
	// this will need to be moved to VC later, so separate it out
	int getLooseDatasets(vector<string>& vsNames)
	{
		//foreach(string strName in Project.DatasetNames) //just for test
		foreach(string strName in Project.LooseDatasetNames)
		{
			vsNames.Add(strName);
		}
		return vsNames.GetSize();
	}
	// this should really be a vc function or at least a global function
	string getDataTypeName(int nType)
	{
		string str;
		switch(nType)
		{
		case FSI_DOUBLE:
			str = "Double";
			break;
		case FSI_REAL:
			str = "Float";
			break;
		case FSI_SHORT:
			str = "Integer";
			break;
		case FSI_LONG:
			str = "Long";
			break;
		case FSI_CHAR:
			str = "Char";
			break;
		case FSI_TEXT:
			str = "Text";
			break;
		case FSI_MIXED:
			str = "Text & Numeric";
			break;
		case FSI_BYTE:
			str = "Byte";
			break;
		case FSI_USHORT:
			str = "UShort";
			break;
		case FSI_ULONG:
			str = "ULong";
			break;
		case FSI_COMPLEX:
			str = "Complex";
			break;
		}
		return str;
	}
	
	// reutrn -1 if invliad, return internal type otherwise
	int getDatasetInfo(LPCSTR lpcszName, uint& nSize, double* pv1stVal = NULL, double* pvMin = NULL, double* pvMax = NULL)
	{
		if(lpcszName == NULL)
			return -1;
		
		DWORD  dLooseDSInfo;
		dLooseDSInfo = Project.GetDatasetInfo(lpcszName, true);
		
		int		nType = -1;
		nType = HIWORD(dLooseDSInfo);

		nSize = getDatasetSize(lpcszName);
		
		getDatasetValues(lpcszName, nSize, pv1stVal, pvMin ,pvMax );
		//getDatasetPlotInfo(lpcszName);
		return nType;
	}
	double getDatasetSize( LPCSTR lpcszName )
	{
		string strLT;
		strLT.Format("get %s -e v1", lpcszName);
		LT_execute(strLT);
		double vv;
		LT_get_var("v1", &vv);
		return vv;
	}
	bool getDatasetValues(LPCSTR lpcszName, uint& nSize, double* pv1stVal = NULL, double* pvMin = NULL, double* pvMax = NULL)
	{
		Dataset ds(lpcszName);
		if(!ds.IsValid())
			return false;
		
		double min, max;
		ds.GetMinMax(min, max);
		
		if(pvMin)
			*pvMin = min;
		if(pvMax)
			*pvMax = max;
		
		if(pv1stVal && ds.IsValid() && ds.GetSize() > 0)
			*pv1stVal = ds[0];
		
		return true;		
	}
	string getDatasetPlotInfo(LPCSTR lpcszName)
	{
		string strPlotInfo;
		
		if(lpcszName == NULL)
			return strPlotInfo;
		
		vector<string> vsGraphNames;
		vector<int> vnLayers;
		vector<int> vnPlotDesignations;
		
		int nn= Project.GetDatasetPlotList(lpcszName, vsGraphNames, vnLayers, vnPlotDesignations);
		if(nn <= 0 )
			return strPlotInfo;		
		
		string strSeperate = STR_SEPERATE_OF_DATASET_PLOT_INFO;
		for(int ii = 0; ii < nn; ii++)
		{
			char szTemp[NAME_SIZE];
			if(!get_plot_designation_str(vnPlotDesignations[ii], szTemp, NAME_SIZE))
				lstrcpy(szTemp, "Unknown");

			if(ii > 0)
				strPlotInfo += STR_SEPERATE_OF_DATASET_PLOT_INFO;

			strPlotInfo +=  vsGraphNames[ii] + "." + (1+vnLayers[ii]) + "(" + szTemp + ")";
		}
		
		return strPlotInfo;
	}
	void loadDatasets()
	{
		vector<string> 	vsNames, vsSizes, vsTypes, vsPlotInfo;
		
		getLooseDatasets(vsNames);
		for(int ii = 0; ii < vsNames.GetSize(); ii++)
		{
			uint 	nSize;
			int 	nType = getDatasetInfo(vsNames[ii], nSize);
			if(nType >= FSI_DOUBLE)
			{
				vsTypes.Add(getDataTypeName(nType));
				vsSizes.Add(ftoa(nSize));	
				
				string strPlotInfo = getDatasetPlotInfo(vsNames[ii]);
				vsPlotInfo.Add(strPlotInfo);
			}
			
		}
		
		BeforeUpdate();
		SetColumn(LDE_NAME, vsNames);
		SetColumn(LDE_TYPE, vsTypes);
		SetColumn(LDE_SIZE, vsSizes);
		SetColumn(LDE_PLOT_INFO, vsPlotInfo);
		AfterUpdate();
		
	}
	
	void InitButtons()
	{
		m_btnDel = GetItem(IDC_RG_BUTTON1);
		if(m_btnDel)
		{
			m_btnDel.Text = "Delete";
			m_btnDel.Visible = true;
		}
		
		Control ccClose = GetItem(IDCANCEL);
		if(ccClose)
		{
			ccClose.Text = "Close";
			ccClose.Visible = true;
		}
	}
	
	void updateButtonState(bool bEnable = false)
	{
		if(m_btnDel)
			m_btnDel.Enable = bEnable;
	}
private:
	bool			m_bDeleteOnDestroy;
	vector<uint>	m_vnButtons;
	vector<string>	m_vsColTitles;
	Control			m_btnDel;
};

//create some dataset for testing
void createDatasets()
{
	string strLT;
	strLT = "create test -wd 10 aa bb cc";
	LT_execute(strLT);
	
	strLT = "create Test2 -wdn 10 nn";
	LT_execute(strLT);	
}

// generic func prototype for VC level calling
// nMsg = 0 to open
// nMsg = 1 to close
// nMsg = 2 to update
int LooseDatasetEdit(int nMsg=0, DWORD dwCntrl=0, LPVOID lpData = NULL)
{
	bool bClose = OMSG_CLOSE==nMsg? true:false;
	bool bUpdate = OMSG_UPDATE==nMsg? true:false;

	if(bClose)
	{
		if(s_pLooseDatasetEditDlg)
		{
			Window winDlg = s_pLooseDatasetEditDlg->GetWindow();
			if(winDlg)
				winDlg.SendMessage(WM_CLOSE);
			delete s_pLooseDatasetEditDlg;
			s_pLooseDatasetEditDlg = NULL;
		}
		return 0;
	}
	// open or update
	if(!s_pLooseDatasetEditDlg)
	{
		if(bUpdate)
			return 1;// not possible to update, since dialog not opened

		s_pLooseDatasetEditDlg = new LooseDatasetEditDlg;
		s_pLooseDatasetEditDlg->Create(GetWindow());
	}
	if(bUpdate)
		s_pLooseDatasetEditDlg->Update();//"from global message");
	
	return 0;
}


