/***************************************************************************
**
**  This file is part of GeopsyCore.
**
**  GeopsyCore 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 3 of the License, or
**  (at your option) any later version.
**
**  GeopsyCore is distributed in the hope that it will be useful,
**  but WITHOUT ANY WARRANTY; without even the implied warranty of
**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
**  GNU General Public License for more details.
**
**  You should have received a copy of the GNU General Public License
**  along with Foobar.  If not, see <http://www.gnu.org/licenses/>
**
**  See http://www.geopsy.org for more information.
**
**  Created: 2006-03-20
**  Copyright: 2006-2019
**    Marc Wathelet
**    Marc Wathelet (LGIT, Grenoble, France)
**
***************************************************************************/

#ifndef SIGNALDATABASE_H
#define SIGNALDATABASE_H

#include <QGpCoreTools.h>

#include "SubSignalPool.h"
#include "MasterSignalGroup.h"
#include "SignalFilePool.h"
#include "SharedMetaData.h"
#include "GeopsyCoreDLLExport.h"
#include "SeismicEventTable.h"

namespace GeopsyCore {

#define SIGNAL_DATABASE_CURRENT_VERSION 8

class SubSignalPool;
class SignalGroup;

class GEOPSYCORE_EXPORT SignalDatabase : private SubSignalPool, public XMLClass,
    public XMLContext, public UniqueID
{
  TRANSLATIONS("SignalDatabase")
public:
  SignalDatabase();
  ~SignalDatabase();

  virtual const QString& xml_tagName() const {return xmlSignalDatabaseTag;}
  static const QString xmlSignalDatabaseTag;

  static QString askSaveAs();
  bool saveAs(QString fileName=QString());
  bool save();
  bool open(QString fileName);
  QDir newFilePath() const;
  void clear();
  void cleanProcessedFiles();


  bool exists() const {return !name().isEmpty();}
  QString name() const {return SubSignalPool::name();}
  void setName(const QString& n) {SubSignalPool::setName(n);}
  int version() const {return _version;}

  bool contains(Signal * sig) const {return SubSignalPool::contains(sig);}
  Signal * signal(int id) const;
  void addSignal(Signal * sig);
  void addFile(SignalFile * file);
  SignalFilePool& filePool() {return _files;}
  const SubSignalPool& subPool() const {return *this;}

  MasterSignalGroup * masterGroup() {return _masterGroup;}
  const MasterSignalGroup * masterGroup() const {return _masterGroup;}

  const AbstractSignalGroup * findGroup(QString name) const {return _masterGroup->find(name);}
  const AbstractSignalGroup * findGroup(int id) const {return _masterGroup->find(id);}
  QList<const AbstractSignalGroup *> findGroups(const QRegExp& name) const {return const_cast<const MasterSignalGroup *>(_masterGroup)->find(name);}
  AbstractSignalGroup * findGroup(QString name) {return _masterGroup->find(name);}
  AbstractSignalGroup * findGroup(int id) {return _masterGroup->find(id);}
  QList<AbstractSignalGroup *> findGroups(const QRegExp& name) {return _masterGroup->find(name);}

  SeismicEventTable * seismicEvents() {return _seismicEvents;}
  const SeismicEventTable * seismicEvents() const {return _seismicEvents;}

  bool isModified();
  void removeFile(SignalFile * f);
  void removeSignal(Signal * sig) {SubSignalPool::remove(sig);}
  void signalDeleted(Signal * sig);

  int count() const {return SubSignalPool::count();}
  int isEmpty() const {return SubSignalPool::isEmpty();}
  Signal * at(int index) const {return SubSignalPool::at(index);}

  void addMetaData(MetaData * d) {_permanentSharedMetaData.add(d);}
  void removeMetaData(int id) {_permanentSharedMetaData.remove(id);}
  MetaData * metaData(int id) {return _permanentSharedMetaData.data(id);}
  const MetaData * metaData(int id) const {return _permanentSharedMetaData.data(id);}
  MetaData * resolveMetaData(int index);

  SubSignalPool load(QString fileName, SignalFileFormat format=SignalFileFormat::Unknown, bool viewFile=false);
  SubSignalPool load(QStringList fileNames, SignalFileFormat format=SignalFileFormat::Unknown, bool viewFiles=false);
  void showSignal(const DoubleSignal * sig, const QString& name=QString(), const QString& comments=QString());
  void showSignal(const KeepSignal * sig, const QString& name=QString(), const QString& comments=QString());
protected:
  virtual void xml_writeProperties(XML_WRITEPROPERTIES_ARGS) const;
  virtual void xml_writeChildren(XML_WRITECHILDREN_ARGS) const;
  virtual bool xml_setProperty(XML_SETPROPERTY_ARGS);
  virtual XMLMember xml_member(XML_MEMBER_ARGS);
  bool xml_polish(XML_POLISH_ARGS);
private:
  bool add(SignalDatabase * o);
  QMap<const AbstractSignalGroup *, SubSignalPool> temporarySignals(QString& tempSignalList, int& tempSignalToSave) const;
  bool saveTemporaryFiles();
  bool saveTemporarySignals();
  virtual int countId(int id, int& newId) const;
  void createAllSharedMetaData();
  void collectAllSharedMetaData();
  void releaseAllSharedMetaData();
  bool openDBFileV12(QString fileName);
  bool openDBFileV2(FILE * f);
  void openGroupsV12();

  SignalFilePool _files;
  MasterSignalGroup * _masterGroup;
  SeismicEventTable * _seismicEvents;
  int _version;
  MetaDataMap _permanentSharedMetaData;
  SharedMetaData * _allSharedMetaData;
};

} // namespace GeopsyCore

#endif // SIGNALDATABASE_H
