﻿// TortoiseSVN - a Windows shell extension for easy version control

// Copyright (C) 2026 - 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 "scintilla.h"
#include <vector>

class CPartialDiff;

/**
 * \ingroup TortoiseProc
 * Read-only Scintilla control which shows the diff of a CPartialDiff.
 * A check box in the left margin of each changed line selects the line
 * for the commit. The check box of a hunk header selects the whole hunk.
 *
 * The control sends WM_DIFFSELCHANGED to the parent window after the
 * user changes the selection.
 */
class CDiffSelectCtrl : public CWnd
{
    DECLARE_DYNAMIC(CDiffSelectCtrl)

public:
    CDiffSelectCtrl();
    ~CDiffSelectCtrl() override;

    static const UINT WM_DIFFSELCHANGED;

    void Init();
    /// shows the diff of \a diff. The control does not own the object.
    void SetDiff(CPartialDiff* diff);
    /// shows a message instead of a diff
    void SetMessage(const CString& message);
    CPartialDiff* GetDiff() const { return m_diff; }

protected:
    DECLARE_MESSAGE_MAP()
    BOOL         OnChildNotify(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pLResult) override;
    afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
    afx_msg void OnContextMenu(CWnd* pWnd, CPoint point);

private:
    enum class LineType
    {
        Header,
        Context,
        Removed,
        Added,
    };
    struct DisplayLine
    {
        LineType type;
        size_t   hunk;
        size_t   index; ///< index of the line inside the hunk (removed or added lines)
    };

    LRESULT Call(UINT message, WPARAM wParam = 0, LPARAM lParam = 0) const;
    void    SetupStyles();
    void    DefineMarkers();
    void    SetText(const std::string& text);
    void    UpdateLineState(size_t displayLine);
    void    UpdateAllLineStates();
    bool    IsLineSelected(const DisplayLine& line) const;
    /// toggles all changed lines between \a firstLine and \a lastLine (display lines)
    void    ToggleLines(size_t firstLine, size_t lastLine);
    void    SelectLines(size_t firstLine, size_t lastLine, bool select);
    void    NotifyParent() const;
    size_t  GetHunkOfLine(size_t displayLine) const;

    LRESULT                  m_directFunction;
    LRESULT                  m_directPointer;
    int                      m_themeCallbackId;
    CPartialDiff*            m_diff;
    std::vector<DisplayLine> m_lines;
};
