//
//  Lol Engine
//
//  Copyright © 2010—2015 Sam Hocevar <sam@hocevar.net>
//
//  Lol Engine is free software. It comes without any warranty, to
//  the extent permitted by applicable law. You can redistribute it
//  and/or modify it under the terms of the Do What the Fuck You Want
//  to Public License, Version 2, as published by the WTFPL Task Force.
//  See http://www.wtfpl.net/ for more details.
//

#include <lol/engine-internal.h>

#include <cctype>

#if HAVE_UNISTD_H
#   include <unistd.h>
#endif

#if _WIN32
#   define WIN32_LEAN_AND_MEAN
#   include <direct.h>
#endif

namespace lol
{

namespace System
{

#if _WIN32
#   define SEPARATOR '\\'
#else
#   define SEPARATOR '/'
#endif

static array<String> data_dir;

void Init(int argc, char *argv[],
          String const &projectdir,
          String const &solutiondir,
          String const &sourcesubdir)
{
    using namespace std;

    msg::debug("project dir: “%s”\n", projectdir.C());
    msg::debug("solution dir: “%s”\n", solutiondir.C());
    msg::debug("source subdir: “%s”\n", sourcesubdir.C());

    /*
     * Retrieve binary directory, defaulting to no directory on Android
     * and emscripten, and the current directory on other platforms.
     */

#if __ANDROID__ || EMSCRIPTEN
    String binarydir = "";
#else
    String binarydir = ".";
    char *cwd = nullptr;

#   if HAVE_GETCWD
    cwd = getcwd(nullptr, 0);
#   elif HAVE__GETCWD || (_WIN32 && !_XBOX)
    cwd = _getcwd(nullptr, 0);
#   endif

    if (cwd)
    {
        binarydir = cwd;
        free(cwd);
    }

    binarydir += SEPARATOR;

    if (argc > 0)
    {
        char const *last_sep = strrchr(argv[0], SEPARATOR);
        if (last_sep)
            binarydir = String(argv[0], last_sep - argv[0] + 1);
    }
#endif

    bool got_rootdir = false;

    /*
     * If project dir and solution dir are set, add them to data; also
     * add current directory in case we were launched from another place.
     */

    if (!got_rootdir && projectdir.count() && solutiondir.count())
    {
        /* This data dir is for standalone executables */
        String rootdir = binarydir;
        if (rootdir.count() && rootdir.last() != SEPARATOR)
            rootdir += SEPARATOR;
        AddDataDir(rootdir);

        /* This data dir is for engine stuff */
        rootdir = solutiondir;
        if (rootdir.count() && rootdir.last() != SEPARATOR)
            rootdir += SEPARATOR;
        rootdir += "../src/"; /* FIXME: use SEPARATOR? */
        AddDataDir(rootdir);

        /* This data dir is for project-specific stuff */
        rootdir = projectdir;
        if (rootdir.count() && rootdir.last() != SEPARATOR)
            rootdir += SEPARATOR;
        AddDataDir(rootdir);

        got_rootdir = true;
    }

    /*
     * If no project dir, use the executable location as the starting point
     * to guess the data dir.
     */
    if (!got_rootdir)
    {
        /* First climb back the hierarchy to get to the engine root and
         * add a data dir for engine stuff. */
        String rootdir = binarydir;
        if (rootdir.count() && rootdir.last() != SEPARATOR)
            rootdir += SEPARATOR;
        for (int i = 1; i < sourcesubdir.count(); ++i)
        {
            if ((sourcesubdir[i] == SEPARATOR
                  && sourcesubdir[i - 1] != SEPARATOR)
                 || i == sourcesubdir.count() - 1)
                rootdir += "../";
        }
        rootdir += "src/";
        AddDataDir(rootdir);

        /* This data dir is for project-specific stuff */
        rootdir = binarydir;
        AddDataDir(rootdir);

        got_rootdir = true;
    }

    msg::debug("binary dir: “%s”\n", binarydir.C());
    for (int i = 0; i < data_dir.count(); ++i)
        msg::debug("data dir %d/%d: “%s”\n", i + 1, data_dir.count(),
                   data_dir[i].C());
}

/*
 * Data directory handling
 */

void AddDataDir(String const &dir)
{
    data_dir << dir;
}

array<String> GetPathList(String const &file)
{
    array<String> ret;

    for (int i = 0; i < data_dir.count(); ++i)
        ret << data_dir[i] + file;

    if (ret.count() == 0)
        ret << file;

    return ret;
}

} /* namespace System */

} /* namespace lol */