#include "MountieMemory.h"
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>

MountieMemory * MountieMemory::the_one = NULL;

uid_t MountieMemory::my_uid = (uid_t)-1;
gid_t MountieMemory::my_gid = (gid_t)-1;
uid_t MountieMemory::home_uid = (uid_t)-1;
gid_t MountieMemory::home_gid = (gid_t)-1;

MountieMemory::MountieMemory()
 : settings(MountieMemory::MountieFileName(), QSettings::NativeFormat) {
   SetMyUser();
   return;
}

MountieMemory::MountieMemory(const MountieMemory & /* cpy */) {
   return;
}

MountieMemory::~MountieMemory() {
   return;
}

MountieMemory &
MountieMemory::operator =(const MountieMemory & /* cpy */) {
   return *this;
}

MountieMemory *
MountieMemory::Get() {
   if (the_one == NULL) {
      the_one = new MountieMemory;
   }
   return the_one;
}

QSize
MountieMemory::GetSize() {
   SetHomeUser();
   int width = settings.value("geometry/width", 800).toInt();
   int height = settings.value("geometry/height", 340).toInt();
   QSize rval(width, height);
   SetMyUser();
   return rval;
}

void
MountieMemory::SaveSize(const QSize & new_size) {
   SetHomeUser();
   settings.setValue("geometry/width", new_size.width());
   settings.setValue("geometry/height", new_size.height());
   settings.sync();
   SetMyUser();
}

bool
MountieMemory::GetStayOpen() {
   SetHomeUser();
   bool stay_open = settings.value("options/stay_open", false).toBool();
   SetMyUser();
   return stay_open;
}

void
MountieMemory::SaveStayOpen(bool new_stay_open) {
   SetHomeUser();
   settings.setValue("options/stay_open", new_stay_open);
   settings.sync();
   SetMyUser();
}

QString
MountieMemory::GetProgname() {
   SetHomeUser();
   QString progname = settings.value("options/progname", "").toString();
   SetMyUser();
   return progname;
}

void
MountieMemory::SaveProgname(QString new_progname) {
   SetHomeUser();
   settings.setValue("options/progname", new_progname);
   settings.sync();
   SetMyUser();
}

bool
MountieMemory::GetKeepHistory() {
   SetHomeUser();
   bool keep_history = settings.value("options/keep_history", true).toBool();
   SetMyUser();
   return keep_history;
}

void
MountieMemory::SaveKeepHistory(bool new_keep_history) {
   SetHomeUser();
   settings.setValue("options/keep_history", new_keep_history);
   if (! new_keep_history) {
      settings.remove("history");
   }
   settings.sync();
   SetMyUser();
}

void
MountieMemory::GetHistory(QComboBox * combo) {
   SetHomeUser();
   int current = settings.value("history/current", 0).toInt();
   MountieHistoryList hist;
   ReadHistory(hist);
   SetMyUser();
   combo->clear();
   combo->clearEditText();
   QStringList items;
   int size = hist.count();
   if (size > 0) {
      for (int i = 0; i < size; ++i) {
         items << hist[i].mountpoint;
      }
      combo->addItems(items);
      QDir dirname(items.at(current));
      if (! (dirname.exists() && (dirname.count() <= 2))) {

         // The current "current" value points to a directory already
         // mounted. Start at 0 and look for one not mounted.

         for (current = 0; current < items.size(); ++current) {
            QDir dirname(items.at(current));
            if (dirname.exists() && (dirname.count() <= 2)) {
               break;
            }
         }
         if (current == items.size()) {
            current = 0;
         }
      }
      combo->setCurrentIndex(current);
   }
}

void
MountieMemory::SaveHistory(QString mountpoint) {
   if (! Get()->GetKeepHistory()) {
      return;
   }
   SetHomeUser();
   MountieHistoryList hist;
   ReadHistory(hist);
   int current = FindHistory(hist, mountpoint);
   if (current == -1) {
      MountieHistory mh(mountpoint, 1);
      hist << mh;
   } else {
      hist[current].use_count += 1;
   }
   qSort(hist.begin(), hist.end());
   current = FindHistory(hist, mountpoint);
   WriteHistory(hist);
   settings.setValue("history/current", current);
   settings.sync();
   SetMyUser();
}

void
MountieMemory::ReadHistory(MountieHistoryList & hist) {
   int size = settings.beginReadArray("history");
   for (int i = 0; i < size; ++i) {
      settings.setArrayIndex(i);
      MountieHistory mh;
      mh.mountpoint = settings.value("mountpoint").toString();
      mh.use_count = settings.value("use_count").toInt();
      hist << mh;
   }
   settings.endArray();
}

void
MountieMemory::WriteHistory(MountieHistoryList & hist) {
   int size = hist.count();
   settings.beginWriteArray("history", size);
   for (int i = 0; i < size; ++i) {
      MountieHistory & mh = hist[i];
      settings.setArrayIndex(i);
      settings.setValue("mountpoint", mh.mountpoint);
      settings.setValue("use_count", mh.use_count);
   }
   settings.endArray();
}

int
MountieMemory::FindHistory(MountieHistoryList & hist, QString mountpoint) {
   int count = hist.count();
   for (int i = 0; i < count; ++i) {
      MountieHistory & mh = hist[i];
      if (mh.mountpoint == mountpoint) {
         return i;
      }
   }
   return -1;
}

QString
MountieMemory::MountieFileName() {
   struct stat homestat;
   char * homedir = getenv("HOME");
   QString rval;

   my_uid = getuid();
   my_gid = getgid();
   if (stat(homedir, &homestat) == 0) {
      home_uid = homestat.st_uid;
      home_gid = homestat.st_gid;
   }
   SetHomeUser();
   rval.append(homedir);
   if (! rval.endsWith('/')) {
      rval.append('/');
   }
   rval.append(".mountierc");
   return rval;
}

void
MountieMemory::SetHomeUser() {
   if ((my_uid == 0) && (home_uid != 0)) {
      setegid(home_gid);
      seteuid(home_uid);
   }
}

void
MountieMemory::SetMyUser() {
   if ((my_uid == 0) && (home_uid != 0)) {
      seteuid(my_uid);
      setegid(my_gid);
   }
}
