/*
** 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 "MacCvsConstant.h"
#endif /* qMacCvsPP */

#include "MultiString.h"
#include "LineCmd.h"
#include "CvsArgs.h"
#include "PromptFiles.h"
#include "CPStr.h"
#include "TextBinary.h"

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

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

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

#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)
{
	LCheckBoxGroupBox *cbox = dynamic_cast<LCheckBoxGroupBox*>
		(theDialog->FindPaneByID(item_CheckGroupPath));
	LPushButton *epath = dynamic_cast<LPushButton*>
		(theDialog->FindPaneByID(item_EditPath));
	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
#include "GetPrefs.h"
#include "CvsPrefs.h"

IMPLEMENT_DYNCREATE(CCmdLine_MAIN, CPropertyPage)

CCmdLine_MAIN::CCmdLine_MAIN(const char *lastcmd, bool hasPath,	const char *lastpath) 
	: CPropertyPage(CCmdLine_MAIN::IDD)
{
	//{{AFX_DATA_INIT(CCmdLine_MAIN)
	m_checkPath = hasPath;
	m_cmdLine = lastcmd;
	m_folderLoc = lastpath;
	//}}AFX_DATA_INIT

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

CCmdLine_MAIN::CCmdLine_MAIN() : CPropertyPage(CCmdLine_MAIN::IDD)
{
}

CCmdLine_MAIN::~CCmdLine_MAIN()
{
}

void CCmdLine_MAIN::DoDataExchange(CDataExchange* pDX)
{
	CPropertyPage::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CCmdLine_MAIN)
	DDX_Control(pDX, IDC_CMDLINE, m_cmdLineEdit);
	DDX_Control(pDX, IDC_PREVCMD, m_prevCmdCombo);
	DDX_Control(pDX, IDC_SELFOLDER, m_selFolder);
	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);
	//}}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);
	}
	
	if( m_checkPath )
	{
		DDV_MinChars(pDX, m_folderLoc, 1);
		DDV_CheckPathExists(pDX, IDC_FOLDERLOC, m_folderLoc);
	}

	if( !pDX->m_bSaveAndValidate )
	{
		m_selFolder.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)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

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

void CCmdLine_MAIN::OnCheckpath() 
{
	CButton* button = (CButton *)GetDlgItem(IDC_CHECKPATH);
	int isChecked = button->GetCheck();
	CWnd* folderLoc = GetDlgItem(IDC_FOLDERLOC);
	
	m_selFolder.EnableWindow(isChecked);
	folderLoc->EnableWindow(isChecked);
	m_selFolder.EnableWindow(isChecked);
}

void CCmdLine_MAIN::OnSelfolder() 
{
	const char *dir = BrowserGetDirectory("Select where to execute:", IsWindow(this->m_hWnd) ? this : NULL);
	if( dir != 0L )
	{
		SetDlgItemText(IDC_FOLDERLOC, dir);
	}
}

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
			UpdateData();
			EndDialog(IDOK);
			break;
		default:
			break;
		}
	}
	
	return CPropertyPage::PreTranslateMessage(pMsg);
}

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

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]);
}

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);
		}
	}
}

#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()
{
	const char *dir = BrowserGetDirectory("Select where to execute :");
	if(dir != 0L)
		UEventSendMessage(GetWidID(), EV_SETTEXT, kStatPath, (void *)dir);
	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

bool CompatGetCommand(CvsArgs &args, const char * &dir)
{
	char cmd[MAX_CMD_LEN] = {'\0'};
	dir = 0L;

	static CStr sLastCmdline(DEF_CVS_CMD);
#ifdef macintosh
	static CPStr sLastPath("pick:a:mac:path:");
#else /* !macintosh */
	static CPStr sLastPath("");
#endif /* !macintosh */
	static bool sLastHasPath = false;

#ifdef WIN32
	CPropertySheet pages("Command line settings");
	pages.m_psh.dwFlags |= PSH_NOAPPLYNOW;
	CCmdLine_MAIN page1(sLastCmdline, sLastHasPath, sLastPath);
	CGetPrefs_GLOBALS page2;
	pages.AddPage(&page1);
	pages.AddPage(&page2);
	if( pages.DoModal() == IDOK )
	{
		sLastCmdline = page1.m_cmdLine;
		sLastHasPath = page1.m_checkPath == TRUE;
		sLastPath = page1.m_folderLoc;
		
		dir = page1.m_checkPath ? (const char *)sLastPath : 0L;
		strcpy(cmd, page1.m_cmdLine);

		page2.StoreValues();
		gCvsPrefs.save();
	}
	else
		return false;
#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;

		dir = tab1->m_checkpath ? (const char *)sLastPath : 0L;
		strcpy(cmd, tab1->m_cmdline);
	}
	else
	{
		delete dlg;
		return false;
	}

	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);

	LCheckBoxGroupBox *cbox = dynamic_cast<LCheckBoxGroupBox*>
		(theDialog->FindPaneByID(item_CheckGroupPath));
	LPushButton *epath = dynamic_cast<LPushButton*>
		(theDialog->FindPaneByID(item_EditPath));
	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<LCheckBoxGroupBox*>
				(theDialog->FindPaneByID(item_CheckGroupPath));
			epath = dynamic_cast<LPushButton*>
				(theDialog->FindPaneByID(item_EditPath));
			if(cbox->GetValue() == Button_Off)
			{
				dir = 0L;
				continue;
			}
			
			dir = BrowserGetDirectory("Select where to execute :");
			if(dir != 0L)
			{
				CPStr tmp(dir);
				epath->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);
		
		strcpy(cmd, sLastCmdline);
		Assert_(sLastCmdline.length() != 0);
		dir = sLastHasPath ? (const char *)sLastPath : 0L;
	}
	else
		return false;
#endif /* qMacCvsPP */
	
	if(cmd[0] == '\0' || (dir != 0L && dir[0] == '\0'))
		return false;

	char *argv[MAX_ARGS];
	int argc = StringToArgv(cmd, argv);

	for (int i = 0; i < argc; i++)
		args.add(argv[i]);

	return true;
}
