/***************************************************************************
**
**  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: 2010-03-20
**  Copyright: 2010-2019
**    Marc Wathelet (LGIT, Grenoble, France)
**
***************************************************************************/

#include "CustomFileFormats.h"
#include "AsciiSignalFormat.h"

namespace GeopsyCore {

/*!
  \class CustomFileFormats CustomFileFormats.h
  \brief Official list of custom formats (ASCII and others)

  Full description of class still missing
*/

const QString CustomFileFormats::xmlCustomFileFormatsTag="CustomFileFormats";

/*!
  Description of constructor still missing
*/
CustomFileFormats::CustomFileFormats()
    : XMLClass()
{
  TRACE;
  restore();
}

/*!
  Description of destructor still missing
*/
CustomFileFormats::~CustomFileFormats()
{
  TRACE;
  clear(SignalFileFormat::Unknown, false);
}

QString CustomFileFormats::name(int index) const
{
  TRACE;
  return _formats.at(index)->name();
}

void CustomFileFormats::save()
{
  TRACE;
  QSettings& reg=CoreApplication::instance()->settings();
  XMLHeader hdr(this);
  reg.setValue("CustomFileFormats", hdr.xml_saveString());
}

void CustomFileFormats::restore()
{
  TRACE;
  QSettings& reg=CoreApplication::instance()->settings();
  QString xmlFormats=reg.value("CustomFileFormats", "").toString();
  if(!xmlFormats.isEmpty()) {
    clear(SignalFileFormat::Unknown, true);
    XMLHeader hdr(this);
    XMLErrorReport xmler(XMLErrorReport::Read | XMLErrorReport::NoMessageBox);
    xmler.setTitle(tr("Loading custom formats"));
    xmler.exec(hdr.xml_restoreString(xmlFormats));
  }
}

bool CustomFileFormats::contains(const QString& name) const
{
  TRACE;
  foreach(AbstractFileFormat * format, _formats) {
    if(format->name()==name) {
      return true;
    }
  }
  return false;
}

/*!
  Remove all formats with id \id, or all formats if \id is SignalFileFormat::Unknown.
  if \a userProperties is true, only the formats with user properties are removed.
*/
void CustomFileFormats::clear(SignalFileFormat::Format id, bool userProperties)
{
  TRACE;
  QMutableListIterator<AbstractFileFormat *> it(_formats);
   while(it.hasNext()) {
     AbstractFileFormat * format=it.next();
     if((id==SignalFileFormat::Unknown || format->format()==id) &&
        (!userProperties || format->hasUserProperties())) {
       AbstractFileFormat::removeReference(format);
       it.remove();
     }
   }
}

void CustomFileFormats::remove(int index)
{
  TRACE;
  AbstractFileFormat * format=_formats.at(index);
  AbstractFileFormat::removeReference(format);
  _formats.removeAt(index);
}

void CustomFileFormats::add(AbstractFileFormat * format)
{
  TRACE;
  format->addReference();
  _formats.append(format);
}

/*!
  Get format from \a suffix. If \a fmt is not SignalFileFormat::Unknown, it returns
  SignalFileFormat::Unknown if at least another format can be identified and issues a
  message to user.
*/
SignalFileFormat CustomFileFormats::fromSuffix(const QString& suffix, const SignalFileFormat &stdfmt) const
{
  TRACE;
  SignalFileFormat fmt=SignalFileFormat::Unknown;
  foreach(AbstractFileFormat * format, _formats) {
    if(!format->suffixList().isEmpty()) {
      if(format->suffixList().contains(suffix)) {
        if(fmt==SignalFileFormat::Unknown && stdfmt==SignalFileFormat::Unknown) {
          fmt=SignalFileFormat(format->format(), format);
        } else {
          if(fmt==SignalFileFormat::Unknown) {
            fmt=stdfmt;
          }
          Message::warning(MSG_ID, tr("Format recognition from suffix"),
                           tr("More than one format has suffix '%1' (%2 and %3). Fix the ambiguity in your custom file formats.")
                           .arg(suffix).arg(format->name()).arg(fmt.name()));
          return SignalFileFormat::Unknown;
        }
      }
    }
  }
  return fmt;
}

SignalFileFormat CustomFileFormats::fromContent(const QString& fileName) const
{
  TRACE;
  // Sort format by decreasing complexity (to avoid false identifications)
  QMultiMap<int, AbstractFileFormat *> formatMap;
  foreach(AbstractFileFormat * format, _formats) {
    formatMap.insert(format->complexity(), format);
  }
  QMapIterator<int, AbstractFileFormat *> it(formatMap);
  it.toBack();
  QElapsedTimer chrono;
  while(it.hasPrevious()) {
    it.previous();
    AbstractFileFormat * format=it.value();
    chrono.start();
    bool ret=format->isValid(fileName);
    App::log(1, tr("Time for checking for format '%1': %2\n")
                      .arg(format->name())
                      .arg(chrono.elapsed()*0.001));
    if(ret) {
      return SignalFileFormat(format->format(), format);
    }
  }
  return SignalFileFormat::Unknown;
}

SignalFileFormat CustomFileFormats::fromName(const QString& n) const
{
  TRACE;
  foreach(AbstractFileFormat * format, _formats) {
    QString fn=format->name().toLower();
    if(n==fn) {
      return SignalFileFormat(format->format(), format);
    }
  }
  return SignalFileFormat::Unknown;
}

SignalFileFormat CustomFileFormats::fromCaptionFilter(const QString& cf) const
{
  TRACE;
  foreach(AbstractFileFormat * format, _formats) {
    QString fcf=format->captionFilter().toLower();
    if(cf==fcf) {
      return SignalFileFormat(format->format(), format);
    }
  }
  return SignalFileFormat::Unknown;
}

QList<SignalFileFormat> CustomFileFormats::list() const
{
  TRACE;
  QList<SignalFileFormat> formats;
  foreach(AbstractFileFormat * format, _formats) {
    formats.append(SignalFileFormat(format->format(), format));
  }
  return formats;
}

void CustomFileFormats::xml_writeChildren(XML_WRITECHILDREN_ARGS) const
{
  TRACE;
  for(QList<AbstractFileFormat *>::const_iterator it=_formats.begin();it!=_formats.end();it++) {
    AbstractFileFormat * f=*it;
    if(f->hasUserProperties()) {
      (*it)->xml_save(s, context);
    }
  }
}

XMLMember CustomFileFormats::xml_member(XML_MEMBER_ARGS)
{
  TRACE;
  Q_UNUSED(context)
  Q_UNUSED(attributes)
  if(tag==AsciiSignalFormat::xmlAsciiSignalFormatTag) {
    AsciiSignalFormat * format=new AsciiSignalFormat;
    add(format);
    return XMLMember(format);
  }
  return XMLMember(XMLMember::Unknown);
}

} // namespace GeopsyCore
