// SPDX-License-Identifier: GPL-2.0-only
/*
 * Digital Voice Modem - Peer ID Editor
 * GPLv2 Open Source. Use is subject to license terms.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 *  Copyright (C) 2024 Bryan Biedenkapp, N2PLL
 *
 */
/**
 * @file PeerEdMainWnd.h
 * @ingroup peered
 */
#if !defined(__PEERED_MAIN_WND_H__)
#define __PEERED_MAIN_WND_H__

#include "common/Log.h"
#include "common/Thread.h"

using namespace lookups;

#include <final/final.h>
using namespace finalcut;
#undef null

#include "PeerEdMain.h"

#include "LogDisplayWnd.h"
#include "PeerListWnd.h"
#include "PeerEditWnd.h"

#include <vector>

// ---------------------------------------------------------------------------
//  Constants
// ---------------------------------------------------------------------------

#define MINIMUM_SUPPORTED_SIZE_WIDTH 83
#define MINIMUM_SUPPORTED_SIZE_HEIGHT 30

// ---------------------------------------------------------------------------
//  Class Prototypes
// ---------------------------------------------------------------------------

class HOST_SW_API PeerEdApplication;

// ---------------------------------------------------------------------------
//  Class Declaration
// ---------------------------------------------------------------------------

/**
 * @brief This class implements the root window control.
 * @ingroup peered
 */
class HOST_SW_API PeerEdMainWnd final : public finalcut::FWidget {
public:
    /**
     * @brief Initializes a new instance of the PeerEdMainWnd class.
     * @param widget 
     */
    explicit PeerEdMainWnd(FWidget* widget = nullptr) : FWidget{widget}
    {
        log_internal::SetInternalOutputStream(m_logWnd);

        // file menu
        m_fileMenuSeparator1.setSeparator();
        m_fileMenuSeparator2.setSeparator();
        m_saveSettingsItem.addAccelerator(FKey::Meta_s); // Meta/Alt + S
        m_saveSettingsItem.addCallback("clicked", this, [&]() { save(); });
        m_reloadSettingsItem.addAccelerator(FKey::Meta_r); // Meta/Alt + R
        m_reloadSettingsItem.addCallback("clicked", this, [&]() { g_pidLookups->reload(); m_wnd->loadListView(); });
        m_keyF2.addCallback("activate", this, [&]() { save(); });
        m_quitItem.addAccelerator(FKey::Meta_x); // Meta/Alt + X
        m_quitItem.addCallback("clicked", getFApplication(), &FApplication::cb_exitApp, this);
        m_keyF3.addCallback("activate", getFApplication(), &FApplication::cb_exitApp, this);
        m_keyF5.addCallback("activate", this, [&]() { g_pidLookups->reload(); m_wnd->loadListView(); LogInfoEx(LOG_HOST, "Loaded peer ID file: %s", g_iniFile.c_str()); });

        m_backupOnSave.setChecked();

        // help menu
        m_aboutItem.addCallback("clicked", this, [&]() {
            const FString line(2, UniChar::BoxDrawingsHorizontal);
            FMessageBox info("About", line + __PROG_NAME__ + line + L"\n\n"
                L"" + __BANNER__ + L"\n"
                L"Version " + __VER__ + L"\n\n"
                L"Copyright (c) 2017-2026 Bryan Biedenkapp, N2PLL and DVMProject (https://github.com/dvmproject) Authors." + L"\n"
                L"Portions Copyright (c) 2015-2021 by Jonathan Naylor, G4KLX and others", 
                FMessageBox::ButtonType::Ok, FMessageBox::ButtonType::Reject, FMessageBox::ButtonType::Reject, this);
            info.setCenterText();
            info.show();
        });
    }

private:
    friend class PeerEdApplication;

    LogDisplayWnd m_logWnd{this};
    PeerListWnd* m_wnd;

    FMenuBar m_menuBar{this};

    FMenu m_fileMenu{"&File", &m_menuBar};
    FMenuItem m_reloadSettingsItem{"&Reload", &m_fileMenu};
    FMenuItem m_saveSettingsItem{"&Save", &m_fileMenu};
    FMenuItem m_fileMenuSeparator2{&m_fileMenu};
    FCheckMenuItem m_saveOnCloseToggle{"Save on Close?", &m_fileMenu};
    FCheckMenuItem m_backupOnSave{"Backup Rules File?", &m_fileMenu};
    FMenuItem m_fileMenuSeparator1{&m_fileMenu};
    FMenuItem m_quitItem{"&Quit", &m_fileMenu};

    FMenu m_helpMenu{"&Help", &m_menuBar};
    FMenuItem m_aboutItem{"&About", &m_helpMenu};

    FStatusBar m_statusBar{this};
    FStatusKey m_keyF2{FKey::F2, "Save", &m_statusBar};
    FStatusKey m_keyF3{FKey::F3, "Quit", &m_statusBar};
    FStatusKey m_keyF5{FKey::F5, "Reload", &m_statusBar};

    /**
     * @brief 
     */
    void save()
    {
        if (m_backupOnSave.isChecked()) {
            std::string bakFile = g_iniFile + ".bak";
            LogInfoEx(LOG_HOST, "Backing up existing file %s to %s", g_iniFile.c_str(), bakFile.c_str());
            copyFile(g_iniFile.c_str(), bakFile.c_str());
        }

        g_pidLookups->commit(); 
    }

    /**
     * @brief Helper to copy one file to another.
     * @param src Source file.
     * @param dest Destination File.
     * @returns bool True, if file copied, otherwise false.
     */
    bool copyFile(const char *srcFilePath, const char* destFilePath)
    {
        std::ifstream src(srcFilePath, std::ios::binary);
        std::ofstream dest(destFilePath, std::ios::binary);
        dest << src.rdbuf();
        return src && dest;
    }

    /*
    ** Event Handlers
    */

    /**
     * @brief Event that occurs when the window is shown.
     * @param e Show Event
     */
    void onShow(FShowEvent* e) override
    {
        const auto& rootWidget = getRootWidget();

        int fullWidth = rootWidget->getWidth();
        if (fullWidth < MINIMUM_SUPPORTED_SIZE_WIDTH) {
            clearArea();
            ::fatal("screen resolution too small must be wider then %u characters, console width = %u", MINIMUM_SUPPORTED_SIZE_WIDTH, fullWidth);
        }

        int fullHeight = rootWidget->getHeight();
        if (fullHeight < MINIMUM_SUPPORTED_SIZE_HEIGHT) {
            clearArea();
            ::fatal("screen resolution too small must be taller then %u characters, console height = %u", MINIMUM_SUPPORTED_SIZE_HEIGHT, fullHeight);
        }

        int maxWidth = 77;
        if (rootWidget) {
            maxWidth = rootWidget->getClientWidth() - 3;
        }

        int maxHeight = PEER_LIST_HEIGHT;
        if (rootWidget) {
            maxHeight = rootWidget->getClientHeight() - 3;
        }

        m_wnd = new PeerListWnd(this);
        if (maxHeight - 21 < PEER_LIST_HEIGHT)
            maxHeight = PEER_LIST_HEIGHT + 21;

        m_wnd->setGeometry(FPoint{2, 2}, FSize{(size_t)(maxWidth - 1), (size_t)(maxHeight - 21)});

        m_wnd->setModal(false);
        m_wnd->show();

        m_wnd->raiseWindow();
        m_wnd->activateWindow();

        redraw();

        if (g_hideLoggingWnd) {
            const auto& rootWidget = getRootWidget();
            m_logWnd.setGeometry(FPoint{(int)(rootWidget->getClientWidth() - 81), (int)(rootWidget->getClientHeight() - 1)}, FSize{80, 20});

            m_logWnd.minimizeWindow();
        }
    }

    /**
     * @brief Event that occurs when the window is closed.
     * @param e Close Event
     */
    void onClose(FCloseEvent* e) override
    {
        // if we are saving on close -- fire off the file save event
        if (m_saveOnCloseToggle.isChecked()) {
            g_pidLookups->commit();
        }

        FApplication::closeConfirmationDialog(this, e);
    }
};

#endif // __PEERED_MAIN_WND_H__