#include "stdafx.h"
#include "wb_updater.h"
#include <iostream>

using namespace grt;


Wb_updater::Wb_updater(bec::GRTManager *grtm)
:
  _grtm(grtm)
{
  if (!_grtm)
    return;

  working_dir(_grtm->get_tmp_dir());

  DictRef options= DictRef::cast_from(_grtm->get_grt()->get("/wb/options/options"));

  proxy_type(options.get_string("ProxyType"));
  proxy_server(options.get_string("ProxyServer"));
  proxy_userpwd(options.get_string("ProxyUserPwd"));

  std::ostringstream version;
  {
    GrtVersionRef ver= GrtVersionRef::cast_from(grtm->get_grt()->get("/wb/info/version"));
    version << ver->majorNumber() << "." << ver->minorNumber() << "." << ver->releaseNumber();
  }
  active_version(version.str());
  user_agent("mysql_workbench-agent/" + version.str());
}


bool Wb_updater::fetch_release_info()
{
  DictRef options= DictRef::cast_from(_grtm->get_grt()->get("/wb/options/options"));

  // versions file url (passing parameters to get proper versions file)
  {
    std::string edition= _active_config.substr(0, _active_config.find(' '));
    std::string rel_type= _active_config.substr(_active_config.find(' ') + 1);

    std::string url_= options.get_string("VersionsFileURL");
    url_ += "?config=" + _active_config
      + "&version=" + _active_version
      + "&revision=" + _active_revision
      + "&edition=" + edition
      + "&rel_type=" + rel_type
#ifdef _WIN32
      + "&os=win32&pack_type=msi"
#endif
      ;

    for (std::string::iterator i= url_.begin(), i_end= url_.end(); i != i_end; ++i)
      if (' ' == *i)
        *i= '_';
    url(url_);
  }

  return App_updater::fetch_release_info();
}


void Wb_updater::get_rel_names(std::list<std::string> &rel_names)
{
  App_updater::get_rel_names(rel_names);
}


void Wb_updater::get_mirrors(int rel_index, std::list<std::string> &mirrors)
{
  App_updater::get_mirrors(rel_index, mirrors);
}

std::string Wb_updater::result_filepath()
{
  std::string fn= App_updater::result_filepath();

#ifdef _WIN32
  // convert path from short to long
  CHAR csfn[MAX_PATH]= {0};
  std::copy(fn.begin(), fn.end(), csfn);
  WCHAR wsfn[MAX_PATH]= {0};
  WCHAR wlfn[MAX_PATH]= {0};
  MultiByteToWideChar(CP_UTF8, 0, csfn, -1, wsfn, MAX_PATH);
  DWORD dest_capacity= GetLongPathName(wsfn, wlfn, MAX_PATH);
  if ((dest_capacity > MAX_PATH) || (0 == dest_capacity))
    fn.clear();
  else
  {
    dest_capacity= WideCharToMultiByte(CP_UTF8, 0, wlfn, -1, csfn, MAX_PATH, NULL, NULL);
    if ((dest_capacity > MAX_PATH) || (0 == dest_capacity))
      fn.clear();
    else
      fn= csfn;
  }

  // replace: '/' -> '\'
  {
    size_t n= fn.find('/');
    while (std::string::npos != n)
    {
      fn.replace(n, 1, 1, '\\');
      n= fn.find('/');
    }
  }
#endif

  return fn;
}


bool Wb_updater::install()
{
  return App_updater::install();
}


void Wb_updater::start_download(int rel_index, int mirror_index)
{
  bec::GRTTask *task= new bec::GRTTask("Download new version", 
    _grtm->get_dispatcher(),
    sigc::bind<int, int>(
      sigc::mem_fun(this, &Wb_updater::download),
      rel_index, mirror_index));

  task->signal_message().connect(sigc::mem_fun(this, &Wb_updater::process_task_msg));
  task->signal_failed().connect(sigc::mem_fun(this, &Wb_updater::process_task_fail));
  task->signal_finished().connect(sigc::mem_fun(this, &Wb_updater::process_task_finish));

  _grtm->get_dispatcher()->add_task(task);
}


ValueRef Wb_updater::download(grt::GRT *grt, int rel_index, int mirror_index)
{
  _progress_state= 0.f;
  progress_cb(sigc::mem_fun(this, &Wb_updater::process_download_progress));
  if (!App_updater::download(rel_index, mirror_index))
  {
    const char *msg= cancelled() ?
      "Download was cancelled." :
      "Failed to download new version. For more details look into log files in temp dir.";
    process_download_error(-1, msg);
  }
  return grt::StringRef("");
}


void Wb_updater::cancel_download()
{
  App_updater::cancel_download();
}


int Wb_updater::process_download_error(long long err_no, const char *err_msg)
{
  std::ostringstream oss;
  oss << _("Error ") << err_no << _(": ") << err_msg << std::endl;
  _grtm->get_grt()->send_error(oss.str());
  return 0;
}


int Wb_updater::process_download_progress(double dltotal, double dlnow)
{
  if (dltotal == dlnow)
  {
    if (0 != dltotal && _progress_state != 1.f)
    {
      _grtm->get_grt()->send_info(_("Download finished."));
      _progress_state= 1.f;
    }
  }
  else
    _progress_state= (float)(dlnow / dltotal);

  std::ostringstream oss;
  oss << (int)(_progress_state*100) << "%";

  _grtm->get_grt()->send_progress(_progress_state, _(oss.str().c_str()));

  return 0;
}


void Wb_updater::process_task_msg(const grt::Message &msg)
{
  switch (msg.type)
  {
  case grt::WarningMsg:
  case grt::ErrorMsg:
  case grt::InfoMsg:
    _task_msg_cb(msg.type, msg.text);
    break;
  case grt::OutputMsg:
    std::cout << msg.text << std::endl;
  case grt::ProgressMsg:
    _task_progress_cb(msg.progress, msg.text);
    break;
  }
}


void Wb_updater::process_task_fail(const std::exception &error)
{
  _task_fail_cb(error.what());
}


void Wb_updater::process_task_finish(grt::ValueRef res)
{
  _grtm->get_grt()->send_info(grt::StringRef::cast_from(res));
  _grtm->perform_idle_tasks();
  _task_finish_cb();
}
