//==============================================
//  copyright            : (C) 2003-2005 by Will Stokes
//==============================================
//  This program 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 2 of the License, or
//  (at your option) any later version.
//==============================================

//Systemwide includes
#include <qdir.h>
#include <qfile.h>
#include <qstring.h>
#include <qtextstream.h>
#include <qdom.h>

#if defined(Q_OS_WIN)
#include <stdlib.h>
#endif

//Projectwide includes
#include "configuration.h"
#include "settinggroup.h"
#include "../config.h"
#include "../backend/tools/xmlTools.h"
#include "../backend/tools/fileTools.h"
//==============================================
bool Configuration::constructSettingsDirectory()
{
  //PLATFORM_SPECIFIC_CODE
 
  //-----------------------------
  //Mac OSX requires no directories to be created
  #if defined(Q_OS_MACX)
  return true;
  //-----------------------------
  //Windows
  #elif defined(Q_OS_WIN)
  bool configDirMade = true;

  //attempt to get folder location using windows api, if this fails try hard coded path as a last resort
  QString folderLoc;
  if( !getWindowsFolderLocation(LOCAL_SETTINGS_APPLICATION_DATA,  folderLoc) )
  { 
    folderLoc = getenv("USERPROFILE") + QString("/Local Settings/Application Data"); 
  }
  QDir dataDir( folderLoc );    
  if(!dataDir.exists("Album Shaper"))
  {
    configDirMade = dataDir.mkdir("Album Shaper"); 
  }  
  return configDirMade;
  //-----------------------------
  //Unix/Linux/BSD
  #else
  bool configDirMade = true;
  QDir homeDir( QDir::homeDirPath() );
  if(!homeDir.exists(".albumShaper")) 
  { 
    configDirMade = homeDir.mkdir(".albumShaper"); 
  }
  return configDirMade; 
  #endif    
  //-----------------------------
}
//==============================================
Configuration::Configuration()
{
  //-----------------------------
  //Determine settings filename
  //-----------------------------

  //PLATFORM_SPECIFIC_CODE
  
  //Mac OS X
  #if defined(Q_OS_MACX)
  settingsFilename = QDir::homeDirPath() + QString("/Library/Preferences/net.sourceforge.albumshaper.xml");
  //----------------------------- 
  //Windows
  #elif defined(Q_OS_WIN)
  //attempt to get folder location using windows api, if this fails try hard coded path as a last resort
  QString tmp;
  if( !getWindowsFolderLocation(LOCAL_SETTINGS_APPLICATION_DATA,  tmp) )
  { 
    tmp = getenv("USERPROFILE") + QString("/Local Settings/Application Data"); 
  }
  settingsFilename = QDir::convertSeparators( tmp + "/Album Shaper/settings.xml" );
  //-----------------------------
  //Unix/Linux/BSD
  #else
  settingsFilename = QDir::homeDirPath() + QString("/.albumShaper/settings.xml");
  #endif
  //-----------------------------
 
  //no groups by default
  firstGroup = NULL;
  lastGroup = NULL;

  //no group selected by default
  curGroup = NULL;
}
//==============================================
Configuration::~Configuration()
{
  //delete all setting groups
  SettingGroup* cur = firstGroup;
  while(cur != NULL)
  {
    SettingGroup* next = cur->getNext();
    delete cur;
    cur = next;
  }
}
//==============================================
void Configuration::setString( QString group, QString key, QString value)
{
  //check if cached group has same name, if not find group, create it if group does not exist
  if(curGroup == NULL || curGroup->getName().compare(group) != 0)
  {
    curGroup = firstGroup;
    while(curGroup != NULL)
    {
      if(curGroup->getName().compare(group) == 0)
        break;
      curGroup = curGroup->getNext();
    }

    //if we have not found the group create it and add to list
    if(curGroup == NULL)
    {
      //create new group
      curGroup = new SettingGroup(group);

      //add group to list
      if(firstGroup == NULL)
        firstGroup = curGroup;
      else
        lastGroup->setNext(curGroup);
      lastGroup = curGroup;
    }
  }

  //set setting value
  curGroup->setValue(key, value);
}
//==============================================
void Configuration::setBool( QString group, QString key, bool val )
{
  setString( group, key, (val ? "1" : "0" ) );
}
//==============================================
void Configuration::setInt( QString group, QString key, int val )
{
  setString( group, key, QString("%1").arg(val) );
}
//==============================================
QString Configuration::getString(QString group, QString key)
{
  //check if cached group is correct group, if not find correct group
  if(curGroup == NULL || curGroup->getName().compare(group) != 0)
  {
    curGroup = firstGroup;
    while(curGroup != NULL)
    {
      if(curGroup->getName().compare(group) == 0)
        break;
      curGroup = curGroup->getNext();
    }

    //if we have not found the group return error value (-1)
    if(curGroup == NULL)
    {
      return "-1";
    }
  }

  //return setting value from group
  return curGroup->getValue(key);
}
//==============================================
void Configuration::resetSetting(QString group, QString key)
{
  //check if cached group is correct group, if not find correct group
  if(curGroup == NULL || curGroup->getName().compare(group) != 0)
  {
    curGroup = firstGroup;
    while(curGroup != NULL)
    {
      if(curGroup->getName().compare(group) == 0)
        break;
      curGroup = curGroup->getNext();
    }

    //if we have not found the group return error value (-1)
    if(curGroup == NULL)
    {
      return;
    }
  }

  //return setting value from group
  curGroup->resetSetting(key);
}
//==============================================
bool Configuration::getBool(QString group, QString key)
{
  return ( getString(group,key).compare("1") == 0 );
}
//==============================================
int Configuration::getInt(QString group, QString key)
{
  return getString(group,key).toInt();
}
//==============================================
float Configuration::getFloat(QString group, QString key)
{
  return getString(group,key).toFloat();
}
//==============================================
double Configuration::getDouble(QString group, QString key)
{
  return getString(group,key).toDouble();
}
//==============================================
void Configuration::removeGroup(QString group)
{  
  //iterate through groups, remove group once found
  SettingGroup* prev = NULL;
  curGroup = firstGroup;
  while(curGroup != NULL)
  {
    //found
    if(curGroup->getName().compare(group) == 0)
    {
      //keep handle on group for deletion purposes
      SettingGroup* temp = curGroup;

      //fix head if necessary
      if(curGroup == firstGroup)
        firstGroup = curGroup->getNext();
            
      //fix tail if necessary
      if(lastGroup == curGroup)
        lastGroup = prev;

      //splice out group
      if(prev != NULL)
        prev->setNext( curGroup->getNext() );                 
      
      //update curGroup pointer so valid
      curGroup = curGroup->getNext();

      //free group
      delete temp;
      temp = NULL;
      
      //done       
      return;
    }
    
    //update prev and cur pointers and move along
    prev = curGroup;
    curGroup = curGroup->getNext();        
  }  
}
//==============================================
bool Configuration::loadSettings()
{
  //-----------------------------------
  //attempt to load xml settings file and construct dom, if either action failes return false
  QFile settingsFile( settingsFilename );
  if( !settingsFile.open( IO_ReadOnly ) )
    return false;

  QDomDocument DOM;
  if( !DOM.setContent( &settingsFile ) )
    return false;

  settingsFile.close();

  //-----------------------------------
  //walk though DOM and look for setting nodes.
  //for each setting fetch, type, key, and value
  //walk through list of settings and find previous setting
  //if previous setting found replace value, otherwise add new setting to list
  QDomElement root = DOM.documentElement();
  QDomNode node = root.firstChild();

  while( !node.isNull() )
  {
    if( node.isElement() && node.nodeName() == "group" )
    {
      //find group name, if no name found then move on to next group
      QDomNamedNodeMap attributes = node.attributes();
      if(attributes.namedItem("name").isNull())
      {
        node = node.nextSibling();
        continue;
      }

      //create group if it does not already exist
      SettingGroup* loadedGroup = NULL;

      //last used group is the one we are looking for
      if(curGroup->getName().compare( attributes.namedItem("name").nodeValue()) == 0)
        loadedGroup = curGroup;
      //search list of groups
      else
      {
        SettingGroup* cur = firstGroup;
        while(cur != NULL)
         {
           //found it!
           if(cur->getName().compare( attributes.namedItem("name").nodeValue()) == 0)
           {
             loadedGroup = cur;
             break;
           }
          //nope, move on to next group
          cur = cur->getNext();
        }
      }
      //if group to be loaded is not found then create it
      if(loadedGroup == NULL)
      {
        loadedGroup = new SettingGroup( attributes.namedItem("name").nodeValue() );
        if(firstGroup == NULL)
          firstGroup = loadedGroup;
        else
          lastGroup->setNext(loadedGroup);
        lastGroup = loadedGroup;
      }

      loadedGroup->loadSettings(node);
    }
    //move on to next setting
    node = node.nextSibling();
  }
  //-----------------------------------
  //loading of settingings was successful
  return true;
}
//==============================================
bool Configuration::saveSettings()
{
  //create/open html file
  QFile file( settingsFilename );
  if(file.open(IO_WriteOnly))
  {
    //-----
    QTextStream stream;
    stream.setDevice( &file );
    stream.setEncoding( QTextStream::UnicodeUTF8 );
    
    //write header
    stream << "<settings app=\"Album Shaper\" version=\"" << ALBUMSHAPER_VERSION << "\">\n";

    //iterate over every group
    curGroup = firstGroup;
    while(curGroup != NULL)
    {
      curGroup->saveSettings( stream );
      curGroup = curGroup->getNext();
    }

    //end xml file
    stream << "</settings>\n";

    //success saving settings!
    file.close();
    return true;
  }

  //opening file for saving failed
  file.close();
  return false;
}
//==============================================
