//  ************************************************************************************************
//
//  qt-mvvm: Model-view-view-model framework for large GUI applications
//
//! @file      mvvm/view/mvvm/widgets/widgetutils.cpp
//! @brief     Implements class CLASS?
//!
//! @homepage  http://www.bornagainproject.org
//! @license   GNU General Public License v3 or higher (see COPYING)
//! @copyright Forschungszentrum Jülich GmbH 2020
//! @authors   Gennady Pospelov et al, Scientific Computing Group at MLZ (see CITATION, AUTHORS)
//
//  ************************************************************************************************

#include "mvvm/widgets/widgetutils.h"
#include "mvvm/utils/numericutils.h"
#include <QApplication>
#include <QColor>
#include <QDir>
#include <QFontMetrics>
#include <QLabel>
#include <QMainWindow>
#include <QSize>

namespace {

//! Calculates size of letter `M` for current system font settings.

QSize FindSizeOfLetterM()
{
    QFontMetrics fontMetric(QApplication::font());
    auto em = fontMetric.horizontalAdvance('M');
    auto fontAscent = fontMetric.ascent();
    return QSize(em, fontAscent);
}

const QString untitled_name = "Untitled";

} // namespace

QColor ModelView::Utils::RandomColor()
{
    auto rndm = []() -> int { return ModelView::Utils::RandInt(0, 255); };
    return QColor(rndm(), rndm(), rndm());
}

std::string ModelView::Utils::RandomNamedColor()
{
    return RandomColor().name().toStdString();
}

bool ModelView::Utils::IsWindowsHost()
{
#if defined(Q_OS_WIN)
    return true;
#else
    return false;
#endif
}

bool ModelView::Utils::IsMacHost()
{
#if defined(Q_OS_MAC)
    return true;
#else
    return false;
#endif
}

bool ModelView::Utils::IsLinuxHost()
{
#if defined(Q_OS_LINUX)
    return true;
#else
    return false;
#endif
}

QString ModelView::Utils::WithTildeHomePath(const QString& path)
{
    if (ModelView::Utils::IsWindowsHost())
        return path;

    static const QString homePath = QDir::homePath();

    QFileInfo fi(QDir::cleanPath(path));
    QString outPath = fi.absoluteFilePath();
    if (outPath.startsWith(homePath))
        outPath = QLatin1Char('~') + outPath.mid(homePath.size());
    else
        outPath = path;
    return outPath;
}

//! Project without projectDir will be "Untitled", modified project will be "*Untitled".
//! Project with projectDir in "/home/user/project1" will get title "project1".

QString ModelView::Utils::ProjectWindowTitle(const QString& project_dir, bool is_modified)
{
    auto pos = project_dir.lastIndexOf('/');
    auto project_name = (pos == -1) ? untitled_name : project_dir.mid(pos + 1);
    auto unsaved_status = is_modified ? QString("*") : QString();
    return unsaved_status + project_name;
}

int ModelView::Utils::WidthOfLetterM()
{
    return ModelView::Utils::SizeOfLetterM().width();
}

int ModelView::Utils::HeightOfLetterM()
{
    return ModelView::Utils::SizeOfLetterM().height();
}

QSize ModelView::Utils::SizeOfLetterM()
{
    static QSize result = FindSizeOfLetterM();
    return result;
}

int ModelView::Utils::SystemPointSize()
{
    return QApplication::font().pointSize();
}

QMainWindow* ModelView::Utils::FindMainWindow()
{
    for (auto widget : qApp->topLevelWidgets()) {
        if (auto result = dynamic_cast<QMainWindow*>(widget); result)
            return result;
    }
    return nullptr;
}

QString ModelView::Utils::ClickableText(const QString& text, const QString& tag)
{
    return QString("<a href=\"%1\">%2</a>").arg(tag.isEmpty() ? text : tag, text);
}

void ModelView::Utils::ScaleLabelFont(QLabel* label, double scale)
{
    QFont font = label->font();
    font.setPointSize(ModelView::Utils::SystemPointSize() * scale);
    label->setFont(font);
}

QStringList ModelView::Utils::toStringList(const std::vector<std::string>& vec)
{
    QStringList result;
    for (const auto& x : vec)
        result.push_back(QString::fromStdString(x));
    return result;
}

std::vector<std::string> ModelView::Utils::fromStringList(const QStringList& string_list)
{
    std::vector<std::string> result;
    for (const auto& x : string_list)
        result.push_back(x.toStdString());
    return result;
}

QByteArray ModelView::Utils::serialize(const QStringList& data)
{
    QByteArray byteArray;
    QDataStream out(&byteArray, QIODevice::WriteOnly);
    out << data;
    return byteArray;
}

QStringList ModelView::Utils::deserialize(const QByteArray& byteArray)
{
    QByteArray array = byteArray;
    QStringList result;
    QDataStream in(&array, QIODevice::ReadOnly);
    in >> result;
    return result;
}
