/* BEGIN software license
 *
 * MsXpertSuite - mass spectrometry software suite
 * -----------------------------------------------
 * Copyright(C) 2009,...,2026 Filippo Rusconi
 *
 * http://www.msxpertsuite.org
 *
 * This file is part of the MsXpertSuite project.
 *
 * The MsXpertSuite project is the successor of the massXpert project. This
 * project now includes various independent modules:
 *
 * - MassXpert, model polymer chemistries and simulate mass spectrometric data;
 * - MineXpert, a powerful TIC chromatogram/mass spectrum viewer/miner;
 *
 * 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 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 *
 * END software license
 */


/////////////////////// Std includes
#include <iostream>


/////////////////////// Qt includes
#include <QApplication>
#include <QTranslator>
#include <QtGlobal>
#include <QTimer>
#include <QDebug>
#include <QFile>
#include <QStringList>


/////////////////////// Local includes
#include "nongui/globals.hpp"
#include "config.h"
#include "gui/ProgramWindow.hpp"
#include "gui/Application.hpp"


using std::cout;

namespace MsXpS
{
namespace MassXpert
{

  #define APPLICATION_NAME "MassXpert3"


void printGreetings();
void printHelp();
void printVersion();
void printConfig(const QString & = QString());


void
printHelp()
{
  QString help = QObject::tr("The following options are available:\n");
  help += QObject::tr("? | -h | --help : Display this help\n");
  help += QObject::tr("-v | --version : Display version info\n");
  help += QObject::tr("-c | --config : Display the software configuration\n");
  help += QObject::tr("-l | --license : Display the software license\n");
  help += QObject::tr("\n");

  cout << help.toStdString();
}


void
printGreetings()
{
  QString version(VERSION);


  QString greetings = QObject::tr("MassXpert3, version %1\n\n").arg(VERSION);

  greetings += QObject::tr("Type 'MassXpert3 --help' for help\n\n");

  greetings += QString(
    "%1 is Copyright 2016-2025 \n"
    "by Filippo Rusconi.\n\n"
    "%1 comes with ABSOLUTELY NO WARRANTY.\n"
    "%1 is free software, "
    "covered by the GNU General\n"
    "Public License Version 3 or later, "
    "and you are welcome to change it\n"
    "and/or distribute copies of it under "
    "certain conditions.\n"
    "Check the file COPYING in the distribution "
    "and/or the\n"
    "'Help/About(Ctrl+H)' menu item of the program.\n"
    "\nHappy MassXpert'ing!\n\n")
  .arg(APPLICATION_NAME);

  std::cout << greetings.toStdString();
}


void
printVersion()
{
  QString version = QString(
    "%1, version %2 -- "
    "Compiled against Qt, version %3\n")
  .arg(APPLICATION_NAME)
  .arg(VERSION)
  .arg(QT_VERSION_STR);

  std::cout << version.toStdString();
}


void
printConfig(const QString &execName)
{
  QString config = QString(
    "%1: "
    "Compiled with the following configuration:\n"
    "EXECUTABLE BINARY FILE: = %2\n"
    "PROJECT_INSTALL_BIN_DIR = %3\n"
    "PROJECT_INSTALL_LIB_DIR = %4\n"
    "PROJECT_INSTALL_DATA_DIR = %5\n"
    "PROJECT_INSTALL_DOC_DIR = %6\n")
  .arg(APPLICATION_NAME)
  .arg(execName)
  .arg(PROJECT_INSTALL_BIN_DIR)
  .arg(PROJECT_INSTALL_LIB_DIR)
  .arg(PROJECT_INSTALL_DATA_DIR)
  .arg(PROJECT_INSTALL_DOC_DIR);

  std::cout << config.toStdString();
}


} // namespace MassXpert
} // namespace MsXpS


void
myMessageOutputFormat(QtMsgType type,
                      const QMessageLogContext &context,
                      const QString &msg)
{
// Define ANSI color codes
#define RESET "\033[0m"
#define BLACK "\033[30m"
#define RED "\033[31m"
#define GREEN "\033[32m"
#define YELLOW "\033[33m"
#define BLUE "\033[34m"
#define MAGENTA "\033[35m"
#define CYAN "\033[36m"
#define WHITE "\033[37m"
#define BOLD "\033[1m"

  QByteArray localMsg  = msg.toLocal8Bit();
  const char *file     = context.file ? context.file : "";
  const char *function = context.function ? context.function : "";

  QString prefix;
  QString color;


  switch(type)
    {
      case QtInfoMsg:
        prefix = "INFO: ";
        color  = QString("%1").arg(GREEN);
        break;
      case QtWarningMsg:
        prefix = "WARNING: ";
        color  = QString("%1").arg(BLUE);
        break;
      case QtCriticalMsg:
        prefix = "CRITICAL: ";
        color  = QString("%1").arg(MAGENTA);
        break;
      case QtFatalMsg:
        prefix = "FATAL: ";
        color  = QString("%1").arg(RED);
        break;
      case QtDebugMsg:
        prefix = "DEBUG: ";
        color  = QString("%1").arg(YELLOW);
        break;
    }

  fprintf(stderr,
          "%s%s%s%s:%s%u%s\n%s\n%s======> %s%s\n\n",
          color.toLocal8Bit().constData(),
          prefix.toLocal8Bit().constData(),
          RESET,
          file,
          color.toLocal8Bit().constData(),
          context.line,
          RESET,
          function,
          color.toLocal8Bit().constData(),
          localMsg.constData(),
          RESET);

  fflush(stderr); // Ensure it actually appears
}


int
main(int argc, char **argv)
{
  // Set the debugging message formatting pattern.
  // qSetMessagePattern(QString("Debug: %{file}:%{line}-%{function}():
  // %{message}"));
  qInstallMessageHandler(myMessageOutputFormat);
  // qInfo() << "Installed the message handler.";

  QString project_name = APPLICATION_NAME;

  // Qt stuff starts here.
  MsXpS::MassXpert::Application application(
    argc, argv, project_name.toLatin1().data());
  application.setApplicationVersion(VERSION);
  application.setApplicationName(project_name);
  application.setApplicationDisplayName(project_name);

  // application.addLibraryPath(PappsoMS_ACTIVE_DIR_PATH);
  // qDebug() << "Library paths:" << application.libraryPaths();

  QCommandLineParser parser;

  parser.setApplicationDescription(
    "Modelling of polymer chemistries and simulation of mass spectra of "
    "(bio-)chemical experiments");

  QCommandLineOption helpOption(QStringList() << "h" << "help",
                                "Display this help.");
  parser.addOption(helpOption);

  QCommandLineOption versionOption(QStringList() << "v" << "version",
                                   "Display version info.");
  parser.addOption(versionOption);

  QCommandLineOption configOption(QStringList() << "c" << "config",
                                  "Display the software configuration.");
  parser.addOption(configOption);

  QCommandLineOption licenseOption(QStringList() << "l" << "license",
                                   "Display the software license.");
  parser.addOption(licenseOption);

  // Process the actual command line arguments given by the user
  parser.process(application);

  // Check if options are set
  bool isHelpOption    = parser.isSet(helpOption);
  bool isVersionOption = parser.isSet(versionOption);
  bool isConfigOption  = parser.isSet(configOption);
  bool isLicenseOption = parser.isSet(licenseOption);

  // Handle positional arguments (e.g., filenames)
  QStringList file_names;

  const QStringList positional_args = parser.positionalArguments();
  for(const QString &positional_arg : positional_args)
    {
      qDebug() << "Positional argument:" << positional_arg;
      file_names.append(positional_arg);
    }

  application.processEvents();

  if(isHelpOption)
    {
      MsXpS::MassXpert::printHelp();
      return 0;
    }

  if(isVersionOption)
    {
      MsXpS::MassXpert::printVersion();
      return 0;
    }

  if(isLicenseOption)
    {
      MsXpS::MassXpert::printGreetings();
      return 0;
    }

  if(isConfigOption)
    {
      MsXpS::MassXpert::printConfig();
      return 0;
    }

  // Only now do we manage to show the main window, since all
  // the options that do not require it have dealt with.

  MsXpS::MassXpert::ProgramWindow *main_window_p =
    new MsXpS::MassXpert::ProgramWindow(
      nullptr, project_name, "Main program window");

  // It is crucial that we set to the Application the pointer to the
  // ProgramWindow as soon as possible. Many functions, including in
  // windows allocated by ProgramWindow during its construction time
  // need to be able to call application.getProgramWindow().
  application.setProgramWindow(main_window_p);

  // qDebug() << "Set the pointer to ProgramWindow in Application to "
  //          << application.getProgramWindow();

  main_window_p->setupWindow();
  dynamic_cast<QWidget *>(main_window_p)->show();


  if(file_names.size())
    {
      for(int iter = 0; iter < file_names.size(); ++iter)
        {
          QString file_name = file_names.at(iter);
          QFileInfo file_info(file_name);
          if(file_info.exists())
            main_window_p->openSequence(file_name);
        }
    }
  else
    MsXpS::MassXpert::printGreetings();

  // Now set the default locale to american english.
  QLocale::setDefault(QLocale(QLocale::English, QLocale::UnitedStates));

  return application.exec();
}
// End of
// main(int argc, char **argv)
