/*
 * This file is part of the Colobot: Gold Edition source code
 * Copyright (C) 2001-2023, Daniel Roux, EPSITEC SA & TerranovaTeam
 * http://epsitec.ch; http://colobot.info; http://github.com/colobot
 *
 * 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://gnu.org/licenses
 */

/**
 * \file app/main.cpp
 * \brief Entry point of application - main() function
 */

#include "common/config.h"

#include "app/app.h"
#include "app/signal_handlers.h"

#include "common/logger.h"
#include "common/make_unique.h"
#include "common/profiler.h"
#include "common/restext.h"
#include "common/version.h"

#include "common/resources/resourcemanager.h"

#include "common/system/system.h"
#if PLATFORM_WINDOWS
    #include "common/system/system_windows.h"
#endif

#if PLATFORM_WINDOWS
    #include <windows.h>
#endif

#include <memory>
#include <vector>
#include <boost/filesystem.hpp>

/**
\mainpage

Doxygen documentation of Colobot: Gold Edition project.

<b>Colobot</b> <i>(COLOnize with BOTs)</i> is a game combining elements of real time strategy (RTS)
and educational game, aiming to teach programming through entertainment. You are playing as an astronaut
on a journey with robot helpers to find a planet for colonization. It features a C++ and Java-like,
object-oriented language, CBOT, which can be used to program the robots available in the game.

The original version of the game was developed by [Epsitec](http://www.epsitec.ch/) and released in 2001.
Later, in 2005 another version named Ceebot was released. In March 2012, through attempts
by Polish Colobot fans, Epsitec agreed to release the source code of the game on GPLv3 license.
The license was given specifically to our community, <b>TerranovaTeam</b>,
part of <b>International Colobot Community (ICC)</b> (previously known as <i>Polish Portal of Colobot (PPC)</i>;
Polish: <i>Polski Portal Colobota</i>) with our website at http://colobot.info/.

\section Intro Introduction

The source code released by Epsitec was sparsely documented. This documentation, written from scratch,
will aim to describe the various components of the code.

Currently, the only documented classes are the ones written from scratch or the old ones rewritten
to match the new code.
In time, the documentation will be extended to cover every major part of the code.

\section Structure Code structure

The source code was split from the original all-in-one directory to subdirectories,
each containing one major part of the project.
The current layout is the following:
 - src/CBot - separate library with CBot language
 - src/app - class CApplication and everything concerned with SDL
 - src/common - shared structs, enums, defines, etc.; should not have any external dependencies
 - src/common/resources - filesystem management using PHYSFS library
 - src/common/system - system-dependent code such as displaying a message box, finding files, etc.
 - src/common/thread - wrapper classes for SDL threads
 - src/graphics/core - abstract interface of graphics device (abstract CDevice class)
 - src/graphics/engine - main graphics engine based on abstract graphics device; is composed
   of CEngine class and associated classes implementing the 3D engine
 - src/graphics/model - code related to loading/saving model files
 - src/graphics/opengl - concrete implementation of CDevice class in OpenGL: CGLDevice
 - src/graphics/d3d - in (far) future - perhaps a newer implementation in DirectX (9? 10?)
 - src/math - mathematical structures and functions
 - src/object - non-graphical game object logic, that is robots, buildings, etc.
 - src/level - main part of non-graphical game engine, that is loading levels etc.
 - src/level/parser - parser for loading/saving level files from format known as <i>scene files</i>
 - src/ui - 2D user interface (menu, buttons, check boxes, etc.)
 - src/sound - sound and music engine written using fmod library
 - src/physics - physics engine
 - src/script - link with the CBot library
*/

//! Entry point to the program
extern "C"
{

int main(int argc, char *argv[])
{
    CLogger logger; // single instance of logger
    logger.AddOutput(stderr);

    auto systemUtils = CSystemUtils::Create(); // platform-specific utils
    systemUtils->Init();

    CProfiler::SetSystemUtils(systemUtils.get());

    // Add file output to the logger
    std::string logFileName;
    #if DEV_BUILD
        logFileName = "log.txt";
    #else
        boost::filesystem::create_directories(systemUtils->GetSaveDir());
        logFileName = systemUtils->GetSaveDir() + "/log.txt";
    #endif
    FILE* logFile = fopen(logFileName.c_str(), "w");
    if (logFile)
        logger.AddOutput(logFile);
    else
        logger.Error("Failed to create log file, writing log to file disabled\n");


    // Workaround for character encoding in argv on Windows
    #if PLATFORM_WINDOWS
    int wargc = 0;
    wchar_t** wargv = CommandLineToArgvW(GetCommandLineW(), &wargc);
    if (wargv == nullptr)
    {
        logger.Error("CommandLineToArgvW failed\n");
        return 1;
    }

    std::vector<std::vector<char>> windowsArgs;
    for (int i = 0; i < wargc; i++)
    {
        std::wstring warg = wargv[i];
        std::string arg = CSystemUtilsWindows::UTF8_Encode(warg);
        std::vector<char> argVec(arg.begin(), arg.end());
        argVec.push_back('\0');
        windowsArgs.push_back(std::move(argVec));
    }

    auto windowsArgvPtrs = MakeUniqueArray<char*>(wargc);
    for (int i = 0; i < wargc; i++)
        windowsArgvPtrs[i] = windowsArgs[i].data();

    argv = windowsArgvPtrs.get();

    LocalFree(wargv);
    #endif

    logger.Info("%s starting\n", COLOBOT_FULLNAME);

    CSignalHandlers::Init(systemUtils.get());

    CResourceManager manager(argv[0]);

    // Initialize static string arrays
    InitializeRestext();
    InitializeEventTypeTexts();

    int code = 0;
    CApplication app(systemUtils.get()); // single instance of the application

    app.LoadEnvironmentVariables();

    ParseArgsStatus status = app.ParseArguments(argc, argv);
    if (status == PARSE_ARGS_FAIL)
    {
        systemUtils->SystemDialog(SystemDialogType::ERROR_MSG, "COLOBOT - Fatal Error", "Invalid commandline arguments!\n");
        return app.GetExitCode();
    }
    else if (status == PARSE_ARGS_HELP)
    {
        return app.GetExitCode();
    }

    if (! app.Create())
    {
        code = app.GetExitCode();
        if (code != 0 && !app.GetErrorMessage().empty())
        {
            systemUtils->SystemDialog(SystemDialogType::ERROR_MSG, "COLOBOT - Fatal Error", app.GetErrorMessage());
        }
        logger.Info("Didn't run main loop. Exiting with code %d\n", code);
        return code;
    }

    code = app.Run();

    logger.Info("Exiting with code %d\n", code);

    return code;
}

} // extern "C"
