/*! @file

    @id $Id$
*/
//       1         2         3         4         5         6         7         8
// 45678901234567890123456789012345678901234567890123456789012345678901234567890

#include <ui_settings.h>
#include <QtWebKit/QWebSettings>
#include <QtCore/QSettings>
#include <QtCore/QMap>
#include <QtCore/QList>
#include <QtGui/QLineEdit>

#include <cassert>
#include <QtCore/QDebug>
#ifndef LOG
#define LOG qDebug()<<__PRETTY_FUNCTION__
#endif

class Settings: public QDialog, protected Ui::Settings {

    Q_OBJECT;

  public:

    typedef QMap<QString, QVariant> MimeTypes;
    typedef QMap<QString, QVariant> SearchEngines;

  Q_SIGNALS:

    void newSettings();

  public:

    Settings(MimeTypes mimetypes, QWidget* p=0,
             QSettings* settings=0, bool autoWrite=true):
        QDialog(p), _settings(settings),
        _autoWrite(autoWrite), _mimetypes(mimetypes) {
      
      setupUi(this);

      // Web Attributes
      _attributes[QWebSettings::AutoLoadImages] =
        _settingAutoLoadImages;
      _attributes[QWebSettings::DnsPrefetchEnabled] =
        _settingDnsPrefetchEnabled;
      _attributes[QWebSettings::JavascriptEnabled] =
        _settingJavascriptEnabled;
      _attributes[QWebSettings::JavaEnabled] =
        _settingJavaEnabled;
      _attributes[QWebSettings::PluginsEnabled] =
        _settingPluginsEnabled;
      _attributes[QWebSettings::PrivateBrowsingEnabled] =
        _settingPrivateBrowsingEnabled;
      _attributes[QWebSettings::JavascriptCanOpenWindows] =
        _settingJavascriptCanOpenWindows;
      _attributes[QWebSettings::JavascriptCanAccessClipboard] =
        _settingJavascriptCanAccessClipboard;
      _attributes[QWebSettings::DeveloperExtrasEnabled] =
        _settingDeveloperExtrasEnabled;
      _attributes[QWebSettings::SpatialNavigationEnabled] =
        _settingSpatialNavigationEnabled;
      _attributes[QWebSettings::LinksIncludedInFocusChain] =
        _settingLinksIncludedInFocusChain;
      _attributes[QWebSettings::ZoomTextOnly] =
        _settingZoomTextOnly;
      _attributes[QWebSettings::PrintElementBackgrounds] =
        _settingPrintElementBackgrounds;
      _attributes[QWebSettings::OfflineStorageDatabaseEnabled] =
        _settingOfflineStorageDatabaseEnabled;
      _attributes[QWebSettings::OfflineWebApplicationCacheEnabled] =
        _settingOfflineWebApplicationCacheEnabled;
      _attributes[QWebSettings::LocalStorageEnabled] =
        _settingLocalStorageEnabled;
      _attributes[QWebSettings::LocalContentCanAccessRemoteUrls] =
        _settingLocalContentCanAccessRemoteUrls;
      _attributes[QWebSettings::LocalContentCanAccessFileUrls] =
        _settingLocalContentCanAccessFileUrls;
      // not in qt 4.7.0 (mac)
      // _attributes[QWebSettings::XSSAuditingEnabled] =
      //   _settingXSSAuditingEnabled;
      _attributes[QWebSettings::AcceleratedCompositingEnabled] =
        _settingAcceleratedCompositingEnabled;
      _attributes[QWebSettings::TiledBackingStoreEnabled] =
        _settingTiledBackingStoreEnabled;
      _attributes[QWebSettings::FrameFlatteningEnabled] =
        _settingFrameFlatteningEnabled;
      // not in qt 4.7.0 (mac)
      // _attributes[QWebSettings::SiteSpecificQuirksEnabled] =
      //   _settingSiteSpecificQuirksEnabled;

      // CheckBoxes
      _checkboxes["SaveWindowState"] =
        std::make_pair(_saveWindowState, _saveWindowState->isChecked());
      _checkboxes["CloseApps"] =
        std::make_pair(_closeApps, _closeApps->isChecked());

      load(!_mimetypes.size());
      on__buttons_rejected();
    }

    void setSettings(QSettings* settings) {
      _settings = settings;
    }

    QSettings* operator()() {
      return _settings;
    }

    void setAttribute(QWebSettings::WebAttribute attr, bool state) {
      //LOG;
      QWebSettings::globalSettings()->setAttribute(attr, state);
      _attributes[attr]->setChecked(state);
    }

    bool flag(const QString& name) {
      assert(_checkboxes.find(name)!=_checkboxes.end());
      return _checkboxes[name].second;
    }

    const QString& text(const QString& name) {
      assert(_lineedits.find(name)!=_lineedits.end());
      return _lineedits[name].second;
    }

    const MimeTypes& mimetypes() const {
      return _mimetypes;
    }

    QStringList mimetype(QString mimetype, QString filename) const {
      Settings::MimeTypes::const_iterator
        it(_mimetypes.find(mimetype.split(';')[0]));
      if (it!=_mimetypes.end()) return it.value().toStringList();
      for (it=_mimetypes.begin(); it!=_mimetypes.end(); ++it)
        if (filename.endsWith("."+it.value().toStringList().at(0)))
          return it.value().toStringList();
      return QStringList();
    }

    QString& replaceSearchEngine(QString& url) {
      LOG;
      int len(url.indexOf(QRegExp("[ :]")));
      if (len<=0) return url;
      QString scheme(url.left(len));
      LOG<<"scheme:"<<scheme;
      if (!_searchEngines.contains(scheme)) return url;
      QString query(url.right(url.size()-len-1));
      LOG<<"query:"<<query;
      url = QString(_searchEngines[scheme].toString())
        .arg(query).arg(QLocale::system().name().left(2));
      return url;
    }

    const SearchEngines& searchEngines() const {
      return _searchEngines;
    }

    bool save() {
      LOG;
      if (!_settings || !_settings->isWritable()) return false;
      // Attributes
      for (Attributes::iterator it(_attributes.begin());
           it!=_attributes.end(); ++it)
        _settings->setValue
          (QString("QWebSettings/%1").arg(it->first),
           QWebSettings::globalSettings()->testAttribute(it->first));
      // CheckBoxes
      for (CheckBoxes::iterator it(_checkboxes.begin());
           it!=_checkboxes.end(); ++it)
        _settings->setValue
          (QString("Flags/%1").arg(it->first), it->second.second);
      // LineEdits
      for (LineEdits::iterator it(_lineedits.begin());
           it!=_lineedits.end(); ++it)
        _settings->setValue
          (QString("Texts/%1").arg(it->first), it->second.second);
      // MimeTypes
      _settings->setValue("QWebSettings/MimeTypes", _mimetypes);
      // Search Engines
      _settings->setValue("QWebSettings/SearchEngines", _searchEngines);
      return true;
    }

    bool load(bool overwriteMimeTypes=true) {
      LOG;
      if (!_settings) return false;
      // Attributes
      for (Attributes::iterator it(_attributes.begin());
           it!=_attributes.end(); ++it) {
        QVariant val
          (_settings->value
           (QString("QWebSettings/%1").arg(it->first),
            QWebSettings::globalSettings()->testAttribute(it->first)));
        if (val.isValid() && val.canConvert(QVariant::Bool))
          setAttribute(it->first, val.toBool());
      }
      // CheckBoxes
      for (CheckBoxes::iterator it(_checkboxes.begin());
           it!=_checkboxes.end(); ++it) {
        QVariant val
          (_settings->value
           (QString("Flags/%1").arg(it->first), it->second.second));
        if (val.isValid() && val.canConvert(QVariant::Bool)) {
          it->second.first->setChecked(val.toBool());
          it->second.second = val.toBool();
        }
      }
      // LineEdits
      for (LineEdits::iterator it(_lineedits.begin());
           it!=_lineedits.end(); ++it) {
        QVariant val
          (_settings->value
           (QString("Texts/%1").arg(it->first), it->second.second));
        if (val.isValid() && val.canConvert(QVariant::String)) {
          it->second.first->setText(val.toString());
          it->second.second = val.toString();
        }
      }
      // MimeTypes
      if (overwriteMimeTypes) {
        QVariant val(_settings->value("QWebSettings/MimeTypes"));
        if (val.isValid() && val.canConvert(QVariant::Map))
          _mimetypes = val.toMap();
      }
      // SearchEngines
      QVariant val(_settings->value("QWebSettings/SearchEngines"));
      if (val.isValid() && val.canConvert(QVariant::Map))
        _searchEngines = val.toMap();
      newSettings();
      return true;
    }

  private Q_SLOTS:

    void on__buttons_accepted() {
      LOG;
      // Attributes
      for (Attributes::iterator it(_attributes.begin());
           it!=_attributes.end(); ++it)
        QWebSettings::globalSettings()
          ->setAttribute(it->first, it->second->isChecked());
      // CheckBoxes
      for (CheckBoxes::iterator it(_checkboxes.begin());
           it!=_checkboxes.end(); ++it)
        it->second.second = it->second.first->isChecked();
      // LineEdits
      for (LineEdits::iterator it(_lineedits.begin());
           it!=_lineedits.end(); ++it)
        it->second.second = it->second.first->text();
      // MimeTypes
      _mimetypes.clear();
      for (int row(_mimeTypeTable->rowCount()); row--;)
        _mimetypes[_mimeTypeTable->item(row, 0)->text()] =
          QStringList()
          <<_mimeTypeTable->item(row, 1)->text()
          <<_mimeTypeTable->item(row, 2)->text();
      // SearchEngines
      _searchEngines.clear();
      for (int row(_searchEngineTable->rowCount()); row--;)
        _searchEngines[_searchEngineTable->item(row, 0)->text()] =
          _searchEngineTable->item(row, 1)->text();
      // Save
      if (_autoWrite) save();
      newSettings();
    }

    void on__buttons_rejected() {
      LOG;
      // Attributes
      for (Attributes::iterator it(_attributes.begin());
           it!=_attributes.end(); ++it)
        it->second->setChecked
          (QWebSettings::globalSettings()->testAttribute(it->first));
      // CheckBoxes
      for (CheckBoxes::iterator it(_checkboxes.begin());
           it!=_checkboxes.end(); ++it)
        it->second.first->setChecked(it->second.second);
      // LineEdits
      for (LineEdits::iterator it(_lineedits.begin());
           it!=_lineedits.end(); ++it)
        it->second.first->setText(it->second.second);
      // MimeTypes
      _mimeTypeTable->setRowCount(_mimetypes.size());
      _mimeTypeTable->verticalHeader()->show();
      _mimeTypeTable->horizontalHeader()->show();
      _mimeTypeTable->horizontalHeader()->setStretchLastSection(true);
      int row(0);
      for (MimeTypes::iterator it(_mimetypes.begin());
           it!=_mimetypes.end(); ++it, ++row) {
        LOG<<"MimeType:"<<it.key()<<it.value().toStringList();
        _mimeTypeTable->setItem
          (row, 0, new QTableWidgetItem(it.key()));
        _mimeTypeTable->setItem
          (row, 1, new QTableWidgetItem(it.value().toStringList().at(0)));
        _mimeTypeTable->setItem
          (row, 2, new QTableWidgetItem(it.value().toStringList().at(1)));
      }
      // SearchEngines
      _searchEngineTable->setRowCount(_searchEngines.size());
      _searchEngineTable->verticalHeader()->show();
      _searchEngineTable->horizontalHeader()->show();
      _searchEngineTable->horizontalHeader()->setStretchLastSection(true);
      row = 0;
      for (MimeTypes::iterator it(_searchEngines.begin());
           it!=_searchEngines.end(); ++it, ++row) {
        LOG<<"SearchEngine:"<<it.key()<<it.value().toString();
        _searchEngineTable->setItem
          (row, 0, new QTableWidgetItem(it.key()));
        _searchEngineTable->setItem
          (row, 1, new QTableWidgetItem(it.value().toString()));
      }
    }

    void on__addMimeType_pressed() {
      _mimeTypeTable->setRowCount(_mimeTypeTable->rowCount()+1);
      _mimeTypeTable->setItem(_mimeTypeTable->rowCount()-1, 0,
                              new QTableWidgetItem);
      _mimeTypeTable->setItem(_mimeTypeTable->rowCount()-1, 1,
                              new QTableWidgetItem);
      _mimeTypeTable->setItem(_mimeTypeTable->rowCount()-1, 2,
                              new QTableWidgetItem);
    }

    void on__removeMimeType_pressed() {
      QList<QTableWidgetSelectionRange> ranges
        (_mimeTypeTable->selectedRanges());
      if (ranges.isEmpty()) return;
      for (int begin(ranges.at(0).topRow()), count(ranges.at(0).rowCount());
           count; --count)
        _mimeTypeTable->removeRow(begin);
    }
    
    void on__addSearchEngine_pressed() {
      _searchEngineTable->setRowCount(_searchEngineTable->rowCount()+1);
      _searchEngineTable->setItem(_searchEngineTable->rowCount()-1, 0,
                                  new QTableWidgetItem);
      _searchEngineTable->setItem(_searchEngineTable->rowCount()-1, 1,
                                  new QTableWidgetItem);
      _searchEngineTable->setItem(_searchEngineTable->rowCount()-1, 2,
                                  new QTableWidgetItem);
    }

    void on__removeSearchEngine_pressed() {
      QList<QTableWidgetSelectionRange> ranges
        (_searchEngineTable->selectedRanges());
      if (ranges.isEmpty()) return;
      for (int begin(ranges.at(0).topRow()), count(ranges.at(0).rowCount());
           count; --count)
        _searchEngineTable->removeRow(begin);
    }
    
  private:

    typedef std::map<QWebSettings::WebAttribute, QCheckBox*> Attributes ;
    Attributes _attributes;
    typedef std::map<QString, std::pair<QCheckBox*, bool> > CheckBoxes;
    CheckBoxes _checkboxes;
    typedef std::map<QString, std::pair<QLineEdit*, QString> > LineEdits;
    LineEdits _lineedits;
    QSettings* _settings;
    bool _autoWrite;
    MimeTypes _mimetypes;
    SearchEngines _searchEngines;

};
