/*
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 1, or (at your option)
** any later version.

** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.

** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

/*
 * Author : Alexandre Parenteau <aubonbeurre@hotmail.com> --- December 1997
 */

// LineCmd.cpp : implementation file
//

#include "stdafx.h"

#ifdef WIN32
#	include "wincvs.h"
#endif /* WIN32 */

#ifdef qMacCvsPP
#	include <UModalDialogs.h>
#	include <LCheckBoxGroupBox.h>
#	include <LTextEditView.h>
#	include <LPushButton.h>
#	include <LMultiPanelView.h>
#	include <LPopupGroupBox.h>
#	include <LCheckBox.h>
#	include <LEditText.h>

#	include "MacCvsConstant.h"
#endif /* qMacCvsPP */

#include "LineCmd.h"
#include "MultiString.h"
#include "CvsArgs.h"
#include "PromptFiles.h"
#include "CPStr.h"
#include "CvsCommands.h"
#include "MultiFiles.h"
#include "ItemListDlg.h"

#include "GetPrefs.h"
#include "CvsPrefs.h"

#if qUnix
#	include "UCvsDialogs.h"
#endif

/// Default previous commands
char* sDefPrevCvsCmd[] = 
{
	"cvs --help-options",
	"cvs --help-commands",
	"cvs --help-synonyms",
	"cvs -H <cvs_command>",
	0L
};

static CMString gPrevCvsCmd(20, "P_PrevCvsCmd", sDefPrevCvsCmd);
static CMString gPrevCvsCmdDir(20, "P_PrevCvsCmdDir");

#ifdef WIN32
#	ifdef _DEBUG
#	define new DEBUG_NEW
#	undef THIS_FILE
	static char THIS_FILE[] = __FILE__;
#	endif
#endif /* WIN32 */

#ifdef qMacCvsPP
static void DoDataExchange_CmdlineMain(LWindow *theDialog, CStr & cmdline, CPStr & path, bool & hasPath, bool putValue)
{
	LCheckBox *cbox = dynamic_cast<LCheckBox*>
		(theDialog->FindPaneByID(item_CheckGroupPath));
	LEditText *epath = dynamic_cast<LEditText*>
		(theDialog->FindPaneByID(item_ShowPath));
	LTextEditView *cline = dynamic_cast<LTextEditView*>
		(theDialog->FindPaneByID(item_NonEmptyTextEdit));
	
	if(putValue)
	{
		cline->SetTextPtr((Ptr)(const char *)cmdline, cmdline.length());
		cbox->SetValue(hasPath ? Button_On : Button_Off);
		epath->SetDescriptor(path);
		
		// this will take care about an empty module name
		theDialog->SetLatentSub(cline);
		//cline->AddListener(LCommander::GetTopCommander());
		if(cmdline.length() == 0)
		{
			LPushButton *theOK = dynamic_cast<LPushButton*>
										(theDialog->FindPaneByID(item_OK));
			Assert_(theOK != 0L);
			theOK->Disable();
		}
	}
	else
	{
		Handle hdl = cline->GetTextHandle();
		Assert_(hdl != 0L);
		cmdline.set(*hdl, GetHandleSize(hdl));
		
		Str255 outDescriptor;
		epath->GetDescriptor(outDescriptor);
		path = outDescriptor;
		hasPath = cbox->GetValue() == Button_On;
	}
}
#endif /* qMacCvsPP */

#ifdef WIN32
IMPLEMENT_DYNAMIC(CCmdLine_MAIN, CPropertyPage)

CCmdLine_MAIN::CCmdLine_MAIN(const MultiFiles* mf, 
							 const char* lastcmd, bool hasPath, const char* lastpath,
							 bool addDefault, bool addSelection, bool forceRoot) 
							 : m_mf(mf), CPropertyPage(CCmdLine_MAIN::IDD)
{
	//{{AFX_DATA_INIT(CCmdLine_MAIN)
	m_checkPath = hasPath;
	m_cmdLine = lastcmd;
	m_folderLoc = lastpath;
	m_addDefault = addDefault;
	m_addSelection = addSelection;
	m_forceRoot = forceRoot;
	//}}AFX_DATA_INIT

	m_hasSelection = m_mf->NumDirs() > 0;

	m_firstTimeCmdline = true;
	m_prevCmdCombo.SetItems(&gPrevCvsCmd);
	m_folderLocCombo.SetItems(&gPrevCvsCmdDir);
}

CCmdLine_MAIN::~CCmdLine_MAIN()
{
}

void CCmdLine_MAIN::DoDataExchange(CDataExchange* pDX)
{
	CPropertyPage::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CCmdLine_MAIN)
	DDX_Control(pDX, IDC_FOLDERLOC, m_folderLocCombo);
	DDX_Control(pDX, IDC_ADD_SELECTION, m_addSelectionCheck);
	DDX_Control(pDX, IDC_CHECKPATH, m_checkPathCheck);
	DDX_Control(pDX, IDC_CMDLINE, m_cmdLineEdit);
	DDX_Control(pDX, IDC_PREVCMD, m_prevCmdCombo);
	DDX_Control(pDX, IDC_SELFOLDER, m_selFolderButton);
	DDX_Check(pDX, IDC_CHECKPATH, m_checkPath);
	DDX_Text(pDX, IDC_CMDLINE, m_cmdLine);
	DDV_MinChars(pDX, m_cmdLine, 1);
	DDX_Text(pDX, IDC_FOLDERLOC, m_folderLoc);
	DDX_Check(pDX, IDC_ADD_DEFAULT, m_addDefault);
	DDX_Check(pDX, IDC_ADD_SELECTION, m_addSelection);
	DDX_Check(pDX, IDC_FORCEROOT, m_forceRoot);
	//}}AFX_DATA_MAP
	
	if( pDX->m_bSaveAndValidate )
	{
		if( !m_cmdLine.IsEmpty() && DEF_CVS_CMD != m_cmdLine )
		{
			gPrevCvsCmd.Insert(m_cmdLine);
		}
	}
	else
	{
		DDX_ComboMString(pDX, IDC_PREVCMD, m_prevCmdCombo);
	}
	
	DDX_ComboMString(pDX, IDC_FOLDERLOC, m_folderLocCombo);

	if( m_checkPath )
	{
		DDV_MinChars(pDX, m_folderLoc, 1);
		DDV_CheckPathExists(pDX, IDC_FOLDERLOC, m_folderLoc);
	}

	if( !pDX->m_bSaveAndValidate )
	{
		m_selFolderButton.EnableWindow(m_checkPath);
	}
}


BEGIN_MESSAGE_MAP(CCmdLine_MAIN, CPropertyPage)
	//{{AFX_MSG_MAP(CCmdLine_MAIN)
	ON_BN_CLICKED(IDC_CHECKPATH, OnCheckpath)
	ON_BN_CLICKED(IDC_SELFOLDER, OnSelfolder)
	ON_CBN_SELCHANGE(IDC_PREVCMD, OnSelchangePrevcmd)
	ON_EN_SETFOCUS(IDC_CMDLINE, OnSetfocusCmdline)
	ON_BN_CLICKED(IDC_TAG, OnTag)
	ON_BN_CLICKED(IDC_MODULE, OnModule)
	ON_BN_CLICKED(IDC_ADD_SELECTION, OnAddSelection)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CCmdLine_MAIN message handlers

/// BN_CLICKED message handler, enable controls
void CCmdLine_MAIN::OnCheckpath() 
{
	const BOOL enable = m_checkPathCheck.GetCheck();

	m_selFolderButton.EnableWindow(enable);
	m_folderLocCombo.EnableWindow(enable);
	m_addSelectionCheck.EnableWindow(!enable && m_hasSelection);

	if( enable && m_hasSelection && m_mf )
	{
		CString strFolderLoc;
		m_folderLocCombo.GetWindowText(strFolderLoc);
		
		if( strFolderLoc.IsEmpty() )
		{
			CStr path;
			if( m_mf->getdir(0, path) )
			{
				m_folderLocCombo.SetWindowText(path.c_str());
			}
		}
	}
}

/// BN_CLICKED message handler, select folder to execute command
void CCmdLine_MAIN::OnSelfolder() 
{
	CString strFolderLoc;
    m_folderLocCombo.GetWindowText(strFolderLoc);
	
	CStr folderLoc(strFolderLoc);
	if( BrowserGetDirectory("Select where to execute", folderLoc, IsWindow(m_hWnd) ? this : NULL) )
	{
		m_folderLocCombo.SetWindowText(folderLoc);
	}
}

/// PreTranslateMessage virtual override, intercept the Cancel and Enter keys to allow closing the dialog even is command line has focus
BOOL CCmdLine_MAIN::PreTranslateMessage(MSG* pMsg) 
{
	if( pMsg->message == WM_KEYDOWN )
	{
		switch( (int)pMsg->wParam )
		{
		case VK_ESCAPE:		//dialog can be dismissed by Esc key
			EndDialog(IDCANCEL);
			break;
		case VK_RETURN:		//command can be executed with Enter key
			if( UpdateData() )
			{
				EndDialog(IDOK);
			}
			break;
		default:
			break;
		}
	}
	
	return CPropertyPage::PreTranslateMessage(pMsg);
}

/// OnInitDialog virtual override, enable controls
BOOL CCmdLine_MAIN::OnInitDialog() 
{
	CPropertyPage::OnInitDialog();
	
	// Extra initialization
	OnCheckpath();
	OnAddSelection();
	
	return TRUE;  // return TRUE unless you set the focus to a control
	              // EXCEPTION: OCX Property Pages should return FALSE
}

/// CBN_SELCHANGE message handler, insert the selected previous command into command line control
void CCmdLine_MAIN::OnSelchangePrevcmd() 
{
	int sel = m_prevCmdCombo.GetCurSel();
	if( sel == CB_ERR )
		return;

	m_cmdLineEdit.SetSel(0, -1);
	const NAMESPACE(std) vector<CStr> & list = gPrevCvsCmd.GetList();
	m_cmdLineEdit.ReplaceSel(list[sel]);
}

/// EN_SETFOCUS message handler, cancel the selection if it's the first time command line control gets focus
void CCmdLine_MAIN::OnSetfocusCmdline() 
{
	if( m_firstTimeCmdline )
	{
		m_firstTimeCmdline = false;
		
		CString cmdLine;
		m_cmdLineEdit.GetWindowText(cmdLine);

		if( DEF_CVS_CMD == cmdLine )
		{
			m_cmdLineEdit.SetSel(-1, -1);
		}
	}
}

/// BN_CLICKED message handler, display browse tag/branch dialog
void CCmdLine_MAIN::OnTag() 
{
	CStr tagName;
	if( CompatGetTagListItem(m_mf, tagName) )
	{
		m_cmdLineEdit.ReplaceSel(tagName.c_str(), TRUE);
	}
}

/// BN_CLICKED message handler, browse for file/directory
void CCmdLine_MAIN::OnModule() 
{
	CStr moduleName;
	if( CompatGetModuleListItem(m_mf, moduleName) )
	{
		m_cmdLineEdit.ReplaceSel(moduleName.c_str(), TRUE);
	}
}

/// BN_CLICKED message handler, enable controls
void CCmdLine_MAIN::OnAddSelection() 
{
	if( m_addSelectionCheck.IsWindowEnabled() )
	{
		const BOOL enable = m_addSelectionCheck.GetCheck() ? false : true;
		
		OnCheckpath();
		
		m_checkPathCheck.EnableWindow(enable);
		m_selFolderButton.EnableWindow(enable);
		m_folderLocCombo.EnableWindow(enable);
		
		if( enable )
		{
			OnCheckpath();
		}
	}
}
#endif /* WIN32 */

#if qUnix
class UCvsCmdline : public UWidget
{
	UDECLARE_DYNAMIC(UCvsCmdline)
public:
	UCvsCmdline() : UWidget(::UEventGetWidID()) {}
	virtual ~UCvsCmdline() {}

	enum
	{
		kOK = EV_COMMAND_START,	// 0
		kCancel,				// 1
		kTabGeneral				// 2
	};

	virtual void DoDataExchange(bool fill);

protected:
	ev_msg int OnOK(void);
	ev_msg int OnCancel(void);

	UDECLARE_MESSAGE_MAP()
};

UIMPLEMENT_DYNAMIC(UCvsCmdline, UWidget)

UBEGIN_MESSAGE_MAP(UCvsCmdline, UWidget)
	ON_UCOMMAND(UCvsCmdline::kOK, UCvsCmdline::OnOK)
	ON_UCOMMAND(UCvsCmdline::kCancel, UCvsCmdline::OnCancel)
UEND_MESSAGE_MAP()

int UCvsCmdline::OnOK(void)
{
	EndModal(true);
	return 0;
}

int UCvsCmdline::OnCancel(void)
{
	EndModal(false);
	return 0;
}

void UCvsCmdline::DoDataExchange(bool fill)
{
	if(fill)
	{
	}
	else
	{
	}
}

class UCvsCmdline_MAIN : public UWidget
{
	UDECLARE_DYNAMIC(UCvsCmdline_MAIN)
public:
	UCvsCmdline_MAIN(const char *lastcmd, bool hasPath,
					 const char *lastpath);
	virtual ~UCvsCmdline_MAIN() {}

	enum
	{
		kEditCmd = EV_COMMAND_START,	// 0
		kCheckPath,			// 1
		kStatPath,			// 2
		kBtnPath			// 3
	};

	virtual void DoDataExchange(bool fill);

	bool m_checkpath;
	UStr m_cmdline;
	UStr m_folderloc;
protected:
	ev_msg int OnCheckPath(void);
	ev_msg int OnBtnPath(void);

	UDECLARE_MESSAGE_MAP()
};

UIMPLEMENT_DYNAMIC(UCvsCmdline_MAIN, UWidget)

UBEGIN_MESSAGE_MAP(UCvsCmdline_MAIN, UWidget)
	ON_UCOMMAND(UCvsCmdline_MAIN::kCheckPath, UCvsCmdline_MAIN::OnCheckPath)
	ON_UCOMMAND(UCvsCmdline_MAIN::kBtnPath, UCvsCmdline_MAIN::OnBtnPath)
UEND_MESSAGE_MAP()

UCvsCmdline_MAIN::UCvsCmdline_MAIN(const char *lastcmd, bool hasPath,
							 const char *lastpath) : UWidget(::UEventGetWidID())
{
	m_checkpath = hasPath;
	m_cmdline = lastcmd;
	m_folderloc = lastpath;
}

int UCvsCmdline_MAIN::OnCheckPath()
{
	int state = UEventSendMessage(GetWidID(), EV_QUERYSTATE, kCheckPath, 0L);
	UEventSendMessage(GetWidID(), EV_ENABLECMD, UMAKEINT(kStatPath, state), 0L);
	UEventSendMessage(GetWidID(), EV_ENABLECMD, UMAKEINT(kBtnPath, state), 0L);
	return 0;
}

int UCvsCmdline_MAIN::OnBtnPath()
{
	CStr dir;
	if( BrowserGetDirectory("Select where to execute", dir) )
	{
		UEventSendMessage(GetWidID(), EV_SETTEXT, kStatPath, (void*)dir.c_str());
	}

	return 0;
}

void UCvsCmdline_MAIN::DoDataExchange(bool fill)
{
	if(fill)
	{
		UEventSendMessage(GetWidID(), EV_SETSTATE, UMAKEINT(kCheckPath, m_checkpath), 0L);
		UEventSendMessage(GetWidID(), EV_SETTEXT, kEditCmd, (void *)(const char *)m_cmdline);
		UEventSendMessage(GetWidID(), EV_SETTEXT, kStatPath, (void *)(const char *)m_folderloc);

		OnCheckPath();
	}
	else
	{
		m_checkpath = UEventSendMessage(GetWidID(), EV_QUERYSTATE, kCheckPath, 0L) != 0;
		UEventSendMessage(GetWidID(), EV_GETTEXT, kEditCmd, &m_cmdline);
		UEventSendMessage(GetWidID(), EV_GETTEXT, kStatPath, &m_folderloc);
	}
}
#endif // qUnix

/// Get the command line options
bool CompatGetCommand(const MultiFiles* mf,
					  CStr& cmd, CStr& dir, bool& addDefault, bool& addSelection,
					  bool& forceCvsroot)
{
	bool userHitOK = false;

	static CStr sLastCmdline(DEF_CVS_CMD);
	static CPStr sLastPath("");
	static bool sLastHasPath = false;
	static bool lastAddDefault = false;
	static bool lastAddSelection = false;
	static bool lastForceCvsroot = false;

#ifdef WIN32
	CPropertySheet pages("Command line settings");
	pages.m_psh.dwFlags |= PSH_NOAPPLYNOW;
	
	CCmdLine_MAIN page1(mf, sLastCmdline, sLastHasPath, sLastPath, lastAddDefault, lastAddSelection, lastForceCvsroot);
	CGetPrefs_CVSROOT page2;
	CGetPrefs_GLOBALS page3;

	pages.AddPage(&page1);
	pages.AddPage(&page2);
	pages.AddPage(&page3);
	
	if( pages.DoModal() == IDOK )
	{
		sLastCmdline = page1.m_cmdLine;
		sLastHasPath = page1.m_checkPath == TRUE;
		sLastPath = page1.m_folderLoc;
		lastAddDefault = page1.m_addDefault ? true : false;
		lastAddSelection = page1.m_addSelection ? true : false;
		lastForceCvsroot = page1.m_forceRoot ? true : false;

		page2.StoreValues();
		page3.StoreValues();

		userHitOK = true;
	}
#endif /* WIN32 */

#if qUnix
	void *wid = UCreate_CmdlineDlg();

	UCvsCmdline *dlg = new UCvsCmdline();
	UCvsCmdline_MAIN *tab1 = new UCvsCmdline_MAIN(sLastCmdline, sLastHasPath, sLastPath);
	UEventSendMessage(dlg->GetWidID(), EV_INIT_WIDGET, kUMainWidget, wid);	
	dlg->AddPage(tab1, UCvsCmdline::kTabGeneral, 0);

	if(dlg->DoModal())
	{
		sLastCmdline = tab1->m_cmdline;
		sLastHasPath = tab1->m_checkpath;
		sLastPath = tab1->m_folderloc;

		userHitOK = true;
	}

	delete dlg;
#endif // qUnix

#ifdef qMacCvsPP
	StDialogHandler	theHandler(dlg_Cmdline, LCommander::GetTopCommander());
	LWindow *theDialog = theHandler.GetDialog();
	ThrowIfNil_(theDialog);
	static UInt16 sRuntimePanel = 1;
	
	LMultiPanelView *multiView = dynamic_cast<LMultiPanelView*>
		(theDialog->FindPaneByID(item_MultiViewPrefs));
	LPane *groupView = theDialog->FindPaneByID(item_GroupViewPrefs);
	
	multiView->SwitchToPanel(2);
	DoDataExchange_Globals(theDialog, true);
	multiView->SwitchToPanel(1);
	DoDataExchange_CmdlineMain(theDialog, sLastCmdline, sLastPath, sLastHasPath, true);

	LCheckBox *cbox = dynamic_cast<LCheckBox*>
		(theDialog->FindPaneByID(item_CheckGroupPath));
	LPushButton *epath = dynamic_cast<LPushButton*>
		(theDialog->FindPaneByID(item_EditPath));
	LEditText *pathDisplay = dynamic_cast<LEditText*>
		(theDialog->FindPaneByID(item_ShowPath));
	epath->AddListener(&theHandler);
	cbox->AddListener(&theHandler);
	
	groupView->SetValue(sRuntimePanel);
	theDialog->Show();
	MessageT hitMessage;
	while (true)
	{		// Let DialogHandler process events
		hitMessage = theHandler.DoDialog();
		
		if (hitMessage == msg_OK || hitMessage == msg_Cancel)
			break;
		
		if(hitMessage == item_CheckGroupPath || hitMessage == item_EditPath)
		{
			cbox = dynamic_cast<LCheckBox*>
				(theDialog->FindPaneByID(item_CheckGroupPath));
			pathDisplay = dynamic_cast<LEditText*>
				(theDialog->FindPaneByID(item_ShowPath));
			if(cbox->GetValue() == Button_Off)
			{
				continue;
			}
			
			if( BrowserGetDirectory("Select where to execute", dir) )
			{
				CPStr tmp(dir.c_str());
				pathDisplay->SetDescriptor(tmp);
			}
			else if(hitMessage == item_CheckGroupPath)
			{
				cbox->SetValue(Button_Off);
			}
		}

	}
	theDialog->Hide();
	sRuntimePanel = groupView->GetValue();
	
	if(hitMessage == msg_OK)
	{
		multiView->SwitchToPanel(1);
		DoDataExchange_CmdlineMain(theDialog, sLastCmdline, sLastPath, sLastHasPath, false);
		multiView->SwitchToPanel(2);
		DoDataExchange_Globals(theDialog, false);
		Assert_(sLastCmdline.length() != 0);

		userHitOK = true;
	}
#endif /* qMacCvsPP */

	if( userHitOK )
	{
		cmd = sLastCmdline;
		dir = sLastHasPath ? (const char*)sLastPath : 0L;

		addDefault = lastAddDefault;
		addSelection = lastAddSelection;
		forceCvsroot = lastForceCvsroot;

		gCvsPrefs.save();
	}

	return userHitOK;
}
