/*
** 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> --- March 1998
 */

/*
 * DiffDlg.cpp : the cvs diff dialog
 */

#include "stdafx.h"

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

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

#ifdef qMacCvsPP
#	include <UModalDialogs.h>
#	include <LRadioButton.h>
#	include <LEditText.h>
#	include <LCheckBox.h>
#	include <LMultiPanelView.h>
#	include <LPopupGroupBox.h>
#	include "LPopupFiller.h"

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

#include "DiffDlg.h"
#include "CvsPrefs.h"
#include "UpdateDlg.h"

static CPersistentBool gUseExtDiff("P_DiffUseExtDiff", false);

#ifdef WIN32
#include "GetPrefs.h"

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

IMPLEMENT_DYNCREATE(CDiff_MAIN, CPropertyPage)

CDiff_MAIN::CDiff_MAIN(const char *rev1, const char *rev2, bool allowExtDiff, bool noWhiteSpace, bool ignoreCare) :
	CPropertyPage(CDiff_MAIN::IDD), m_allowExtDiff(allowExtDiff)
{
	//{{AFX_DATA_INIT(CDiff_MAIN)
	m_check1 = FALSE;
	m_check2 = FALSE;
	m_str1 = rev1;
	m_str2 = rev2;
	m_diff = 0;
	m_norecurs = FALSE;
	m_extdiff = (bool)gUseExtDiff;
	m_noWhiteSpace = noWhiteSpace;
	m_ignoreCase = ignoreCare;
	//}}AFX_DATA_INIT
}

CDiff_MAIN::CDiff_MAIN() : CPropertyPage(CDiff_MAIN::IDD)
{
}

CDiff_MAIN::~CDiff_MAIN()
{
}

void CDiff_MAIN::DoDataExchange(CDataExchange* pDX)
{
	CPropertyPage::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CDiff_MAIN)
	DDX_Control(pDX, IDC_EXTDIFF, m_extdiffctl);
	DDX_Control(pDX, IDC_COMBO2, m_def2);
	DDX_Control(pDX, IDC_COMBO1, m_def1);
	DDX_Check(pDX, IDC_CHECK1, m_check1);
	DDX_Check(pDX, IDC_CHECK2, m_check2);
	DDX_CBString(pDX, IDC_COMBO1, m_str1);
	DDX_CBString(pDX, IDC_COMBO2, m_str2);
	DDX_Radio(pDX, IDC_DIFF1, m_diff);
	DDX_Check(pDX, IDC_NORECURS, m_norecurs);
	DDX_Check(pDX, IDC_EXTDIFF, m_extdiff);
	DDX_Check(pDX, IDC_IGNOREWHITESPACE, m_noWhiteSpace);
	DDX_Check(pDX, IDC_IGNORECASE, m_ignoreCase);
	//}}AFX_DATA_MAP
	if(m_diff == 1 || m_diff == 2)
		DDV_MinChars(pDX, m_str1, 1);
	if(m_diff == 2)
		DDV_MinChars(pDX, m_str2, 1);
	if(!pDX->m_bSaveAndValidate)
	{
		OnDiff1();
	}
		
	DDX_ComboMString(pDX, IDC_COMBO1, m_check1 ? gDateNames : gRevNames, m_def1);
	DDX_ComboMString(pDX, IDC_COMBO2, m_check2 ? gDateNames : gRevNames, m_def2);

	m_extdiffctl.EnableWindow(m_allowExtDiff ? true : false);
	OnExtdiff();
}

BEGIN_MESSAGE_MAP(CDiff_MAIN, CPropertyPage)
	//{{AFX_MSG_MAP(CDiff_MAIN)
	ON_BN_CLICKED(IDC_DIFF1, OnDiff1)
	ON_BN_CLICKED(IDC_DIFF2, OnDiff2)
	ON_BN_CLICKED(IDC_DIFF3, OnDiff3)
	ON_BN_CLICKED(IDC_EXTDIFF, OnExtdiff)
	ON_BN_CLICKED(IDC_CHECK1, OnCheck1)
	ON_BN_CLICKED(IDC_CHECK2, OnCheck2)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CDiff_MAIN message handlers

void CDiff_MAIN::OnDiff1()
{
	CButton* but = (CButton *)GetDlgItem(IDC_DIFF1);
	CButton* but1 = (CButton *)GetDlgItem(IDC_DIFF2);
	CButton* but2 = (CButton *)GetDlgItem(IDC_DIFF3);
	CWnd* wnd1 = GetDlgItem(IDC_COMBO1);
	CWnd* wnd2 = GetDlgItem(IDC_COMBO2);
	CWnd* wnd3 = GetDlgItem(IDC_CHECK1);
	CWnd* wnd4 = GetDlgItem(IDC_CHECK2);
	if(but->GetCheck() == 1)
	{
		wnd1->EnableWindow(FALSE);
		wnd2->EnableWindow(FALSE);
		wnd3->EnableWindow(FALSE);
		wnd4->EnableWindow(FALSE);
	}
	else if(but1->GetCheck() == 1)
	{
		wnd1->EnableWindow(TRUE);
		wnd2->EnableWindow(FALSE);
		wnd3->EnableWindow(TRUE);
		wnd4->EnableWindow(FALSE);
	}
	else
	{
		wnd1->EnableWindow(TRUE);
		wnd2->EnableWindow(TRUE);
		wnd3->EnableWindow(TRUE);
		wnd4->EnableWindow(TRUE);
	}
}

void CDiff_MAIN::OnDiff2() 
{
	OnDiff1();
}

void CDiff_MAIN::OnDiff3() 
{
	OnDiff1();
}
#endif /* WIN32 */

#ifdef qMacCvsPP
static void DoDataExchange_DiffMain(LWindow *theDialog, bool & noRecurs, bool & isDate1, bool & isDate2,
	CPStr & sLastRev1, CPStr & sLastRev2, bool & hasRev1, bool & hasRev2, bool putValue)
{
	LRadioButton *chkHasRev = dynamic_cast<LRadioButton*>
		(theDialog->FindPaneByID(item_CheckRevTag1));
	LEditText *editRev = dynamic_cast<LEditText*>
		(theDialog->FindPaneByID(item_EditRevTag1));
	LRadioButton *chkHasRev2 = dynamic_cast<LRadioButton*>
		(theDialog->FindPaneByID(item_CheckRevTag2));
	LEditText *editRev2 = dynamic_cast<LEditText*>
		(theDialog->FindPaneByID(item_EditRevTag2));
	LCheckBox *chkHasDate1 = dynamic_cast<LCheckBox*>
		(theDialog->FindPaneByID(item_CheckDate1));
	LCheckBox *chkHasDate2 = dynamic_cast<LCheckBox*>
		(theDialog->FindPaneByID(item_CheckDate2));
	LPopupFiller *fill1 = dynamic_cast<LPopupFiller*>
		(theDialog->FindPaneByID(item_FillerRev1));
	LPopupFiller *fill2 = dynamic_cast<LPopupFiller*>
		(theDialog->FindPaneByID(item_FillerRev2));
	LPane *extDiff = theDialog->FindPaneByID(item_DiffExternal);
	
	if(putValue)
	{
		chkHasDate1->SetValue(isDate1 ? Button_On : Button_Off);
		chkHasDate2->SetValue(isDate2 ? Button_On : Button_Off);
		if(hasRev1 && hasRev2)
			theDialog->SetValueForPaneID (item_CheckRevTag2, Button_On);
		else if(hasRev1)
			theDialog->SetValueForPaneID (item_CheckRevTag1, Button_On);
		else
			theDialog->SetValueForPaneID (item_MergeNone, Button_On);

		editRev->SetText((Ptr)(const char *)sLastRev1, sLastRev1.length());
		editRev2->SetText((Ptr)(const char *)sLastRev2, sLastRev2.length());

		fill1->DoDataExchange(gRevNames, putValue);
		fill2->DoDataExchange(gRevNames, putValue);
		
		extDiff->SetValue ((bool)gUseExtDiff ? Button_On : Button_Off);
	}
	else
	{
		isDate1 = chkHasDate1->GetValue() == Button_On;
		isDate2 = chkHasDate2->GetValue() == Button_On;

		if(theDialog->GetValueForPaneID (item_CheckRevTag2) == Button_On)
		{
			hasRev1 = hasRev2 = true;
		}
		else if (theDialog->GetValueForPaneID (item_CheckRevTag1) == Button_On)
		{
			hasRev1 = true;
			hasRev2 = false;
		}
		else
		{
			hasRev1 = hasRev2 = false;
		}

		fill1->DoDataExchange(isDate1 ? gDateNames : gRevNames, putValue);
		fill2->DoDataExchange(isDate2 ? gDateNames : gRevNames, putValue);

		char str[255];
		Size len;
		
		editRev->GetText(str, 254, &len);
		sLastRev1.set(str, len);
		editRev2->GetText(str, 254, &len);
		sLastRev2.set(str, len);
		
		gUseExtDiff = extDiff->GetValue () == Button_On;
	}
}
#endif /* qMacCvsPP */

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

	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(UCvsDiff, UWidget)

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

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

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

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

class UCvsDiff_MAIN : public UWidget
{
	UDECLARE_DYNAMIC(UCvsDiff_MAIN)
public:
	UCvsDiff_MAIN(const char *rev1, const char *rev2, bool allowExtDiff);
	virtual ~UCvsDiff_MAIN() {}

	enum
	{
		kCheckDiff1 = EV_COMMAND_START,	// 0
		kCheckDiff2,			// 1
		kCheckDiff3,			// 2
		kCheckDate1,			// 3
		kCheckDate2,			// 4
		kComboRev1,				// 5
		kComboRev2,				// 6
		kCheckRecurs,			// 7
		kCheckExtDiff			// 8
	};

	virtual void DoDataExchange(bool fill);

	bool m_check1;
	bool m_check2;
	UStr m_str1;
	UStr m_str2;
	int m_diff;
	bool m_norecurs;
	bool m_extdiff;
	bool m_allowExtDiff;

protected:
	ev_msg int OnDiff(int cmd);

	UDECLARE_MESSAGE_MAP()
};

UIMPLEMENT_DYNAMIC(UCvsDiff_MAIN, UWidget)

UBEGIN_MESSAGE_MAP(UCvsDiff_MAIN, UWidget)
	ON_UCOMMAND_RANGE(UCvsDiff_MAIN::kCheckDiff1, UCvsDiff_MAIN::kCheckDiff2, UCvsDiff_MAIN::OnDiff)
UEND_MESSAGE_MAP()

UCvsDiff_MAIN::UCvsDiff_MAIN(const char *rev1, const char *rev2, bool allowExtDiff) : UWidget(::UEventGetWidID())
{
	m_check1 = false;
	m_check2 = false;
	m_str1 = rev1;
	m_str2 = rev2;
	m_diff = 0;
	m_norecurs = false;
	m_extdiff = gUseExtDiff;
	m_allowExtDiff = allowExtDiff;
}

int UCvsDiff_MAIN::OnDiff(int cmd)
{
	int state = UEventSendMessage(GetWidID(), EV_QUERYSTATE, kCheckDiff1, 0L);
	if(state)
	{
		UEventSendMessage(GetWidID(), EV_ENABLECMD, UMAKEINT(kCheckDate1, 0), 0L);
		UEventSendMessage(GetWidID(), EV_ENABLECMD, UMAKEINT(kComboRev1, 0), 0L);
		UEventSendMessage(GetWidID(), EV_ENABLECMD, UMAKEINT(kCheckDate2, 0), 0L);
		UEventSendMessage(GetWidID(), EV_ENABLECMD, UMAKEINT(kComboRev2, 0), 0L);
	}
	else
	{
		UEventSendMessage(GetWidID(), EV_ENABLECMD, UMAKEINT(kCheckDate1, 1), 0L);
		UEventSendMessage(GetWidID(), EV_ENABLECMD, UMAKEINT(kComboRev1, 1), 0L);
		state = UEventSendMessage(GetWidID(), EV_QUERYSTATE, kCheckDiff2, 0L);
		UEventSendMessage(GetWidID(), EV_ENABLECMD, UMAKEINT(kCheckDate2, state == 0), 0L);
		UEventSendMessage(GetWidID(), EV_ENABLECMD, UMAKEINT(kComboRev2, state == 0), 0L);
	}
	return 0;
}

void UCvsDiff_MAIN::DoDataExchange(bool fill)
{
	::DoDataExchange(fill, GetWidID(), kComboRev1, gDateOrRevNames);
	::DoDataExchange(fill, GetWidID(), kComboRev2, gDateOrRevNames);

	if(fill)
	{
		UEventSendMessage(GetWidID(), EV_ENABLECMD, UMAKEINT(kCheckExtDiff, m_allowExtDiff), 0L);

		UEventSendMessage(GetWidID(), EV_SETSTATE, UMAKEINT(kCheckDate1, m_check1), 0L);
		UEventSendMessage(GetWidID(), EV_SETSTATE, UMAKEINT(kCheckDate2, m_check2), 0L);
		UEventSendMessage(GetWidID(), EV_SETSTATE, UMAKEINT(kCheckRecurs, m_norecurs), 0L);
		UEventSendMessage(GetWidID(), EV_SETSTATE, UMAKEINT(kCheckExtDiff, m_extdiff), 0L);
		UEventSendMessage(GetWidID(), EV_SETSTATE, UMAKEINT(kCheckDiff1 + m_diff, 1), 0L);

		UEventSendMessage(GetWidID(), EV_SETTEXT, kComboRev1, (void *)(const char *)m_str1);
		UEventSendMessage(GetWidID(), EV_SETTEXT, kComboRev2, (void *)(const char *)m_str2);

		OnDiff(kCheckDiff1 + m_diff);
	}
	else
	{
		m_check1 = UEventSendMessage(GetWidID(), EV_QUERYSTATE, kCheckDate1, 0L);
		m_check2 = UEventSendMessage(GetWidID(), EV_QUERYSTATE, kCheckDate2, 0L);
		m_norecurs = UEventSendMessage(GetWidID(), EV_QUERYSTATE, kCheckRecurs, 0L);
		m_extdiff = UEventSendMessage(GetWidID(), EV_QUERYSTATE, kCheckExtDiff, 0L);

		if(UEventSendMessage(GetWidID(), EV_QUERYSTATE, kCheckDiff1, 0L))
			m_diff = 0;
		else if(UEventSendMessage(GetWidID(), EV_QUERYSTATE, kCheckDiff2, 0L))
			m_diff = 1;
		else
			m_diff = 2;

		UEventSendMessage(GetWidID(), EV_GETTEXT, kComboRev1, &m_str1);
		UEventSendMessage(GetWidID(), EV_GETTEXT, kComboRev2, &m_str2);
	}
}
#endif // qUnix

bool CompatGetDiff(bool & noRecurs, bool & isDate1, bool & isDate2,
				   CPStr & rev1, CPStr & rev2, bool & useExtDiff,
				   bool & noWhiteSpace, bool & ignoreCare,
				   bool allowExtDiff)
{
	bool userHitOK = false;

	static CPStr sLastRev1;
	static CPStr sLastRev2;
	static bool bNoWhiteSpace = false;
	static bool bIgnoreCare = false;

	rev1 = "";
	rev2 = "";
	noRecurs = false;
	isDate1 = false;
	isDate2 = false;
	useExtDiff = (bool)gUseExtDiff;
	noWhiteSpace = bNoWhiteSpace;
	ignoreCare = bIgnoreCare;
	bool hasRev1 = false;
	bool hasRev2 = false;
	
#ifdef WIN32
	COptionalPropertySheet pages(gCvsPrefs.HideCommandDlgDiff(), "Diff settings");
	pages.m_psh.dwFlags |= PSH_NOAPPLYNOW;
	CDiff_MAIN page1(sLastRev1, sLastRev2, allowExtDiff, noWhiteSpace, ignoreCare);
	CGetPrefs_GLOBALS page2;
	pages.AddPage(&page1);
	pages.AddPage(&page2);
	if(pages.DoModal() == IDOK)
	{
		noRecurs = page1.m_norecurs == TRUE;

		sLastRev1 = page1.m_str1;
		sLastRev2 = page1.m_str2;
		isDate1 = page1.m_check1 == TRUE;
		isDate2 = page1.m_check2 == TRUE;
		gUseExtDiff = page1.m_extdiff == TRUE;
		if(page1.m_diff == 0)
		{
			hasRev1 = hasRev2 = false;
		}
		else if(page1.m_diff == 1)
		{
			hasRev1 = true;
			hasRev2 = false;
		}
		else
		{
			hasRev1 = true;
			hasRev2 = true;
		}

		noWhiteSpace = page1.m_noWhiteSpace == TRUE;
		ignoreCare = page1.m_ignoreCase == TRUE;

		page2.StoreValues();
		gCvsPrefs.SetHideCommandDlgDiff(pages.GetHideCommandDlg());
		userHitOK = true;
	}
#endif /* WIN32 */
#ifdef qMacCvsPP
	StDialogHandler	theHandler(dlg_Diff, 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_DiffMain(theDialog, noRecurs, isDate1, isDate2, sLastRev1, sLastRev2,
		hasRev1, hasRev2, true);
	
	groupView->SetValue(sRuntimePanel);
	theDialog->Show();
	MessageT hitMessage;
	while (true)
	{		// Let DialogHandler process events
		hitMessage = theHandler.DoDialog();
		
		if (hitMessage == msg_OK || hitMessage == msg_Cancel)
			break;
	}
	theDialog->Hide();
	sRuntimePanel = groupView->GetValue();
	
	if(hitMessage == msg_OK)
	{
		multiView->SwitchToPanel(1);
		DoDataExchange_DiffMain(theDialog, noRecurs, isDate1, isDate2, sLastRev1, sLastRev2,
			hasRev1, hasRev2, false);
		multiView->SwitchToPanel(2);
		DoDataExchange_Globals(theDialog, false);
		userHitOK = true;
	}
#endif /* qMacCvsPP */
#if qUnix
	void *wid = UCreate_DiffDlg();

	UCvsDiff *dlg = new UCvsDiff();
	UCvsDiff_MAIN *tab1 = new UCvsDiff_MAIN(sLastRev1, sLastRev2, allowExtDiff);
	UEventSendMessage(dlg->GetWidID(), EV_INIT_WIDGET, kUMainWidget, wid);	
	dlg->AddPage(tab1, UCvsDiff::kTabGeneral, 0);

	if(dlg->DoModal())
	{
		noRecurs = tab1->m_norecurs;

		sLastRev1 = tab1->m_str1;
		sLastRev2 = tab1->m_str2;
		isDate1 = tab1->m_check1;
		isDate2 = tab1->m_check2;
		gUseExtDiff = tab1->m_extdiff;
		if(tab1->m_diff == 0)
		{
			hasRev1 = hasRev2 = false;
		}
		else if(tab1->m_diff == 1)
		{
			hasRev1 = true;
			hasRev2 = false;
		}
		else
		{
			hasRev1 = true;
			hasRev2 = true;
		}

		userHitOK = true;
	}

	delete dlg;
#endif // qUnix

	if(userHitOK)
	{
		if(hasRev1)
			rev1 = sLastRev1;
		if(hasRev2)
			rev2 = sLastRev2;
		useExtDiff = (bool)gUseExtDiff;

		bNoWhiteSpace = noWhiteSpace;
		bIgnoreCare = ignoreCare;

		gCvsPrefs.save();
	}

	return userHitOK;
}

#ifdef WIN32

void CDiff_MAIN::OnExtdiff() 
{
	// TODO: Add your control notification handler code here
	CButton* but = (CButton *)GetDlgItem(IDC_EXTDIFF);
	CWnd* wnd1 = GetDlgItem(IDC_IGNOREWHITESPACE);
	CWnd* wnd2 = GetDlgItem(IDC_IGNORECASE);
	BOOL bEnableDiffOptions = ( !but->GetCheck() || !but->IsWindowEnabled() );
	wnd1->EnableWindow(bEnableDiffOptions);
	wnd2->EnableWindow(bEnableDiffOptions);
}

void CDiff_MAIN::OnCheck1() 
{
	CButton* btnIsDate = (CButton*)GetDlgItem(IDC_CHECK1);
	DDX_ComboMString(NULL, IDC_COMBO1, btnIsDate->GetCheck() ? gDateNames : gRevNames, m_def1);
}

void CDiff_MAIN::OnCheck2() 
{
	CButton* btnIsDate = (CButton*)GetDlgItem(IDC_CHECK2);
	DDX_ComboMString(NULL, IDC_COMBO2, btnIsDate->GetCheck() ? gDateNames : gRevNames, m_def2);
}

#endif /* WIN32 */
