#include "stdafx.h"
#include "addon_uninstaller.h"
#include <fstream>


Addon_uninstaller::Addon_uninstaller()
{
}


Addon_uninstaller::~Addon_uninstaller()
{
}


void Addon_uninstaller::do_ensure_valid_state(std::string &err)
{
  Addon_proc::do_ensure_valid_state(err);

  if (!err.empty())
    return;
  else if (!_installed_addons)
    err= "Installed addons were not set.";
  else if (_guid.empty())
    err= "GUID was not set.";
}


void Addon_uninstaller::do_execute()
{
  uninstall(_guid);
}


void Addon_uninstaller::uninstall(const std::string &guid)
{
  std::string version;
  Addon *addon = _installed_addons->find(guid, version, version);
  if (!addon)
    _log->throw_err("Failed to find addon: " + guid + ".");

  // check if dependent addons exist
  {
    Addons_list dependent_addons;
    _installed_addons->get_dependent_addons(addon, dependent_addons);
    if (!dependent_addons.empty())
    {
      std::string msg= "Failed to uninstall addon: " + addon->full_name() + ".\nFollowing dependent addons must be uninstalled first:";
      for (Addons_list::const_iterator i= dependent_addons.begin(), i_end= dependent_addons.end(); i != i_end; ++i)
        msg +=  "\n" + (*i)->full_name();
      _log->throw_err(msg);
    }
  }

  // remove files/folders
  {
    File install_log_file= _installed_addons->storage_dir().path() + "/log/" + addon->install_log_filename();

    std::list<File_dir> folders;
    std::list<File> files;

    // load install log
    {
      std::ifstream ifs(install_log_file.path().c_str());
      std::string filepath;
      while (std::getline(ifs, filepath, '\n'))
      {
        bool is_folder= ('/' == *filepath.rbegin());
        if (is_folder)
          folders.push_back(filepath);
        else
          files.push_back(filepath);
      }
    }

    // remove manifest & install_log files from installed addons dir
    files.push_back(_installed_addons->storage_dir().path() + "/" + addon->manifest_filename());
    files.push_back(install_log_file);

    for (File_list::iterator i= files.begin(), i_end= files.end(); i != i_end; ++i)
      if (i->valid())
        (void)i->remove(); // TODO: make the list of files that failed to remove
    for (File_dir_list::iterator i= folders.begin(), i_end= folders.end(); i != i_end; ++i)
      if (i->valid())
        (void)i->remove(false); // TODO: make the list of folders that failed to remove
  }

  std::string msg= addon->full_name();
  _installed_addons->remove(addon);
  _log->push_info(msg);
}
