/*------------------------------------------------------------------------------*
 * File Name: XFDynaDlg.h														*
 * Creation: Sim 03-20-2008														*
 * Purpose: Origin C Header Files												*
 * Copyright (c) OriginLab Corp.2002											*
 * All Rights Reserved															*
 * 																				*
 * Modification Log:															*
 *	Sim 10-22-2008 FIX_RECURSIVE_DESTROY_ATTACHED_PAGE_AND_WIZ_DLG				*
 *	Sim 10-31-2008 INDICATE_THEME_ON_PA_FIT_PARAM_CHANGE						*
 *	Sim 12-09-2008 QA80-12741 OPERATION_UNPROTECT_IO_RANGE_IN_EXEC_TIME_OF_CHANGE_PARAM_FUNC
 *	Sim 11-13-2009 QA81-14623 NOT_CLOSE_DLG_WHEN_ENTER_PRESSED					*
 *------------------------------------------------------------------------------*/

#ifndef __XF_DYNA_DLG_H__
#define __XF_DYNA_DLG_H__

#include <Origin.h>
#include <..\OriginLab\XFunctionEx.h>
#include <..\OriginLab\DialogEx.h>

#include <..\OriginLab\DynaDlg.h>

enum{
	XF_DLG_TYPE_INDEP,
	XF_DLG_TYPE_WIZ,
};
#define MIN_HEIGHT_DYNA 100

enum{
	// DWORD Bits
	XF_FRAME_WORK_XF_NO_READY				= 0x0001,
	XF_FRAME_WORK_FAILED_EXECUTE_XF			= 0x0002,
	XF_FRAME_WORK_APPLIED					= 0x0004,
	XF_FRAME_WORK_REPEATING_APPLICABLE		= 0x0008,
	
};

class XFDynaDlg : public DynaDlg
{
public:
	XFDynaDlg(UINT nDlgID, TreeNode& tr, LPCSTR lpcszDLL)
	: DynaDlg(nDlgID, tr, lpcszDLL)
	{
	}
	///---Sim 12-09-2008 QA80-12741 OPERATION_UNPROTECT_IO_RANGE_IN_EXEC_TIME_OF_CHANGE_PARAM_FUNC
	int DoModal(HWND hParent, const Page &pg)
	{
		m_nPageUID = pg.GetUID(TRUE);
		return DoModal(hParent);
	}
	///---END QA80-12741 OPERATION_UNPROTECT_IO_RANGE_IN_EXEC_TIME_OF_CHANGE_PARAM_FUNC
	BOOL  Create(HWND hParent, const Page &pg)
	{
		m_nPageUID = pg.GetUID(TRUE);
		return Create(hParent);
	}
	
	BOOL Show(BOOL bShow = TRUE)
	{
		return page_xf_dynadlg_shown_control(GetTargetPage(), bShow, false); // show dialog and keep status
	}
protected:
	EVENTS_BEGIN
		//ON_GETNDLG_MSGS(IDC_GRID)
		ON_GETNDLG_MSGS(0) // _ID was not used
		
		ON_PAGE_DESTROY(OnPageDestroy)
		//ON_CHANGE_PAGE(OnChangePage)
		
		ON_CBN_SELCHANGE(IDC_THEME_COMB, OnComboChangeTheme)
		ON_BN_CLICKED(IDC_XF_THEME_SAVE, OnSaveTheme)
		ON_BN_CLICKED(IDC_XF_THEME_SAVEAS, OnSaveThemeAs)
		
		ON_BN_CLICKED(IDC_APPLY, OnApply)
		ON_BN_CLICKED(IDC_UNDO_BTN, OnUndo)
		
		ON_BN_CLICKED(IDC_GETN_CUSTOM_BTN1, OnClickCustomButtom)
		ON_BN_CLICKED(IDC_GETN_CUSTOM_BTN2, OnClickCustomButtom)
		ON_BN_CLICKED(IDC_GETN_CUSTOM_BTN3, OnClickCustomButtom)
		ON_BN_CLICKED(IDC_GETN_CUSTOM_BTN4, OnClickCustomButtom)
		
		ON_DC_GENERIC(OnGenericControlMsg)
		
		ON_USER_MSG(WM_USER_MSG_BOX, OnMsgBox)
		ON_USER_MSG(WM_USER_MSG_ON_DLG, OnDynamicMsg)
		ON_USER_MSG(WM_USER_ON_GRAPH_OBJECT_CHANGE, InvokeGlobalEventOnGraphObjectChange)
		
		ON_HELPINFO(OnHelp)
	EVENTS_END	

	//virtual BOOL OnInitDialog(){return true;}
	//virtual BOOL OnReady(){return true;}
	//virtual BOOL OnDestroy(){return true;}
	//virtual BOOL OnDlgResize(int nType, int cx, int cy){return true;}
	//virtual BOOL OnRestoreSize(DWORD dwSizeInfo){return true;}
	
	BOOL OnChangePage()
	{
		//OUT("OnChangePage");
		
		Page pg = Project.Pages();
		if ( IsAttachedPage(pg) )
		{
			if ( IsDialogShown(pg) )
				return ShowWindow(SW_NORMAL);
		}
		return ShowWindow(SW_HIDE);	
	}
	
	// this function to fix that range selection change cause show dialog unexpectly
	BOOL	OnSelectionTrack()
	{
		//OUT("OnSelectionTrack");
		
		Page pg = Project.Pages();
		if ( IsAttachedPage(pg) )
		{
			if ( IsDialogShown(pg) )
				return m_DynaCntrl.OnSelectionTrack();
		}
		return false;
	}

	BOOL OnPageDestroy(Page pg, DWORD dwCntrl)
	{
		if ( IsAttachedPage(pg) )
		///---Sim 10-22-2008 FIX_RECURSIVE_DESTROY_ATTACHED_PAGE_AND_WIZ_DLG
		{
			int nShow; // not used
			bool bStillAttached = page_xf_dynadlg_shown_control(pg, nShow); // should use xf_dynadlg_storage_control, but it is in xfdynadlg_utils.c, hard to invoke
			
			if ( bStillAttached )
		///---END FIX_RECURSIVE_DESTROY_ATTACHED_PAGE_AND_WIZ_DLG
				SendMessage(WM_CLOSE);
		} ///---Sim 10-22-2008 FIX_RECURSIVE_DESTROY_ATTACHED_PAGE_AND_WIZ_DLG
		return true;
	}
	
	virtual BOOL	OnApply(Control ctrl)
	{
		return Apply();
	}
	virtual BOOL	OnUndo(Control ctrl)
	{
		return Undo();
	}
	
protected:
	//virtual
	void InvokeGlobalEventOnInitDialog()
	{
		InvokeXFEvent(GETNE_ON_INIT);
	}
	//virtual
	void InvokeHandlerOnDestroy()
	{
		InvokeXFEvent(GETNE_ON_DESTORY);
	}

	//virtual
	BOOL	OnClickCustomButton(int nID)
	{
		if(nID >= IDC_GETN_CUSTOM_BTN1 && nID <= IDC_GETN_CUSTOM_BTN4)
		{
			int nn = nID - IDC_GETN_CUSTOM_BTN1 + 1;// CUSTOM_BUTTON = 1,2,3,4
			DWORD dw = CUSTOM_BUTTON_TO_GETNE_EVENT(nn);
			InvokeXFEvent(dw);
			
			//AfterGUIChange();
		}
		else
			out_int("Invalid button id for custom button: ", nID);
		return TRUE;
	}
	
	// virtual
	void OnEnableButtons(DWORD dwEnable, int nEventID)
	{
		bool bOKEnable = (dwEnable & GETNGEVT_OK_ENABLE);
		bool bApplyEnable = (dwEnable & GETNGEVT_APPLY_ENABLE);
		if ( GETNE_ON_VALUE_CHANGE == nEventID )
			bApplyEnable = true;

		switch(nEventID)
		{
		case GETNE_ON_INIT: // init event will be invoked many times
			m_btnUndo.Enable = GetFrameworkState(XF_FRAME_WORK_APPLIED);
		case GETNE_ON_EXTERNAL_MSG:
		case GETNE_ON_GRAPH_OBJECT_CHANGE:
		case GETNE_ON_CUSTOM_BUTTON1:
		case GETNE_ON_CUSTOM_BUTTON2:
		case GETNE_ON_CUSTOM_BUTTON3:
		case GETNE_ON_CUSTOM_BUTTON4:
		case GETNE_ON_THEME:
		case GETNE_ON_VALUE_CHANGE:
			if ( isAbleToApply() )
				m_applyBtn.Enable = (bOKEnable && bApplyEnable);
			else
				m_applyBtn.Enable = false;
			
			EnableCustomButtons(dwEnable);			
			SetFrameworkState(XF_FRAME_WORK_XF_NO_READY, !bOKEnable);
			if ( bOKEnable ) // after value change, should clear execution result status
				SetFrameworkState(XF_FRAME_WORK_FAILED_EXECUTE_XF, false);
	
			break;			
		case GETNE_ON_APPLY:
			if ( GetFrameworkState(XF_FRAME_WORK_APPLIED) )
			{
				if ( !GetFrameworkState(XF_FRAME_WORK_REPEATING_APPLICABLE) ) // apply only one times
					m_applyBtn.Enable = false;
				else
					m_applyBtn.Enable = (bOKEnable && bApplyEnable);
				
				m_btnUndo.Enable = true;
				
				EnableCustomButtons(dwEnable);
			}
			break;
			
		case GETNE_ON_UNDO:
			//if ( !GetFrameworkState(XF_FRAME_WORK_APPLIED) )
			if ( bOKEnable )
			{
				m_applyBtn.Enable = bOKEnable;
				m_btnUndo.Enable = false;
				EnableCustomButtons(dwEnable);
			}
			break;
			
		default:
			break;
		}
	}
	
	///---Sim 10-31-2008 INDICATE_THEME_ON_PA_FIT_PARAM_CHANGE
	/*
	//virtual
	bool CheckCustomBottonEvents(int nEventID, int nEventRet, const string& strAux)
	{
		//if ( is_aux_value(strAux, XF_NEED_APPLY) )
		//{
			//if ( isAbleToApply() )
				//m_applyBtn.Enable = true;
		//}
	
		if ( is_aux_value(strAux, DLG_NEED_CHANGE_GRID) )
		{
			UpdateDynaControl(true, GETNEVENT_ON_CHANGE_UPDATE_GUI);
		}
		
		return true;
	}
	*/
	///---END INDICATE_THEME_ON_PA_FIT_PARAM_CHANGE
	
	// virtual
	BOOL	OnAfterUpdateDynaControl(uint wParam, uint lParam)
	{
		/*
		int nEventType = wParam;
		
		// this is for prevent apply twice, 
		// same things will be done later on following event
		switch (nEventType)
		{
		case GETNEVENT_ON_CHANGE_UPDATE_GUI: // called by graph object changed, custom buttons clicked
		//case GETNEVENT_ON_CUSTOM_BUTTON1:
		//case GETNEVENT_ON_CUSTOM_BUTTON2:
		//case GETNEVENT_ON_CUSTOM_BUTTON3:
		//case GETNEVENT_ON_CUSTOM_BUTTON4:
			return false;
		}
		*/
		
		AfterGUIChange();
		return true;
	}

	// virtual
	void 	InvokeGlobalEventOnThemeChange()
	{
		InvokeXFEvent(GETNE_ON_THEME);
		
		// later will invoke OnAfterUpdateDynaControl()
		//AfterGUIChange();
	}
	
	/*
	// virtual
	void InvokeGlobalEventOnGraphObjectChange(uint wParam, uint lParam)
	{
		DynaDlg::InvokeGlobalEventOnGraphObjectChange(wParam, lParam);
		
		AfterGUIChange();
	}
	*/
	
	// virtual
	bool GetDlgSpecialButtonStatus(DWORD& dwEnables, int nEventID)
	{
		if ( IsFrameworkNormal() )
			dwEnables |= GETNGEVT_OK_ENABLE;
		else
			dwEnables &= ~GETNGEVT_OK_ENABLE;
		return true;
	}
	
protected:
	BOOL 	InitXFDynaDlg(int nDynaID)
	{
		InitDynaControl(nDynaID);
		
		m_staticXFName = GetItem(IDC_XF_NAME);
		m_staticXFDescription = GetItem(IDC_DESCRIPTION);
		m_applyBtn = 				GetItem(IDC_APPLY);
		m_btnUndo = 				GetItem(IDC_UNDO_BTN);
		m_chkAutoApply =			GetItem(IDC_CHK_XFBAR_AUTO_APPLY);
		
		m_chkAutoApply.Check = false;
		
		//m_bApplied = false;
		ResetFrameworkState();

		page_set_xf_dynadlg_storage(GetTargetPage(), (int)GetSafeHwnd());
		return true;
	}
	BOOL DestroyXFDynaDlg()
	{
		page_set_xf_dynadlg_storage(GetTargetPage(), -1);
		return true;
	}
	
	BOOL	Resize(const RECT& rect)
	{
		if(!IsInitReady())
			return TRUE;
		MoveControlsHelper	_temp(this);		///Jasmine 03/27/06 DLG_RESIZE_PAINT_MESS

		int cx = RECT_WIDTH(rect);
		int cy = RECT_HEIGHT(rect);
		
		int nEdge = GetControlGap();
		int nTop		= rect.top;
		int nBottom		= rect.bottom;
		int nLeft 		= rect.left;
		int nRight 		= rect.right;
		
		//uint uThemeItems[] = {IDC_STATIC_THEME, IDC_THEME_COMB, IDC_XF_THEME_SAVE , IDC_XF_THEME_SAVEAS, 0};
		uint uChooserItems[] = {IDC_XF_NAME, 0};
		uint uFunctionItems[] = {IDC_GETN_CUSTOM_BTN1, IDC_GETN_CUSTOM_BTN2, IDC_GETN_CUSTOM_BTN3,  IDC_GETN_CUSTOM_BTN4, IDC_APPLY, IDC_UNDO_BTN, IDC_CHK_XFBAR_AUTO_APPLY, 0, 0};
		//uint uWizardItems[] = {IDC_BTN_PREVIOUS, IDC_BTN_NEXT, IDC_BTN_FINISH, 0, 0};
		
		//if ( XFBAR_WIZARD_MODE == m_nMode )
			//uWizardItems[sizeof(uWizardItems)/sizeof(uint) - 2] = IDC_BTN_CLOSE;
		//else
		if ( XF_DLG_TYPE_INDEP == GetDlgType() )
			uFunctionItems[sizeof(uFunctionItems)/sizeof(uFunctionItems[0]) - 2] = IDC_BTN_CLOSE;
	
		// from top
		/////Joseph 05/17/07 PAGEXFBAR_SUPPORT_NO_THEME_XF
		////nTop = ArrangeControlsLeftRight(uThemeItems, nLeft, nTop, cx, IDC_THEME_COMB);
		//
		//if(m_bThemeDlg)
			//nTop = ArrangeControlsLeftRight(uThemeItems, nLeft, nTop, cx, IDC_THEME_COMB);
		//else
			//ShowControls(uThemeItems, false);
		/////End PAGEXFBAR_SUPPORT_NO_THEME_XF
		
		nTop+= nEdge;
		nTop = ArrangeControlsLeftRight(uChooserItems, nLeft, nTop, nRight, IDC_XF_NAME, 0);
		setFitHeightXFDescripCtrl(cx);
		nTop = StretchControlWide(IDC_DESCRIPTION, nLeft, nTop, nRight, 0);
		nTop+= nEdge;
	
		// from bottom
		///---Sim 07-31-2007 ARRANGE_BUTTON_AUTO_VERTICAL
		//nBottom = ArrangeControlsCenterBottom(uWizardItems, cx, nBottom);
		//nBottom = ArrangeControlsCenterBottom(uFunctionItems, cx, nBottom);
		//nBottom = ArrangeControlsCenterBottom(uWizardItems, cx, nBottom, -1, true, true);
		nBottom = ArrangeControlsCenterBottom(uFunctionItems, cx, nBottom, -1, true, true);
		///---END ARRANGE_BUTTON_AUTO_VERTICAL
	
		// error message
		int	nErrMessageHeight; ///---Sim 07-31-2007 ARRANGE_BUTTON_AUTO_VERTICAL
		if ( m_btnErrMessage )
		{
			///---Sim 07-31-2007 ARRANGE_BUTTON_AUTO_VERTICAL
			//int		nErrMessageHeight = GetDlgStatusMsgBoxHeight(nRight - nLeft);
			nErrMessageHeight = GetDlgStatusMsgBoxHeight(nRight - nLeft);
			///---END ARRANGE_BUTTON_AUTO_VERTICAL
			
			if ( nErrMessageHeight > 0 )
			{
				RECT rrMsg;
				rrMsg.left = nLeft + nEdge;
				rrMsg.right = nRight - nEdge;
				rrMsg.bottom = nBottom - nEdge;
				rrMsg.top = rrMsg.bottom - nErrMessageHeight;
				MoveControl(m_btnErrMessage, rrMsg);
				
				nBottom -= nErrMessageHeight + nEdge*2;
				
				m_btnErrMessage.Visible = true;
			}
			else
				m_btnErrMessage.Visible = false;
		}
		
		// DynaControl
		RECT rrDyna;
		rrDyna.left = nLeft;
		rrDyna.right = nRight;
		rrDyna.top = nTop;
		rrDyna.bottom = nBottom;
		MoveControl(m_DynaCntrl, rrDyna);
		///---END RECODE_RESIZE_DLG
		
		///---Sim 07-31-2007 ARRANGE_BUTTON_AUTO_VERTICAL
		// not enough space for dyna control
		if ( rrDyna.bottom < rrDyna.top + MIN_HEIGHT_DYNA )
		{
			int nOffset = rrDyna.top + MIN_HEIGHT_DYNA - rrDyna.bottom;
			rrDyna.bottom = rrDyna.top + MIN_HEIGHT_DYNA;
			MoveControl(m_DynaCntrl, rrDyna);
			nTop += MIN_HEIGHT_DYNA;
	
			/*
			// if has error message
			if (nErrMessageHeight > 0)
			{
				nTop += nEdge;		
				nTop = PositionControl(IDC_ERR_MESSAGE_BOX, nLeft, nTop, true, true);
			}
			
			nTop = ArrangeControlsCenterTop(uFunctionItems, cx, nTop, -1, true, true);
			nTop = ArrangeControlsCenterTop(uWizardItems, cx, nTop, -1, true, true);
			*/
			PositionControlOffset(IDC_ERR_MESSAGE_BOX, nOffset);
			
			int ii;
			for(ii = 0; uFunctionItems[ii] > 0; ii++)
				PositionControlOffset(uFunctionItems[ii], nOffset);
			//for(ii = 0; uWizardItems[ii] > 0; ii++)
				//PositionControlOffset(uWizardItems[ii], nOffset);
		}
		///---END ARRANGE_BUTTON_AUTO_VERTICAL
		
		return TRUE;		
	}	
	
	virtual string GetXFName(string& strXFDescription = NULL)
	{
		string strXFName;
		TreeNode trGetN = GetTree();
		trGetN.GetAttribute(STR_CLASS_OPTION_NAME_ATTRIB, strXFName);
		return strXFName;
	}
	
	//bool UpdateXFDlg(const RECT& rect)
	bool UpdateXFDlg()
	{
		string strXFName, strXFDesp;
		strXFName = GetXFName(strXFDesp);
		m_staticXFName.Text = strXFName;
		m_staticXFDescription.Text = strXFDesp;		
		
		updateShowControls();
		
		//m_bRepeatingApply = m_chkAutoApply.Visible;
		// not supported multi undo process
		//m_bRepeatingApply = true;
		SetFrameworkState(XF_FRAME_WORK_REPEATING_APPLICABLE, true);
		if ( m_btnUndo.Visible )
			//m_bRepeatingApply = false;
			SetFrameworkState(XF_FRAME_WORK_REPEATING_APPLICABLE, false);
			
		///---Sim 11-13-2009 QA81-14623 NOT_CLOSE_DLG_WHEN_ENTER_PRESSED
		if ( DYNALAYOUT_NOT_CLOSE_ON_ENTER_KEY & m_dwXFBits )
			SetDefaultButton(FALSE);
		else
			SetDefaultButton(TRUE);
		///---END QA81-14623 NOT_CLOSE_DLG_WHEN_ENTER_PRESSED
		
		return true;
		//return Resize(rect);
	}
	
	bool Apply()
	{
		InvokeXFEvent(GETNE_ON_APPLY);
		return true;
	}
	bool Undo()
	{
		InvokeXFEvent(GETNE_ON_UNDO);
		return true;
	}
	
	void InvokeXFEvent(int nEventID)
	{
		invokeBasicGlobalEvent(nEventID);
	}	
	
	void AfterGUIChange()
	{
		if (IsAutoApply())
			Apply();
	}
	
	int		GetDlgType()
	{
		return m_nDlgType;
	}
	
	bool IsAttachedPage(const Page& pg)
	{
		return (pg && pg.GetUID(TRUE) == m_nPageUID);
	}
	Page GetTargetPage()
	{
		Page  pg;
		pg = (Page)Project.GetObject(m_nPageUID);
		return pg;
	}

	bool IsAutoApply()
	{
		return (m_chkAutoApply.Visible && m_chkAutoApply.Check);
	}
	
	void SetFrameworkState(DWORD dwCtrl, bool bValue)
	{
		if ( bValue )
			m_dwFrameWorkState |= dwCtrl;
		else
			m_dwFrameWorkState &= ~dwCtrl;
	}
	bool GetFrameworkState(DWORD dwCtrl)
	{
		return ( m_dwFrameWorkState & dwCtrl );
	}
	void ResetFrameworkState()
	{
		m_dwFrameWorkState = 0;
	}
	bool IsFrameworkNormal()
	{
		return (!GetFrameworkState(XF_FRAME_WORK_XF_NO_READY|XF_FRAME_WORK_FAILED_EXECUTE_XF));
	}
	
	bool IsDialogShown(const Page& pg)
	{
		int nShow = 0;
		if ( !page_xf_dynadlg_shown_control(pg, nShow) )
		{
			ASSERT(false);
			return false;
		}
		
		return (nShow > 0);
	}
	
	void SetPageEventLink(bool bTurnOn)
	{
		PostMessageOnObjectChange(bTurnOn, GetTargetPage());
	}
	
private:
	bool setFitHeightXFDescripCtrl(int cx)
	{
		if(! m_staticXFDescription )
			return false;
		
		int nHeight = GetMsgBoxHeight(m_staticXFDescription, cx);
		
		RECT rtDesp;
		GetClientRect(m_staticXFDescription, rtDesp);
		rtDesp.bottom = rtDesp.bottom - RECT_HEIGHT(rtDesp) + nHeight;
		MoveControl(m_staticXFDescription, rtDesp);	
		return true;
	}
	
	void updateShowControls()
	{
		// reset button status for XF attribute "Keep button status for event handler"
		m_applyBtn.Enable = true; 
		m_btnUndo.Enable = false; 
		DWORD dwEnables = GETNGEVT_ENABLE_ALL_BUTTONS;
		EnableCustomButtons(dwEnables);
		
		m_applyBtn.Visible = true;
		m_btnUndo.Visible = false;
		ShowCustomButton();
		if ( !m_applyBtn.Visible )
			m_btnUndo.Visible = false;	// undo depend on apply
		m_chkAutoApply.Visible = (m_applyBtn.Visible) && ((m_dwXFBits & DYNALAYOUT_AUTO_APPLY_CHKBOX) == 0 ? false : true);
	}
	
	bool isAbleToApply()
	{
		//return ( !m_bApplied || m_bRepeatingApply );
		return (!GetFrameworkState(XF_FRAME_WORK_APPLIED) || GetFrameworkState(XF_FRAME_WORK_REPEATING_APPLICABLE))
	}
	
protected:
	int						m_nDlgType;
	int						m_nPageUID;
	
	DWORD					m_dwFrameWorkState;
	
private:
	Control					m_staticXFName;
	Control					m_staticXFDescription;
	Control					m_applyBtn;
	Control					m_btnUndo;
	Button					m_chkAutoApply;
	
	//bool					m_bApplied;	
	//bool					m_bRepeatingApply;	
};

#endif		//__XF_DYNA_DLG_H__
