#include "stdafx.h"
#include "app_updater.h"
#include <sstream>
#include "tinyxml.h"


// ----------------------------------------------------------------------------
// App_updater::Release_info
// ----------------------------------------------------------------------------


bool App_updater::Release_info::is_new()
{
  std::istringstream av_iss(_updater->active_version());
  std::istringstream rv_iss(version);

  while (av_iss && rv_iss)
  {
    char buf[10];

    av_iss.getline(buf, sizeof(buf), '.');
    int av_num= 0;
    std::istringstream(buf) >> av_num;

    rv_iss.getline(buf, sizeof(buf), '.');
    int rv_num= 0;
    std::istringstream(buf) >> rv_num;

    if (rv_num > av_num)
      return true;
  }

  return false;
}


std::string App_updater::Release_info::full_name() const
{
  std::string res= description;
  if (!version.empty())
    res+= (res.empty() ? "" : " - ") + std::string("v") + version;
  if (!date.empty())
    res+= (res.empty() ? "" : " - ") + std::string("date:") + date;
  return res;
}


// ----------------------------------------------------------------------------
// App_updater::Release_info::Mirror_info
// ----------------------------------------------------------------------------


std::string App_updater::Release_info::Mirror_info::full_name() const
{
  std::string res= description;
  if (!url.empty())
    res+= (res.empty() ? "" : " - ") + url;
  return res;
}


// ----------------------------------------------------------------------------
// App_updater
// ----------------------------------------------------------------------------


App_updater::App_updater()
{
}


App_updater::~App_updater()
{
}


bool App_updater::fetch_release_info()
{
  _releases_info.clear();

  _fd.log_filepath(_working_dir.path() + "/versions.log");
  _fd.filepath(_working_dir.path() + "/versions.xml");
  _fd.url(_url);

  if (!_fd.download())
    return false;

  // parse downloaded versions.xml
  TiXmlDocument xml(_fd.filepath().c_str());
  if (!xml.LoadFile())
    return false;

  const TiXmlElement *el_releases;
  if ((el_releases= xml.FirstChildElement("RELEASES")))
  {
    const TiXmlElement *el_release= el_releases->FirstChildElement("RELEASE");
    while (el_release)
    {
      Release_info rel(this);

      el_release->QueryValueAttribute("Name", &rel.name);
      el_release->QueryValueAttribute("Description", &rel.description);
      el_release->QueryValueAttribute("Version", &rel.version);
      el_release->QueryValueAttribute("Date", &rel.date);
      el_release->QueryValueAttribute("NextReleaseDate", &rel.next_release_date);
      el_release->QueryValueAttribute("ReleaseNotes", &rel.release_notes);
      el_release->QueryValueAttribute("Type", &rel.type);
      el_release->QueryValueAttribute("Authorization", &rel.authorization);

      // mirrors
      const TiXmlElement *el_mirrors= el_release->FirstChildElement("MIRRORS");
      if (el_mirrors)
      {
        const TiXmlElement *el_mirror= el_mirrors->FirstChildElement("MIRROR");
        while (el_mirror)
        {
          Release_info::Mirror_info mirror;
          el_mirror->QueryValueAttribute("URL", &mirror.url);
          el_mirror->QueryValueAttribute("Description", &mirror.description);
          rel.mirrors.push_back(mirror);
          el_mirror= el_mirror->NextSiblingElement();
        }
      }

      _releases_info.push_back(rel);
      el_release= el_release->NextSiblingElement();
    }
  }
  else
    return false;

  return !_releases_info.empty();
}


void App_updater::get_rel_names(std::list<std::string> &rel_names)
{
  std::transform(_releases_info.begin(), _releases_info.end(), std::back_inserter(rel_names),
    &Release_info::get_full_name);
}


void App_updater::get_mirrors(int rel_index, std::list<std::string> &mirrors)
{
  Release_info::Mirrors_info &mirrors_= _releases_info.at(rel_index).mirrors;
  std::transform(mirrors_.begin(), mirrors_.end(), std::back_inserter(mirrors),
    &Release_info::Mirror_info::get_full_name);
}


int App_updater::rel_authorization(int rel_index)
{
  int res= 1;
  if (-1 < rel_index)
    res= _releases_info.at(rel_index).authorization;
  return res;
}


bool App_updater::install()
{
  // call: msiexec.exe /i "%1"
  // placed in wrapper to make use of platform specific facilities
  return true;
}


bool App_updater::do_download(int rel_index, int mirror_index)
{
  Release_info &rel= _releases_info.at(rel_index);

  _fd.filepath(_working_dir.path() + "/" + rel.name + "-" + rel.version + "." + rel.type);

  // if (-1 == mirror_index) then try all mirrors in sequence
  // otherwise try only specified one
  Release_info::Mirrors_info &mirrors= (mirror_index == -1) ? rel.mirrors : Release_info::Mirrors_info();
  if (mirror_index == -1)
    mirror_index= 0;
  else
    mirrors.push_back(rel.mirrors.at(mirror_index));

  for (Release_info::Mirrors_info::const_iterator i= mirrors.begin(), i_end= mirrors.end();
    i != i_end; ++i, ++mirror_index)
  {
    std::ostringstream log_filepath;
    log_filepath << _working_dir.path() << "/" << rel.name << "_mirror" << mirror_index << ".log";
    _fd.log_filepath(log_filepath.str());
    _fd.url(i->url);
    if (_fd.download())
    {
      _result_filepath= _fd.filepath();
      return true;
    }
  }

  return false;
}


bool App_updater::download(int rel_index, int mirror_index)
{
  bool res= do_download(rel_index, mirror_index);
  _fd.disconnect_progress_cb();
  return res;
}


void App_updater::cancel_download()
{
  _fd.cancel_download();
}
