//  ************************************************************************************************
//
//  BornAgain: simulate and fit reflection and scattering
//
//! @file      App/AppOptions.cpp
//! @brief     Implements class ProgramOptions.
//!
//! @homepage  http://www.bornagainproject.org
//! @license   GNU General Public License v3 or higher (see COPYING)
//! @copyright Forschungszentrum Jülich GmbH 2018
//! @authors   Scientific Computing Group at MLZ (see CITATION, AUTHORS)
//
//  ************************************************************************************************

#include "App/AppOptions.h"
#include "GUI/Model/Util/Path.h"
#include <QApplication>
#include <QMessageBox>
#include <QStringList>
#include <boost/program_options/config.hpp>
#include <boost/program_options/parsers.hpp>
#include <fstream>
#include <iostream>

namespace {

//! Converts string "1600x1000" to QSize(1600, 1000)
QSize windowSize(const QString& size_string)
{
    QStringList list = size_string.split("x");

    if (list.size() != 2)
        return QSize();

    return QSize(list[0].toInt(), list[1].toInt());
}

//! Returns true if windows size makes sence.
bool isValid(const QSize& win_size)
{
    return win_size.width() > 640 && win_size.height() > 480;
}

void exitWithGuiMessage(const QString msg)
{
    int argc = 0;
    QApplication a(argc, nullptr);
    QMessageBox msgBox;
    msgBox.setText(msg);
    msgBox.exec();
    exit(-1);
}

} // namespace

ApplicationOptions::ApplicationOptions(int argc, char** argv)
{
    m_options.add_options()("help,h", "print help message and exit");
    m_options.add_options()("version,v", "print version and exit");
    m_options.add_options()("with-debug", "run application with debug printout");
    m_options.add_options()("geometry", bpo::value<std::string>(),
                            "Main window geometry, e.g. 1600x1000");
    m_options.add_options()("project-file", bpo::value<std::string>(), "project file");
    m_positional_options.add("project-file", -1);
    parseCommandLine(argc, argv);

    processOptions();
}

bool ApplicationOptions::find(std::string name) const
{
    return m_variables_map.count(name);
}

//! parse command line arguments

void ApplicationOptions::parseCommandLine(int argc, char** argv)
{
    // parsing command line arguments
    try {
        // if positional option description is empty, no command line arguments
        // without '--' or '-' will be accepted
        // 'store' populates the variable map
        bpo::store(bpo::command_line_parser(argc, argv)
                       .options(m_options)
                       .positional(m_positional_options)
                       .run(),
                   m_variables_map);
        // bpo::store(bpo::parse_command_line(argc, argv, m_options), m_variables_map);

        // 'notify' raises any errors encountered
        bpo::notify(m_variables_map);

    } catch (std::exception& e) {
        std::stringstream s;
        s << "BornAgain was launched with invalid command line option.\n"
          << "Parser error message: " << e.what() << ".\n"
          << "Available options:\n"
          << m_options << "\n";
        exitWithGuiMessage(QString::fromStdString(s.str()));
    }
}

void ApplicationOptions::processOptions()
{
    if (m_variables_map.count("help")) {
        std::cout << "BornAgain Graphical User Interface" << std::endl;
        std::cout << m_options << std::endl;
        exit(0);
    }

    else if (m_variables_map.count("version")) {
        std::cout << "BornAgain-" << GUI::Path::getBornAgainVersionString().toStdString()
                  << std::endl;
        exit(0);
    }

    else if (m_variables_map.count("geometry")) {
        if (!isValid(mainWindowSize()))
            exitWithGuiMessage("Wrong window size, try --geometry=1600x900\n");
    }
}

QSize ApplicationOptions::mainWindowSize() const
{
    QString size_str = QString::fromStdString(m_variables_map["geometry"].as<std::string>());
    return windowSize(size_str);
}

QString ApplicationOptions::projectFile() const
{
    if (find("project-file"))
        return QString::fromStdString(m_variables_map["project-file"].as<std::string>());
    return {};
}
