// TortoiseGitMerge - a Diff/Patch program

// Copyright (C) 2013, 2021-2024 - TortoiseGit
// Copyright (C) 2006-2015, 2017, 2020 - TortoiseSVN

// 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 2
// of the License, 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,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
#pragma once

#include "DiffData.h"
#include "LocatorBar.h"
#include "LineDiffBar.h"
#include "FilePatchesDlg.h"
#include "TempFile.h"
#include "XSplitter.h"
#include "GitPatch.h"
#include "../../ext/SimpleIni/SimpleIni.h"
#include "CustomMFCRibbonStatusBar.h"
#include <tuple>
#include "NativeRibbonApp.h"

class CLeftView;
class CRightView;
class CBottomView;
#define MOVESTOIGNORE 3

#define TABMODE_NONE		0x00
#define TABMODE_USESPACES	0x01
#define TABMODE_SMARTINDENT	0x02

#define TABSIZEBUTTON1 3
#define TABSIZEBUTTON2 4
#define TABSIZEBUTTON4 5
#define TABSIZEBUTTON8 6
#define ENABLEEDITORCONFIG 8

#define TABSIZE_MIN 1
#define TABSIZE_MAX 1000

/**
 * \ingroup TortoiseMerge
 * The main frame of TortoiseMerge. Handles all the menu and toolbar commands.
 */
class CMainFrame : public CFrameWndEx, public CPatchFilesDlgCallBack //CFrameWndEx
{
public:
	CMainFrame();
	virtual ~CMainFrame();

	int InitRibbon();

	void			ShowDiffBar(bool bShow);
	void			DiffLeftToBase();
	void			DiffRightToBase();
	int				CheckResolved();

#ifdef _DEBUG
	virtual void	AssertValid() const;
	virtual void	Dump(CDumpContext& dc) const;
#endif
protected:
	DECLARE_DYNCREATE(CMainFrame)

	virtual BOOL	PreCreateWindow(CREATESTRUCT& cs);
	virtual BOOL	OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext);
	virtual void	ActivateFrame(int nCmdShow = -1);
	virtual BOOL	OnShowPopupMenu(CMFCPopupMenu* pMenuPopup);
	/// line = -1 means keep the current position,
	/// line >= 0 means scroll to that line,
	/// and line == -2 means do nothing or scroll to first diff depending on registry setting
	bool			LoadViews(int line = -2);
	void			ClearViewNamesAndPaths();
	void			SetWindowTitle();
	void			RecalcLayout(BOOL bNotify = TRUE) override;

	afx_msg LRESULT	OnTaskbarButtonCreated(WPARAM wParam, LPARAM lParam);
	afx_msg LRESULT	OnIdleUpdateCmdUI(WPARAM wParam, LPARAM);
	afx_msg LRESULT	OnDPIChanged(WPARAM wParam, LPARAM);

	afx_msg void	OnFileSave();
	afx_msg void	OnFileSaveAs();
	afx_msg void	OnFileOpen();
	afx_msg void	OnFileOpen(bool fillyours);

	afx_msg void	OnFileReload();
	afx_msg void	OnClose();
	afx_msg void	OnActivate(UINT, CWnd*, BOOL);
	afx_msg void	OnViewWhitespaces();
	afx_msg int		OnCreate(LPCREATESTRUCT lpCreateStruct);
	afx_msg void	OnDestroy();
	afx_msg void	OnSize(UINT nType, int cx, int cy);
	afx_msg void	OnUpdateFileSave(CCmdUI *pCmdUI);
	afx_msg void	OnUpdateFileSaveAs(CCmdUI *pCmdUI);
	afx_msg void	OnViewOnewaydiff();
	afx_msg void	OnUpdateViewOnewaydiff(CCmdUI *pCmdUI);
	afx_msg void	OnUpdateViewWhitespaces(CCmdUI *pCmdUI);
	afx_msg void	OnViewOptions();
	afx_msg void	OnViewLinedown();
	afx_msg void	OnViewLineup();
	afx_msg void	OnViewLineleft();
	afx_msg void	OnViewLineright();
	afx_msg void	OnEditUseTheirs();
	afx_msg void	OnEditUseMine();
	afx_msg void	OnEditUseTheirsThenMine();
	afx_msg void	OnEditUseMineThenTheirs();
	afx_msg void	OnUpdateEditUseminethentheirblock(CCmdUI *pCmdUI);
	afx_msg void	OnUpdateEditUsemyblock(CCmdUI *pCmdUI);
	afx_msg void	OnUpdateEditUsetheirblock(CCmdUI *pCmdUI);
	afx_msg void	OnUpdateEditUsetheirthenmyblock(CCmdUI *pCmdUI);
	afx_msg void	OnUpdateMergeMarkasresolved(CCmdUI *pCmdUI);
	afx_msg void	OnMergeMarkasresolved();
	afx_msg void	OnUpdateMergeNextconflict(CCmdUI *pCmdUI);
	afx_msg void	OnUpdateMergePreviousconflict(CCmdUI *pCmdUI);
	afx_msg void	OnUpdateEditCopy(CCmdUI *pCmdUI);
	afx_msg void	OnUpdateEditPaste(CCmdUI *pCmdUI);
	afx_msg void	OnMoving(UINT fwSide, LPRECT pRect);
	afx_msg void	OnViewSwitchleft();
	afx_msg void	OnUpdateViewSwitchleft(CCmdUI *pCmdUI);
	afx_msg void	OnUpdateViewShowfilelist(CCmdUI *pCmdUI);
	afx_msg void	OnViewShowfilelist();
	afx_msg void	OnEditUndo();
	afx_msg void	OnUpdateEditUndo(CCmdUI *pCmdUI);
	afx_msg void	OnEditRedo();
	afx_msg void	OnUpdateEditRedo(CCmdUI *pCmdUI);
	afx_msg void	OnEditEnable();
	afx_msg void	OnUpdateEditEnable(CCmdUI *pCmdUI);
	afx_msg void	OnViewInlinediffword();
	afx_msg void	OnUpdateViewInlinediffword(CCmdUI *pCmdUI);
	afx_msg void	OnViewInlinediff();
	afx_msg void	OnUpdateViewInlinediff(CCmdUI *pCmdUI);
	afx_msg void	OnUpdateEditCreateunifieddifffile(CCmdUI *pCmdUI);
	afx_msg void	OnEditCreateunifieddifffile();
	afx_msg void	OnUpdateViewLinediffbar(CCmdUI *pCmdUI);
	afx_msg void	OnViewLinediffbar();
	afx_msg void	OnUpdateViewLocatorbar(CCmdUI *pCmdUI);
	afx_msg void	OnUpdateViewBars(CCmdUI *pCmdUI);
	afx_msg void	OnViewLocatorbar();
	afx_msg void	OnEditUseleftblock();
	afx_msg void	OnUpdateUseBlock(CCmdUI *pCmdUI);
	afx_msg void	OnUpdateEditUseleftblock(CCmdUI *pCmdUI);
	afx_msg void	OnEditUseleftfile();
	afx_msg void	OnUpdateEditUseleftfile(CCmdUI *pCmdUI);
	afx_msg void	OnEditUseblockfromleftbeforeright();
	afx_msg void	OnUpdateEditUseblockfromleftbeforeright(CCmdUI *pCmdUI);
	afx_msg void	OnEditUseblockfromrightbeforeleft();
	afx_msg void	OnUpdateEditUseblockfromrightbeforeleft(CCmdUI *pCmdUI);
	afx_msg void	OnUpdateNavigateNextdifference(CCmdUI *pCmdUI);
	afx_msg void	OnUpdateNavigatePreviousdifference(CCmdUI *pCmdUI);
	afx_msg void	OnViewCollapsed();
	afx_msg void	OnUpdateViewCollapsed(CCmdUI *pCmdUI);
	afx_msg void	OnViewComparewhitespaces();
	afx_msg void	OnUpdateViewComparewhitespaces(CCmdUI *pCmdUI);
	afx_msg void	OnViewIgnorewhitespacechanges();
	afx_msg void	OnUpdateViewIgnorewhitespacechanges(CCmdUI *pCmdUI);
	afx_msg void	OnViewIgnoreallwhitespacechanges();
	afx_msg void	OnUpdateViewIgnoreallwhitespacechanges(CCmdUI *pCmdUI);
	afx_msg void	OnUpdateNavigateNextinlinediff(CCmdUI *pCmdUI);
	afx_msg void	OnUpdateNavigatePrevinlinediff(CCmdUI *pCmdUI);
	afx_msg void	OnViewMovedBlocks();
	afx_msg void	OnUpdateViewMovedBlocks(CCmdUI *pCmdUI);
	afx_msg void	OnViewWraplonglines();
	afx_msg void	OnUpdateViewWraplonglines(CCmdUI *pCmdUI);
	afx_msg void	OnIndicatorLeftview();
	afx_msg void	OnIndicatorRightview();
	afx_msg void	OnIndicatorBottomview();
	afx_msg void	OnTimer(UINT_PTR nIDEvent);
	afx_msg void	OnViewIgnorecomments();
	afx_msg void	OnUpdateViewIgnorecomments(CCmdUI *pCmdUI);
	afx_msg void	OnViewIgnoreEOL();
	afx_msg void	OnUpdateViewIgnoreEOL(CCmdUI* pCmdUI);
	afx_msg void	OnUpdateViewRegexFilter(CCmdUI *pCmdUI);
	afx_msg void	OnRegexfilter(UINT cmd);
	afx_msg void	OnDummyEnabled() {};
	afx_msg void	OnEncodingLeft(UINT cmd);
	afx_msg void	OnEncodingRight(UINT cmd);
	afx_msg void	OnEncodingBottom(UINT cmd);
	afx_msg void	OnEOLLeft(UINT cmd);
	afx_msg void	OnEOLRight(UINT cmd);
	afx_msg void	OnEOLBottom(UINT cmd);
	afx_msg void	OnTabModeLeft(UINT cmd);
	afx_msg void	OnTabModeRight(UINT cmd);
	afx_msg void	OnTabModeBottom(UINT cmd);
	afx_msg void	OnUpdateEncodingLeft(CCmdUI *pCmdUI);
	afx_msg void	OnUpdateEncodingRight(CCmdUI *pCmdUI);
	afx_msg void	OnUpdateEncodingBottom(CCmdUI *pCmdUI);
	afx_msg void	OnUpdateEOLLeft(CCmdUI *pCmdUI);
	afx_msg void	OnUpdateEOLRight(CCmdUI *pCmdUI);
	afx_msg void	OnUpdateEOLBottom(CCmdUI *pCmdUI);
	afx_msg void	OnUpdateTabModeLeft(CCmdUI *pCmdUI);
	afx_msg void	OnUpdateTabModeRight(CCmdUI *pCmdUI);
	afx_msg void	OnUpdateTabModeBottom(CCmdUI *pCmdUI);
	afx_msg void	OnUpdateThreeWayActions(CCmdUI* pCmdUI);
	afx_msg void	OnUpdateColumnStatusBar(CCmdUI* pCmdUI);
	afx_msg void	OnUpdateMarkedWords(CCmdUI* pCmdUI);
	afx_msg void	OnUpdateEnableIfSelection(CCmdUI* pCmdUI);
	afx_msg	void	OnRegexNoFilter();
	afx_msg void	OnUpdateRegexNoFilter(CCmdUI* pCmdUI);
	afx_msg void	OnSettingChange(UINT uFlags, LPCWSTR lpszSection);
	afx_msg void	OnSysColorChange();
	afx_msg BOOL	OnHelpInfo(HELPINFO* pHelpInfo);
	DECLARE_MESSAGE_MAP()

	void HtmlHelp(DWORD_PTR dwData, UINT nCmd = 0x000F) override;

protected:
	void			UpdateLayout();
	BOOL			PatchFile(CString sFilePath, bool bContentMods, bool bPropMods, CString sVersion, BOOL bAutoPatch) override;
	BOOL			DiffFiles(CString sURL1, CString sRev1, CString sURL2, CString sRev2) override;
	BOOL			MarkAsResolved();
	int				SaveFile(const CString& sFilePath);
	void			WriteWindowPlacement(WINDOWPLACEMENT * pwp);
	BOOL			ReadWindowPlacement(WINDOWPLACEMENT * pwp);
	void			WriteViewBarPreferences();
	bool			FileSave(bool bCheckResolved=true);
	void			PatchSave();
	bool			FileSaveAs(bool bCheckResolved=true);
	void			LoadIgnoreCommentData();
	/// checks if there are modifications and asks the user to save them first
	/// IDCANCEL is returned if the user wants to cancel.
	/// If the user wanted to save the modifications, this method does the saving
	/// itself.
	int				CheckForReload();
	enum class ECheckForSaveReason {
		Close, ///< closing apps
		Switch, ///< switching views
		Reload, ///< reload views also switching between 1 and 2 way diff
		Options, ///< white space change, options
		Open, ///< opening an open dialog
	};
	/// checks if there are modifications and asks the user to save them first
	/// IDCANCEL is returned if the user wants to cancel.
	/// If the user wanted to save the modifications, this method does the saving
	/// itself.
	int				CheckForSave(ECheckForSaveReason eReason/* = ECheckForSaveReason::Switch*/);
	void			DeleteBaseTheirsMineOnClose();
	void			OnViewLineUpDown(int direction);
	void			OnViewLineLeftRight(int direction);
	static void		OnTabMode(CBaseView *view, int cmd);
	static void		OnUpdateTabMode(CBaseView *view, CCmdUI *pCmdUI, int startid);
	bool			HasConflictsWontKeep();
	bool			TryGetFileName(CString& result);
	CBaseView*		GetActiveBaseView() const;
	void			OnViewTextFoldUnfold();
	void			OnViewTextFoldUnfold(CBaseView* view);
	bool			HasUnsavedEdits() const;
	static bool		HasUnsavedEdits(const CBaseView* view);
	bool			HasMarkedBlocks() const;
	static bool		IsViewGood(const CBaseView* view);
	static bool		HasPrevConflict(CBaseView* view);
	static bool		HasNextConflict(CBaseView* view);
	static bool		HasPrevInlineDiff(CBaseView* view);
	static bool		HasNextInlineDiff(CBaseView* view);
	void			BuildRegexSubitems(CMFCPopupMenu* pMenuPopup = nullptr);
	bool			AdjustUnicodeTypeForLoad(CFileTextLines::UnicodeType& type);
	void			DiffTwo(const CWorkingFile& file1, const CWorkingFile& file2);
	void			SetTheme(bool bDark);
	void			SetAccentColor();

protected:
	CMFCStatusBar	m_wndStatusBar;
	CCustomMFCRibbonStatusBar	m_wndRibbonStatusBar;
	CLocatorBar		m_wndLocatorBar;
	CLineDiffBar	m_wndLineDiffBar;
	CXSplitter		m_wndSplitter;
	CXSplitter		m_wndSplitter2;
	CFilePatchesDlg	m_dlgFilePatches;

	GitPatch		m_Patch;
	BOOL			m_bInitSplitter;
	bool			m_bCheckReload = false;

	bool			m_bHasConflicts = false;
	bool			m_bMarkedAsResolvedWasDone = false;

	bool			m_bInlineWordDiff = true;
	bool			m_bInlineDiff;
	bool			m_bLineDiff;
	bool			m_bLocatorBar;
	bool			m_bUseRibbons = true;

	CRegDWORD		m_regWrapLines;
	CRegDWORD		m_regViewModedBlocks;
	CRegDWORD		m_regOneWay;
	CRegDWORD		m_regCollapsed;
	CRegDWORD		m_regInlineDiff;
	CRegDWORD		m_regUseRibbons;
	CRegDWORD		m_regIgnoreComments;
	CRegDWORD		m_regLineDiff;
	CRegDWORD		m_regLocatorBar;
	CRegDWORD		m_regStatusBar;

	std::map<CString, std::tuple<CString, CString, CString>>	m_IgnoreCommentsMap;
	CSimpleIni		m_regexIni;
	int				m_regexIndex = -1;
public:
	CLeftView*		m_pwndLeftView = nullptr;
	CRightView*		m_pwndRightView = nullptr;
	CBottomView*	m_pwndBottomView = nullptr;
	BOOL			m_bOneWay;
	BOOL			m_bReversedPatch = FALSE;
	CDiffData		m_Data;
	bool			m_bReadOnly = false;
	bool			m_bBlame = false;
	int				m_nMoveMovesToIgnore = 0;
	bool			m_bCollapsed;
	bool			m_bViewMovedBlocks;
	bool			m_bWrapLines;
	bool			m_bSaveRequired = false;
	bool			m_bSaveRequiredOnConflicts = false;
	bool			m_bDeleteBaseTheirsMineOnClose = false;
	HWND			resolveMsgWnd = nullptr;
	WPARAM			resolveMsgWParam = 0;
	LPARAM			resolveMsgLParam = 0;

	const CMFCToolBar *   GetToolbar() const { return &m_wndToolBar; }
	void			FillEncodingButton( CMFCRibbonButton * pButton, int start );
	void			FillEOLButton( CMFCRibbonButton * pButton, int start );
	void			FillTabModeButton(CMFCRibbonButton * pButton, int start);
	CMFCMenuBar		m_wndMenuBar;
	CMFCToolBar		m_wndToolBar;

	int				m_themeCallbackId = 0;

	std::unique_ptr<CNativeRibbonApp> m_pRibbonApp;
	CComPtr<IUIFramework> m_pRibbonFramework;
};
