// src/global_preferences.cc - Copyright 2005, 2006, University
//               of Padova, dept. of Pure and Applied
//               Mathematics
//
// This file is part of SGPEMv2.
//
// This 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.
//
// SGPEMv2 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 SGPEMv2. If not, see http://www.gnu.org/licenses/.


#include "gettext.h"

#include <glib/gstdio.h>
#include <glibmm/miscutils.h>

#include <sgpemv2/config.h>
#include <sgpemv2/global_preferences.hh>
#include <sgpemv2/key_file.hh>
#include <sgpemv2/string_utils.hh>

// Do not include in header file:
#include <sgpemv2/templates/singleton.tcc>

#include <sstream>

#ifdef _MSC_VER
  #include <shlobj.h>
#endif

using namespace sgpem;

// Explicit template instantiation to allow to export symbols from the DSO.
template class sgpem::Singleton<GlobalPreferences>;

GlobalPreferences::GlobalPreferences()
    : _mod_dirs(1, PLUGDIR), _pol_dirs(1, POLDIR), _speed(1000)
{}


Glib::ustring
GlobalPreferences::get_preferences_dir() const
{
  using namespace Glib;
  // windows-specific part, i don't use ifdef WIN32 since I'm not sure how
  // it will behave on MinGW/Cygwin...
#ifdef _MSC_VER
  TCHAR raw_path[MAX_PATH];

  if(SUCCEEDED(SHGetFolderPath(NULL,
               CSIDL_APPDATA,
               nullptr,
               SHGFP_TYPE_CURRENT,
               raw_path)))
  {
    // if UNICODE, characters are 16bit, otherwise plain bytes
#  ifdef UNICODE
    std::wstring path(raw_path);
#  else
    std::string path(raw_path);
#  endif

    path += TEXT("\\sgpemv2");

    // Create "Application Data\sgpemv2". if not present,
    // otherwise it is a no-op
    CreateDirectory(path.c_str(), nullptr);

    // if UNICODE, we need to convert to utf-8
    // I'm not sure if this part is OK, anyway...
#  ifdef UNICODE
    char raw_path_utf[MAX_PATH];

    WideCharToMultiByte(CP_UTF8, 0, path.c_str(), -1, raw_path_utf, MAX_PATH, nullptr, nullptr);

    return Glib::ustring(raw_path_utf);
#  else
    // no UNICODE, simply return plain string
    return path;
#  endif //~UNICODE
    }
    else
        throw FileError(FileError::FAILED, _("Unable to obtain Application Data directory"));

#else

  const ustring dir = get_home_dir() + G_DIR_SEPARATOR_S + ".sgpemv2";
  if(!file_test(dir, FILE_TEST_IS_DIR))
    {
      const int err = g_mkdir(dir.c_str(), 0755);
      if(err != 0)
        throw FileError(FileError::FAILED, g_strerror(err));
    }
  return dir;

#endif //~_MSC_VER
}


Glib::ustring
GlobalPreferences::get_config_filename() const
{
  const Glib::ustring filename = get_preferences_dir() + G_DIR_SEPARATOR_S + Glib::ustring("sgpemrc");
  return filename;
}

GlobalPreferences::DirVector&
GlobalPreferences::get_policy_dirs()
{
  return _pol_dirs;
}

GlobalPreferences::DirVector&
GlobalPreferences::get_plugin_dirs()
{
  return _mod_dirs;
}

int
GlobalPreferences::get_speed()
{
  return _speed;
}

int
GlobalPreferences::set_speed(int new_speed)
{
  int old_speed = _speed;
  _speed = new_speed;
  return old_speed;
}

const Glib::ustring
GlobalPreferences::get_schedulable_color(Schedulable::state st) const
{
  switch(st)
  {
  case Schedulable::state_running:
    return "ForestGreen";
  case Schedulable::state_ready:
    return "GoldenRod";
  case Schedulable::state_blocked:
    return "red";
  case Schedulable::state_terminated:
    return "DarkSlateGray";
  case Schedulable::state_future:
    return "Gray";
  default:
    return "black";
  }
}

const Glib::ustring
GlobalPreferences::get_request_color(Request::state st) const
{
  switch(st)
  {
  case Request::state_allocated:
    return "ForestGreen";
  case Request::state_allocable:
    return "GoldenRod";
  case Request::state_unallocable:
    return "red";
  case Request::state_exhausted:
    return "DarkSlateGray";
  case Request::state_future:
    return "Gray";
  default:
    return "black";
  }
}

void
GlobalPreferences::write_configrc()
{
  KeyFile kf;

  key_file_write(kf);
  kf.file_write(get_config_filename());
}

void
GlobalPreferences::load_configrc()
{
  KeyFile kf;

  kf.file_read(get_config_filename());
  key_file_read(kf);
}


void
GlobalPreferences::key_file_read(KeyFile& kf)
{

  _mod_dirs.clear();
  _pol_dirs.clear();
  std::vector<Glib::ustring>  old_mod_dirs(1, PLUGDIR);
  std::vector<Glib::ustring>  old_pol_dirs(1, POLDIR);
  _mod_dirs = old_mod_dirs;
  _pol_dirs = old_pol_dirs;


  // read speed
  {
    int new_speed = 1000; // use a default value
    const Glib::ustring* val = kf.search_value(Glib::ustring("speed"));
    if (val)
    {
      new_speed = string_to<int>(*val);
      set_speed(new_speed);
    }
  }
  // read modules directories
  {
    const Glib::ustring* val = kf.search_value(Glib::ustring("modules-dir-number"));
    if (val)
    {
      std::istringstream istr(*val);
      int n;
      istr >> n;
      for (int i = 1; i <= n; i++)
      {
        std::ostringstream ostr;
        ostr << "modules-dir-" << i;
        Glib::ustring key(ostr.str());
        val = kf.search_value(key);
        if (val && *val != _mod_dirs[0])
        {
          // add_modules_dir(*val);
          _mod_dirs.push_back(*val);
        }
      }
    }
 }

  // read policies directories
  {
    const Glib::ustring* val = kf.search_value(Glib::ustring("policies-dir-number"));
    if (val)
    {
      std::istringstream istr(*val);
      int n;
      istr >> n;
      for (int i = 1; i <= n; i++)
      {
        std::ostringstream ostr;
        ostr << "policies-dir-" << i;
        Glib::ustring key(ostr.str().c_str());
        val = kf.search_value(key);
        if (val && *val != _pol_dirs[0])
        {
          // add_policies_dir(*val);
          _pol_dirs.push_back(*val);
        }
      }
    }
  }


}

void
GlobalPreferences::key_file_write(KeyFile& kf)
{
  // write speed
  {
    Glib::ustring key("speed");
    Glib::ustring value;
    to_string<int>(_speed, value);
    kf.insert_key_value(key, value);
  }

  // add modules directories
  {
    /*
    GlobalPreferences::dir_iterator iter=_globalPreferences.modules_dir_begin();
    */
    DirVectorConstIt iter = _mod_dirs.begin();
    DirVectorConstIt end  = _mod_dirs.end();
    int n = 0;
    while (iter != end)
    {
      std::ostringstream ostr;
      n++;
      ostr << "modules-dir-" << n; // << std::ends;
      Glib::ustring key(ostr.str().c_str());
      kf.insert_key_value(key, (*iter));
      ++iter;
    }
    Glib::ustring key("modules-dir-number");
    std::ostringstream ostr;
    ostr << n << std::ends;
    Glib::ustring value(ostr.str().c_str());
    kf.insert_key_value(key, value);
  }
  // add policies directories
  {
    /*
        GlobalPreferences::dir_iterator iter=_globalPreferences.policies_dir_begin();
       */
    DirVectorConstIt iter = _pol_dirs.begin();
    DirVectorConstIt end  = _pol_dirs.end();
    int n = 0;
    while (iter != end)
    {
      std::ostringstream ostr;
      n++;
      ostr << "policies-dir-" << n; // << std::ends;
      Glib::ustring key(ostr.str().c_str());
      kf.insert_key_value(key, (*iter));
      ++iter;
    }
    Glib::ustring key("policies-dir-number");
    std::ostringstream ostr;
    ostr << n << std::ends;
    Glib::ustring value(ostr.str().c_str());
    kf.insert_key_value(key, value);
  }
}


