/*! @file

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

#include <QtCore/QFile>
#include <QtCore/QDir>
#include <QtCore/QFileInfo>
#include <QtCore/QFileSystemWatcher>
#include <QtCore/QString>
#include <QtCore/QStringList>

#include <cassert>

//! Store string lists.
/** Abstract storage interface to string lists, such as bookmarks. */
class Storage: public QObject {
    Q_OBJECT;
  Q_SIGNALS:
    //! Emitted if file content has changed.
    void changed();
  public:
    Storage() {}
    /*! @return true if readable or writable */
    bool valid() {
      return readable() || writeable();
    }
    /*! @return true if valid */
    operator bool() {
      return valid();
    }
    /*! @return name of the storage, e.g. filename */
    virtual QString name() = 0;
    /*! @return true if storage object already exists */
    virtual bool readable() = 0;
    /*! @return true if storage object exists or could be created */
    virtual bool writeable() = 0;
    /*! @return storage content as string list */
    virtual QStringList read() = 0;
    //! Writes storage content from string list.
    virtual bool write(const QStringList& out) = 0;
};

//! Implement @ref Storage for files.
class FileStorage: public Storage {
    Q_OBJECT;
  public:
    /*! @param file full path to storage file */
    FileStorage(QString file): _file(file) {
      _watcher.addPath(QFileInfo(_file).absolutePath());
      assert(connect(&_watcher, SIGNAL(directoryChanged(const QString&)),
                     SLOT(setupWatcher())));
      assert(connect(&_watcher, SIGNAL(fileChanged(const QString&)),
                     SIGNAL(changed())));
    }
    QString name() {
      return _file.fileName();
    }
    bool readable() {
      return QFileInfo(_file).exists();
    }
    bool writeable() {
      return readable() ||
        (!_file.fileName().isEmpty() &&
         QFileInfo(_file).absoluteDir().exists());
    }
    QStringList read() {
      QStringList res;
      if (readable()) {
        if (_file.open(QIODevice::ReadOnly))
          res=QString::fromUtf8(_file.readAll()).split("\n");
        _file.close();
      }
      return res;
    }
    bool write(const QStringList& out) {
      bool res(false);
      if (writeable()) {
        if (_file.open(QIODevice::WriteOnly))
          if (_file.write(out.join("\n").toUtf8())>=0) res=true;
        _file.close();
      }
      return res;
    }
  private Q_SLOTS:
    void setupWatcher() {
      bool watching(_watcher.files().size());
      if (watching) // remove watchlist if already existent
        _watcher.removePaths(_watcher.files());
      if (readable()) { // add file to watchlist
        _watcher.addPath(_file.fileName());
        if (!watching) // send change event if file is initially created
          changed();
      }
    }
  private:
    QFile _file;
    QFileSystemWatcher _watcher;
};
