//////////////////////////////////////////////////////////////////////////////
//
// Copyright            : (C) 2015 Eran Ifrah
// File name            : clKeyboardManager.h
//
//    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.
//
//////////////////////////////////////////////////////////////////////////////
// Modifed for Code::Blocks by pecan

#ifndef KEYBOARDMANAGER_H
#define KEYBOARDMANAGER_H

#include <list>
#include <wx/frame.h>
#include <wx/accel.h>
#include <vector>
//#include <map>
#include <unordered_map>
#include <unordered_set>

#include <wx/menu.h>
#include <wx/event.h>
#include <wx/filename.h>
#include "macros.h"
#include "wxstringhash.h"   //required for wxWidgets < wx3100
#include "manager.h"
#include "personalitymanager.h"

struct  MenuItemData {
    wxString resourceID;
    wxString accel;
    wxString action;
    wxString parentMenu; // For display purposes

    struct ClearParentMenu {
        void operator()(std::pair<const int, MenuItemData>& iter) { iter.second.parentMenu.Clear(); }
    };

    struct PrependPrefix {
        wxString m_prefix;
        PrependPrefix(const wxString& prefix)
            : m_prefix(prefix)
        {
        }
        void operator()(std::pair<const int, MenuItemData>& iter) { iter.second.action.Prepend(m_prefix); }
    };
};

typedef std::vector<MenuItemData> MenuItemDataVec_t;  //(2019/02/26)

struct  clKeyboardShortcut {
    bool m_ctrl;
    bool m_alt;
    bool m_shift;
    wxString m_keyCode;

    clKeyboardShortcut()
        : m_ctrl(false)
        , m_alt(false)
        , m_shift(false)
    {
    }

    /**
     * @brief clear this accelerator
     */
    void Clear();

    /**
     * @brief construct this object from string representation
     * e.g.: Ctrl-Alt-1
     */
    void FromString(const wxString& accelString);
    /**
     * @brief return a string representation of this accelerator
     */
    wxString ToString() const;

    typedef std::vector<clKeyboardShortcut> Vec_t;
};

// ----------------------------------------------------------------------------
class  clKeyboardManager : public wxEvtHandler
// ----------------------------------------------------------------------------
{
private:
    typedef std::list<wxFrame*> FrameList_t;
    MenuItemDataVec_t m_menuTable;
    MenuItemDataVec_t m_globalTable;
    wxStringSet_t m_keyCodes;
    wxStringSet_t m_allShorcuts;

protected:
    /**
     * @brief return list of frames
     */
    void DoGetFrames(wxFrame* parent, clKeyboardManager::FrameList_t& frames);
    void DoUpdateMenu(wxMenu* menu, MenuItemDataVec_t& accels, std::vector<wxAcceleratorEntry>& table);
    void DoUpdateFrame(wxFrame* frame, MenuItemDataVec_t& accels);
    void DoConvertToIntMap(const MenuItemDataVec_t& strMap, MenuItemDataVec_t& intMap);
    MenuItemDataVec_t DoLoadDefaultAccelerators();

    clKeyboardManager();
    virtual ~clKeyboardManager();

protected:

public:
    static void Release();
    static clKeyboardManager* Get();

    /**
     * @brief return an array of all unassigned keyboard shortcuts
     */
    wxArrayString GetAllUnasignedKeyboardShortcuts() const;

    /**
     * @brief show a 'Add keyboard shortcut' dialog
     */
    int PopupNewKeyboardShortcutDlg(wxWindow* parent, MenuItemData& menuItemData);

    /**
     * @brief return true if the accelerator is already assigned
     */
    bool Exists(const wxString& accel) const;
    MenuItemDataVec_t::iterator ExistsALikeAccel(MenuItemDataVec_t& srcMap, MenuItemDataVec_t::iterator srcvecIter) const; //(2019/04/22)
    void CheckForDuplicateAccels(MenuItemDataVec_t& accelMap) const; //(2019/04/22)

    /**
     * @brief save the bindings to disk
     */
    void Save();

    /**
     * @brief load bindings from the file system
     */
    void Initialize(bool isRefreshRequest);

    /**
     * @brief add keyboard shortcut by specifying the action ID + the shortcut combination
     * For example: AddAccelerator("wxID_COPY", "Ctrl-Shift-C", "Copy the current selection");
     * @return true if the action succeeded, false otherwise
     */
    void AddGlobalAccelerator(
        const wxString& resourceID, const wxString& keyboardShortcut, const wxString& description);

    /**
     * @brief replace all acceleratos with 'accels'
     */
    void SetAccelerators(const MenuItemDataVec_t& accels);

    /**
     * @brief return all accelerators known to CodeLite
     */
    void GetAllAccelerators(MenuItemDataVec_t& accels) const;

    /**
     * @brief update accelerators
     */
    void Update(wxFrame* frame = NULL);

    /**
     * @brief restore keyboard shortcuts to defaults
     */
    void RestoreDefaults();

    bool ReadFileContent(const wxFileName& fn, wxString& data, const wxMBConv& conv = wxConvUTF8);           //(2019/04/3)
    bool WriteFileContent(const wxFileName& fn, const wxString& content, const wxMBConv& conv = wxConvUTF8); //(2019/04/3)

    wxString KeyCodeToString(int keyCode);              //(2019/02/25)
    wxString NumpadKeyCodeToString(int keyCode);        //(2019/02/25)
    void     DumpAccelerators(size_t tableCount, wxAcceleratorEntry* pEntries, wxFrame* pFrame); //(2019/10/27)
    void     LogAccelerators(MenuItemDataVec_t& menuTable, wxString title);

    MenuItemData* FindMenuTableEntryFor(MenuItemDataVec_t& vecTable, MenuItemData* pMenuMapItem);
    MenuItemData* FindMenuTableEntryByPathAndAccel(MenuItemDataVec_t& vecTable, MenuItemData* pMenuMapItem);
    MenuItemData* FindMenuTableEntryByPath(MenuItemDataVec_t& vecTable, MenuItemData* pMenuMapItem);
    MenuItemData* FindMenuTableEntryByID(MenuItemDataVec_t& vecTable, int ID);

    wxString GetTempKeyMnuAccelsFilename() //(2020/02/25)
    {
        wxString userPersonality = Manager::Get()->GetPersonalityManager()->GetPersonality();
        wxString pid_string = wxString::Format(_T("_%lu"), wxGetProcessId());
        wxFileName fnTempKeyMnuAccels(wxStandardPaths::Get().GetTempDir(), _T("keyMnuAccels.conf"));
        fnTempKeyMnuAccels.SetName(userPersonality + _T(".") + fnTempKeyMnuAccels.GetName() + pid_string);
        return fnTempKeyMnuAccels.GetFullPath();
    }

    private:
        DECLARE_EVENT_TABLE()
};

#endif // KEYBOARDMANAGER_H

