/*
 * This file is part of smolbote. It's copyrighted by the contributors recorded
 * in the version control history of the file, available from its original
 * location: https://neueland.iserlohn-fortress.net/gitea/aqua/smolbote
 *
 * SPDX-License-Identifier: GPL-3.0
 */

#include "configuration.h"
#include <QStandardPaths>
#include <fstream>
#include <boost/algorithm/string/predicate.hpp>
#include <iostream>
#include <QCoreApplication>
#include "config.h"

namespace po = boost::program_options;

inline std::string defaultUserConfigLocation()
{
#ifdef CONFIG_PATH_CONFIG
    return CONFIG_PATH_CONFIG;
#else
    // try to locate an existing config
    QString path = QStandardPaths::locate(QStandardPaths::ConfigLocation, "smolbote/smolbote.cfg");

    // it's possible there is no config, so set the path properly
    if(path.isEmpty())
        path = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + "/smolbote/smolbote.cfg";

    return path.toStdString();
#endif
}

Configuration::Configuration(int argc, char **argv, const std::string &path, QObject *parent)
    : QObject(parent)
    , m_homePath(QStandardPaths::writableLocation(QStandardPaths::HomeLocation).toStdString())
{
    configuration_desc.add_options()
        ("browser.stylesheet", po::value<std::string>())
        ("browser.iconTheme", po::value<std::string>(), "Icon theme")
        ("browser.locale", po::value<std::string>(), "Set Qt localization.")
        ("browser.translation", po::value<std::string>(), "Set application localization.")

        // sessions
        ("browser.session.path", po::value<std::string>()->default_value(CONFIG_PATH_SESSION))

#ifdef CONFIG_USEBREAKPAD
        ("browser.crash.path", po::value<std::string>()->default_value(CONFIG_PATH_CRASHDUMP))
        ("browser.crash.handler", po::value<std::string>()->default_value(CONFIG_PATH_CRASHHANDLER))
#endif

        // main window ui
        ("mainwindow.height", po::value<int>()->default_value(720))
        ("mainwindow.width", po::value<int>()->default_value(1280))
        ("mainwindow.maximized", po::value<bool>()->default_value(true))
        ("mainwindow.title", po::value<std::string>()->default_value(CONFIG_POI_NAME))

        // main window shortcuts
        ("mainwindow.shortcuts.saveSession", po::value<std::string>()->default_value("Ctrl+S,S"))
        ("mainwindow.shortcuts.openSession", po::value<std::string>()->default_value("Ctrl+S,O"))

        ("mainwindow.shortcuts.newGroup", po::value<std::string>()->default_value(CONFIG_SHORTCUT_WINDOW_NEWGROUP))
        ("mainwindow.shortcuts.newWindow", po::value<std::string>()->default_value(CONFIG_SHORTCUT_WINDOW_NEWWINDOW))

        ("mainwindow.shortcuts.about", po::value<std::string>()->default_value(CONFIG_SHORTCUT_WINDOW_ABOUT))
        ("mainwindow.shortcuts.quit", po::value<std::string>()->default_value(CONFIG_SHORTCUT_WINDOW_QUIT))

        ("mainwindow.shortcuts.search", po::value<std::string>()->default_value(CONFIG_SHORTCUT_WINDOW_SEARCH))
        ("mainwindow.shortcuts.tileWindows", po::value<std::string>()->default_value(CONFIG_SHORTCUT_SUBWINDOW_TILE))
        ("mainwindow.shortcuts.cascadeWindows", po::value<std::string>()->default_value(CONFIG_SHORTCUT_SUBWINDOW_CASCADE))

        // navigation
        ("navigation.movable", po::value<bool>()->default_value(false))
        ("navigation.shortcuts.back", po::value<std::string>()->default_value(CONFIG_SHORTCUT_NAVIGATION_BACK))
        ("navigation.shortcuts.backMenu", po::value<std::string>()->default_value(CONFIG_SHORTCUT_NAVIGATION_BACKMENU))
        ("navigation.shortcuts.forward", po::value<std::string>()->default_value(CONFIG_SHORTCUT_NAVIGATION_FORWARD))
        ("navigation.shortcuts.forwardMenu", po::value<std::string>()->default_value(CONFIG_SHORTCUT_NAVIGATION_FORWARDMENU))
        ("navigation.shortcuts.refresh", po::value<std::string>()->default_value(CONFIG_SHORTCUT_NAVIGATION_REFRESH))
        ("navigation.shortcuts.reload", po::value<std::string>()->default_value(CONFIG_SHORTCUT_NAVIGATION_RELOAD))
        ("navigation.shortcuts.home", po::value<std::string>()->default_value(CONFIG_SHORTCUT_NAVIGATION_HOME))

        // address bar
        ("addressbar.shortcuts.focus", po::value<std::string>()->default_value(CONFIG_SHORTCUT_ADDRESS_FOCUS))
        ("addressbar.shortcuts.menu", po::value<std::string>()->default_value(CONFIG_SHORTCUT_ADDRESS_MENU))

        // subwindow
        ("subwindow.shortcuts.menu", po::value<std::string>()->default_value(CONFIG_SHORTCUT_SUBWINDOW_MENU))
        ("subwindow.shortcuts.new", po::value<std::string>()->default_value(CONFIG_SHORTCUT_SUBWINDOW_NEWTAB))
        ("subwindow.shortcuts.close", po::value<std::string>()->default_value(CONFIG_SHORTCUT_SUBWINDOW_CLOSETAB))
        ("subwindow.shortcuts.restoreTab", po::value<std::string>()->default_value("Ctrl+Shift+T"))
        ("subwindow.shortcuts.left", po::value<std::string>()->default_value(CONFIG_SHORTCUT_SUBWINDOW_TABLEFT))
        ("subwindow.shortcuts.moveLeft", po::value<std::string>()->default_value(CONFIG_SHORTCUT_SUBWINDOW_MOVETABLEFT))
        ("subwindow.shortcuts.right", po::value<std::string>()->default_value(CONFIG_SHORTCUT_SUBWINDOW_TABRIGHT))
        ("subwindow.shortcuts.moveRight", po::value<std::string>()->default_value(CONFIG_SHORTCUT_SUBWINDOW_MOVETABRIGHT))
        ("subwindow.shortcuts.fullscreen", po::value<std::string>()->default_value(CONFIG_SHORTCUT_SUBWINDOW_FULLSCREEN))

        // Filter settings
        ("filter.hosts", po::value<std::string>()->default_value(CONFIG_PATH_FILTER))
        ("filter.adblock", po::value<std::string>())
        ("filter.header", po::value<std::vector<std::string>>())
//        ("filter.cookies.block.all", po::value<bool>()->default_value(false))
//        ("filter.cookies.block.thirdParty", po::value<bool>()->default_value(true))
//        ("filter.cookies.path", po::value<std::string>()->default_value("~/.config/smolbote/cookies.d"))

        // Plugin settings
        ("plugins.path", po::value<std::string>()->default_value(CONFIG_PATH_PLUGINS))

        // Profile settings
        // default profile name the browser should use; "" is off-the-record
        ("profile.default", po::value<std::string>()->default_value(CONFIG_PROFILE_DEFAULT))
        ("profile.path", po::value<std::string>()->default_value(CONFIG_PATH_PROFILES))
        ("profile.search", po::value<std::string>()->default_value(CONFIG_PROFILE_DEFAULT_SEARCH))
        ("profile.homepage", po::value<std::string>()->default_value(CONFIG_PROFILE_DEFAULT_HOMEPAGE))
        ("profile.newtab", po::value<std::string>()->default_value(CONFIG_PROFILE_DEFAULT_NEWTAB))

        // Bookmark settings
        ("bookmarks.path", po::value<std::string>()->default_value(CONFIG_PATH_BOOKMARKS))
        ("bookmarks.shortcut", po::value<std::string>()->default_value(CONFIG_SHORTCUT_WINDOW_BOOKMARKS))

        // Downloads settings
        ("downloads.path", po::value<std::string>()->default_value(CONFIG_PATH_DOWNLOADS))
        ("downloads.shortcut", po::value<std::string>()->default_value(CONFIG_SHORTCUT_WINDOW_DOWNLOADS))
        ;

    // po::store will only overwrite values that are default, so:
    // 1. parse command line
    {
        auto cmd = po::command_line_parser(argc, argv);
        cmd.allow_unregistered();
        cmd.options(configuration_desc);
        po::store(cmd.run(), vm);
    }
    // 2. parse config file
    {
        std::ifstream f(path, std::ifstream::in);
        // parse_config_file(file, options_description, allow_unregistered)
        po::store(po::parse_config_file(f, configuration_desc, true), vm);
    }
}

QHash<QString, QString> Configuration::section(const std::string &prefix) const
{
    QHash<QString, QString> v;
    for(auto &s : configuration_desc.options()) {
        if(boost::starts_with(s->long_name(), prefix)) {
            v[s->long_name().c_str()] = QString::fromStdString(value<std::string>(s->long_name().c_str()).value());
        }
    }

    return v;
}