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

#include "SignalFileFormat.h"
#include "CustomFileFormats.h"
#include "AsciiSignalFormat.h"
#include "SACHeader.h"
#include "SEGYTraceHeader.h"
#include "PasscalSegYHeader.h"
#include "GeopsySignalHeader.h"
#include "GuralpCompressedBlock.h"
#include "MiniSeedVolume.h"

namespace GeopsyCore {

/*!
  \class SignalFileFormat SignalFileFormat.h
  \brief Brief description of class still missing

  Full description of class still missing
*/

SignalFileFormat::SignalFileFormat(Format f, AbstractFileFormat * customFormat)
{
  _id=f;
  _customFormat=customFormat;
  if(_customFormat) {
    _customFormat->addReference();
  }
}

SignalFileFormat::SignalFileFormat(const SignalFileFormat& o)
{
  _id=o._id;
  _customFormat=o._customFormat;
  if(_customFormat) {
    _customFormat->addReference();
  }
}

SignalFileFormat::~SignalFileFormat()
{
  if(_customFormat) {
    SharedObject::removeReference(_customFormat);
  }
}

void SignalFileFormat::operator=(const SignalFileFormat& o)
{
  _id=o._id;
  if(_customFormat) {
    SharedObject::removeReference(_customFormat);
  }
  _customFormat=o._customFormat;
  if(_customFormat) {
    _customFormat->addReference();
  }
}

bool SignalFileFormat::operator==(const SignalFileFormat& o) const
{
  return _id==o._id && _customFormat==o._customFormat;
}

bool SignalFileFormat::operator<(const SignalFileFormat& o) const
{
  return _id<o._id;
}

/*!
  Returns a list of available formats for import, suitable for all input dialog boxes.
*/
QList< QPair<QString, SignalFileFormat> > SignalFileFormat::importList()
{
  TRACE;
  QList< QPair<QString, SignalFileFormat> > formats;
  // Add conventional formats
  for(int i=1; i<FormatCount; i++) {
    SignalFileFormat format(static_cast<Format>(i));
    if(format.id()!=Temporary && format.id()!=Custom) {
      formats.append(QPair<QString, SignalFileFormat>(format.captionFilter(), format));
    }
  }
  // Add custom formats
  QList<SignalFileFormat> customList=GeopsyCoreEngine::instance()->customFileFormats()->list();
  for(QList<SignalFileFormat>::iterator it=customList.begin(); it!=customList.end(); it++) {
    SignalFileFormat& format=*it;
    formats.append(QPair<QString, SignalFileFormat>(format.captionFilter(), format));
  }
  std::sort(formats.begin(), formats.end());
  // Make sure that "Automatic recognition" is the first one
  SignalFileFormat f;
  formats.prepend(QPair<QString, SignalFileFormat>(f.caption(), f));
  return formats;
}

/*!
  Returns a list of available formats for export, suitable for all input dialog boxes.
*/
QList< QPair<QString, SignalFileFormat> > SignalFileFormat::exportList()
{
  TRACE;
  QList< QPair<QString, SignalFileFormat> > formats;
  // Add conventional formats
  for(int i=1; i<FormatCount; i++) {
    SignalFileFormat format(static_cast<Format>(i));
    if(format.id()!=Temporary && format.id()!=Custom && !format.isReadOnly()) {
      formats.append(QPair<QString, SignalFileFormat>(format.captionFilter(), format));
    }
  }
  // Add custom formats
  QList<SignalFileFormat> customList=GeopsyCoreEngine::instance()->customFileFormats()->list();
  for(QList<SignalFileFormat>::iterator it=customList.begin(); it!=customList.end(); it++) {
    SignalFileFormat& format=*it;
    if(!format.isReadOnly()) {
      formats.append(QPair<QString, SignalFileFormat>(format.captionFilter(), format));
    }
  }
  std::sort(formats.begin(), formats.end());
  return formats;
}

QString SignalFileFormat::name() const
{
  TRACE;
  switch (_id) {
  case Seg2: return "Seg2";
  case SegD: return "SegD";
  case SuLittleEndian: return "SuLittleEndian";
  case SuBigEndian: return "SuBigEndian";
  case Tomo: return "Tomo";
  case RD3: return "RD3";
  case SacLittleEndian: return "SacLittleEndian";
  case SacBigEndian: return "SacBigEndian";
  case Radan: return "Radan";
  case Gse2: return "Gse2";
  case CityShark2: return "CityShark2";
  case MiniShark: return "MiniShark";
  case Ascii:
    if(_customFormat) {
      return _customFormat->name();
    } else {
      return "Ascii";
    }
  case AsciiOneColumn: return "AsciiOneColumn";
  case GeopsySignal: return "GeopsySignal";
  case Saf: return "Saf";
  case MultiGse2: return "MultiGse2";
  case Sismalp: return "Sismalp";
  case Wav: return "Wav";
  case SegYLittleEndian: return "SegYLittleEndian";
  case SegYBigEndian: return "SegYBigEndian";
  case PasscalSegYLittleEndian: return "PasscalSegYLittleEndian";
  case PasscalSegYBigEndian: return "PasscalSegYBigEndian";
  case Temporary: return "Temporary";
  case SyscomXmr: return "SyscomXmr";
  case SyscomSmr: return "SyscomSmr";
  case SyscomVmrx: return "SyscomVmrx";
  case GuralpGcf: return "GuralpGcf";
  case MiniSeed: return "MiniSeed";
  case Fourier: return "Fourier";
  case Custom:
    if(_customFormat) {
      return _customFormat->name();
    }
    break;
  case FormatCount:
  case Unknown:
    break;
  }
  return "Unknown";
}

QString SignalFileFormat::caption() const
{
  TRACE;
  switch (_id) {
  case Seg2: return tr("SEG-2");
  case SegD: return tr("SEG-D");
  case SuLittleEndian: return tr("SU Little Endian");
  case SuBigEndian: return tr("SU Big Endian");
  case Tomo: return tr("Arrival times");
  case RD3: return tr("RD3 Ramac");
  case SacLittleEndian: return tr("Sac Little Endian");
  case SacBigEndian: return tr("Sac Big Endian");
  case Radan: return tr("Radan");
  case Gse2: return tr("GSE 2.0 Single signal");
  case MultiGse2: return tr("GSE 2.0 Multi signals");
  case CityShark2: return tr("CityShark 1 or 2");
  case MiniShark: return tr("MiniShark");
  case Ascii:
    if(_customFormat) {
      return _customFormat->caption();
    } else {
      return tr("Ascii multi columns (no header)");
    }
  case AsciiOneColumn: return tr("Ascii one column (no header)");
  case GeopsySignal: return tr("Geopsy Signal");
  case Saf: return tr("SAF Sesame");
  case Sismalp: return tr("Sismalp");
  case Wav: return tr("WAVE PCM soundfile");
  case SegYLittleEndian: return tr("SEGY Little Endian");
  case SegYBigEndian: return tr("SEGY Big Endian");
  case PasscalSegYLittleEndian: return tr("PASSCAL SEGY Little Endian");
  case PasscalSegYBigEndian: return tr("PASSCAL SEGY Big Endian");
  case SyscomXmr: return tr("SYSCOM XMR");
  case SyscomSmr: return tr("SYSCOM SMR");
  case SyscomVmrx: return tr("SYSCOM VMR/VMX");
  case GuralpGcf: return tr("Guralp");
  case MiniSeed: return tr("Mini seed");
  case Fourier: return tr("Fourier spectrum");
  case Custom:
    if(_customFormat) {
      return _customFormat->caption();
    }
    break;
  case Temporary:
  case FormatCount:
  case Unknown:
    break;
  }
  return tr("Automatic recognition");
}

QString SignalFileFormat::filter() const
{
  TRACE;
  switch (_id) {
  case Seg2: return "*.seg2 *.dat *";
  case SegD: return "*.segd *";
  case SuLittleEndian:
  case SuBigEndian:
    return "*.su";
  case Tomo: return "*.arr *";
  case RD3: return "*.rd3";
  case Ascii:
  case Custom:
    if(_customFormat && !_customFormat->suffixList().isEmpty()) {
      return _customFormat->suffixFilter()+" *";
    }
    break;
  case CityShark2:
  case MiniShark:
  case AsciiOneColumn:
  case GeopsySignal:
  case Unknown:
  case Temporary:
  case FormatCount:
    break;
  case SacLittleEndian:
  case SacBigEndian:
    return "*.sac *";
  case Radan: return "*.dzt";
  case Gse2:
  case MultiGse2:
    return "*.gse *";
  case Saf: return "*.saf *";
  case Sismalp: return "*.ndx *.sis";
  case Wav: return "*.wav";
  case SegYLittleEndian:
  case SegYBigEndian:
  case PasscalSegYLittleEndian:
  case PasscalSegYBigEndian:
    return "*.segy *.sgy";
  case SyscomXmr: return "*.xmr";
  case SyscomSmr: return "*.smr";
  case SyscomVmrx: return "*.vmr *.vmx";
  case GuralpGcf: return "*.gcf *";
  case MiniSeed: return "*.mseed *.msd *";
  case Fourier: return "*.fourier";
  }
  return "*";
}

/*!
  Returns default suffix for exporting with this format
*/
QString SignalFileFormat::suffix() const
{
  TRACE;
  switch (_id) {
  case Seg2: return ".seg2";
  case SegD: return ".segd";
  case SuLittleEndian:
  case SuBigEndian:
    return ".su";
  case Tomo: return ".arr";
  case RD3: return ".rd3";
  case Ascii:
  case Custom:
    if(_customFormat && !_customFormat->suffixList().isEmpty()) {
      return "."+_customFormat->suffixList().first();
    }
    break;
  case CityShark2:
  case MiniShark:
  case AsciiOneColumn:
  case GeopsySignal:
  case Unknown:
  case Temporary:
  case FormatCount:
  case Sismalp:
    break;
  case SacLittleEndian:
  case SacBigEndian:
    return ".sac";
  case Radan: return ".dzt";
  case Gse2:
  case MultiGse2:
    return ".gse";
  case Saf: return ".saf";
  case Wav: return ".wav";
  case SegYLittleEndian:
  case SegYBigEndian:
  case PasscalSegYLittleEndian:
  case PasscalSegYBigEndian:
    return ".sgy";
  case SyscomXmr: return ".xmr";
  case SyscomSmr: return ".smr";
  case SyscomVmrx: return ".vmx";
  case GuralpGcf: return ".gcf";
  case MiniSeed: return ".mseed";
  case Fourier: return ".fourier";
  }
  return QString();
}

QString SignalFileFormat::captionFilter() const
{
  TRACE;
  QString filt=filter();
  if(filt=="*")
    return caption();
  else
    return QString("%1 (%2)").arg(caption()).arg(filt);
}

bool SignalFileFormat::isReadOnly() const
{
  TRACE;
  switch (_id) {
  case Ascii:
    if(_customFormat) {
      return true;
    } else {
      return false;
    }
  case Custom:
    if(_customFormat) {
      return _customFormat->isReadOnly();
    }
    break;
  case Seg2:
  case SuLittleEndian:
  case SuBigEndian:
  case SegYLittleEndian:
  case SegYBigEndian:
  case SacLittleEndian:
  case SacBigEndian:
  case Gse2:
  case MultiGse2:
  case GeopsySignal:
  case Tomo:
  case AsciiOneColumn:
  case MiniSeed:
  case Saf:
  case CityShark2:
  case Wav:
    return false;
  SIGNALFILEFORMAT_READONLY
    break;
  }
  return true;
}

/*!
  Get file format from name
*/
SignalFileFormat SignalFileFormat::fromName(QString n)
{
  TRACE;
  if(n.length()<3) return Unknown;
  n=n.toLower();
  switch (n[0].unicode()) {
  case 'a':
    if(n.startsWith("ascii")) {
      if(n=="ascii") return Ascii;
      else if(n=="asciionecolumn") return AsciiOneColumn;
      else return GeopsyCoreEngine::instance()->customFileFormats()->fromName(n);
    }
    break;
  case 'c':
    if(n=="cityshark2") return CityShark2;
    else if(n=="city2") return CityShark2; // For compatibility
    break;
  case 'g':
    if(n=="gse2") return Gse2;
    else if(n=="geopsysignal") return GeopsySignal;
    else if(n=="guralpgcf") return GuralpGcf;
    break;
  case 'm':
    if(n=="multigse2") return MultiGse2;
    else if(n=="miniseed") return MiniSeed;
    else if(n=="minishark") return MiniShark;
    break;
  case 'r':
    if(n=="rd3") return RD3;
    else if(n=="radan") return Radan;
    break;
  case 's':
    switch (n[2].unicode()) {
    case 'f':
      if(n=="saf") return Saf;
      break;
    case 'l':
      if(n=="sulittleendian") return SuLittleEndian;
      break;
    case 'b':
      if(n=="subigendian") return SuBigEndian;
      break;
    case 'c':
      if(n=="saclittleendian") return SacLittleEndian;
      else if(n=="sacbigendian") return SacBigEndian;
      break;
    case 'g':
      if(n=="seg2") return Seg2;
      else if(n=="segylittleendian") return SegYLittleEndian;
      else if(n=="segybigendian") return SegYBigEndian;
      break;
    case 's':
      if(n=="sismalp") return Sismalp;
      else if(n=="syscomxmr") return SyscomXmr;
      else if(n=="syscomsmr") return SyscomSmr;
      else if(n=="syscomvmrx") return SyscomVmrx;
      break;
    default:
      break;
    }
    break;
  case 't':
    if(n=="tomo") return Tomo;
    else if(n=="temporary") return Temporary;
    break;
  case 'u':
    if(n=="unknown") return Unknown;
    break;
  case 'w':
    if(n=="wav") return Wav;
    break;
  default:
    break;
  }
  return GeopsyCoreEngine::instance()->customFileFormats()->fromName(n);
}

/*!
  Get file format from the caption and the filter as saved in Settings
*/
SignalFileFormat SignalFileFormat::fromCaptionFilter(QString cf)
{
  TRACE;
  if(cf.length()<3) return Unknown;
  cf=cf.toLower();
  switch (cf[2].unicode()) {
  case ' ':
    if(cf.startsWith(tr("su little endian"))) return SuLittleEndian;
    else if(cf.startsWith(tr("su big endian"))) return SuBigEndian;
    break;
  case '3':
    if(cf.startsWith(tr("rd3 ramac"))) return RD3;
    break;
  case 'c':
    if(cf.startsWith(tr("sac"))) {
      if(cf.startsWith(tr("sac little endian"))) return SacLittleEndian;
      else if(cf.startsWith("sac big endian")) return SacBigEndian;
    } else if(cf.startsWith(tr("ascii"))) {
      if(cf.startsWith(tr("ascii multi columns (no header)"))) return Ascii;
      else if(cf.startsWith(tr("ascii one column (no header)"))) return AsciiOneColumn;
    }
    break;
  case 'd':
    if(cf.startsWith(tr("radan"))) return Radan;
    break;
  case 'e':
    if(cf.startsWith(tr("gse 2.0 single signal"))) return Gse2;
    else if(cf.startsWith("gse 2.0 multi signals")) return MultiGse2;
    break;
  case 'g':
    if(cf.startsWith(tr("seg"))) {
      if(cf.startsWith(tr("seg-2"))) return Seg2;
      else if(cf.startsWith(tr("seg-d"))) return SegD;
    } else if(cf.startsWith(tr("SEGY"))) {
      if(cf.startsWith(tr("SEGY Little Endian"))) return SegYLittleEndian;
      if(cf.startsWith(tr("SEGY Big Endian"))) return SegYBigEndian;
    }
    break;
  case 'f':
    if(cf.startsWith(tr("saf sesame"))) return Saf;
    break;
  case 'n':
    if(cf.startsWith(tr("mini seed"))) return MiniSeed;
    else if(cf.startsWith(tr("minishark"))) return MiniShark;
    break;
  case 'o':
    if(cf.startsWith(tr("geopsy signal"))) return GeopsySignal;
    break;
  case 'r':
    if(cf.startsWith(tr("arrival times"))) return Tomo;
    else if(cf.startsWith(tr("guralp"))) return GuralpGcf;
    break;
  case 's':
    if(cf.startsWith(tr("sismalp"))) return Sismalp;
    else if(cf.startsWith(tr("passcal segy"))) {
      if(cf.startsWith(tr("passcal segy little endian"))) return PasscalSegYBigEndian;
      if(cf.startsWith(tr("passcal segy big endian"))) return PasscalSegYLittleEndian;
    }
    else if(cf.startsWith(tr("syscom"))) {
      if(cf.startsWith(tr("syscom xmr"))) return SyscomXmr;
      else if(cf.startsWith(tr("syscom smr"))) return SyscomXmr;
      else if(cf.startsWith(tr("syscom vmr/vmx"))) return SyscomXmr;
    }
    break;
  case 't':
    if(cf.startsWith(tr("cityshark 1 or 2"))) return CityShark2;
    break;
  case 'u':
    if(cf.startsWith(tr("fourier spectrum"))) return Fourier;
    break;
  case 'v':
    if(cf.startsWith(tr("wave pcm soundfile"))) return Wav;
    break;
  default:
    break;
  }
  return GeopsyCoreEngine::instance()->customFileFormats()->fromCaptionFilter(cf);
}

/*!
  Get file format from an existing file.
*/
SignalFileFormat SignalFileFormat::fromContent(QString fileName)
{
  TRACE;
  SignalFileFormat fmt;
  // Originally, the file format was also identified from file suffix
  // This method may lead to ambiguous results especially for custom formats
  // 20160628, the identification from suffix is removed but still those file formats cannot
  // be identified from content:
  //   Radan
  //   Fourier
  //   Sismalp
  //   RD3
  //   Su
  //   SegD
  //   Syscom
  //   Guralp (unsupported features fake the auto-recognition)
  //
  // fromSuffix() is used at the end as a backup method.

  // Test file content
  QFile f(fileName);
  if(!f.open(QIODevice::ReadOnly)) {
    App::log(tr("Determining format: cannot open file %1\n").arg(fileName) );
    return Unknown;
  }
  // Test DBSignal format
  GeopsySignalHeader h;
  QDataStream sd(&f);
  sd.readRawData(h.raw, GEOPSYSIGNAL_HEADERSIZE);
  App::freeze(true);
  bool ret=h.isValid();
  App::freeze(false);
  if(ret) {
    return GeopsySignal;
  }
  f.seek(0); // reset to begin of file
  // Other formats
  QTextStream st(&f);
  QString str=st.readLine();
  if(str.indexOf("Arrival_times_file")>-1) {
    return Tomo;
  }
  if(str.count()>=2 && str[0]==0x55 && str[1]==0x3A) {
    return Seg2;
  }
  if(str.left(4)=="WID2") {
    return MultiGse2;
  }
  if(str.left(10)=="#Minishark") {
    return MiniShark;
  }
  if(str.left(18)=="Original file name") {
    return CityShark2;
  }
  if(str.left(35)=="SESAME ASCII data format (saf) v. 1") {
    return Saf;
  }
  if(str.left(4)=="RIFF") {
    return Wav;
  }
  // Test simple multi-column ascii file without header
  bool ok;
  while(!st.atEnd() && !str.isEmpty() && str[0]=='#') {
    str=st.readLine();
  }
  QString field=str.trimmed().simplified().section(QRegExp("[ \t]"), 0, 0);
  field.toDouble(&ok);
  if(ok) return Ascii;
  f.seek(0); // reset to begin of file
  // Testing Guralp format
  App::freeze(true);
  GuralpCompressedBlock b;
  while(!f.atEnd()) {
    if(!b.readHeader(f)) {
      break;
    }
    if(b.isData()) {
      if(b.readBody(f)) {
        App::freeze(false);
        return GuralpGcf;
      }
    }
  }
  f.close();
  App::freeze(false);
  // Test if SAC format
  fmt=SACHeader::determineByteOrder(fileName);
  if(fmt.id()!=Unknown) return fmt;
  // Testing mini seed
  if(MiniSeedVolume::isValid(fileName)) {
    return MiniSeed;
  } else {
    QFileInfo fi(fileName);
    QString s=fi.suffix();
    if(s=="msd" || s=="mseed" || s=="miniseed") {
      MiniSeedVolume::nonAsciiPathError(fileName);
      return Unknown;
    }
  }
  // Testing PASSCAL SEGY (before SU because it is more strict)
  fmt=PasscalSegYHeader::determineByteOrder(fileName, 1);
  if(fmt.id()!=Unknown) return fmt;
  // Testing SEGY
  fmt=SEGYTraceHeader::determineByteOrderSEGY(fileName, 1);
  if(fmt.id()!=Unknown) return fmt;
  // Testing SU
  fmt=SEGYTraceHeader::determineByteOrderSU(fileName, 1);
  if(fmt.id()!=Unknown) return fmt;
  // Format still not identified, use suffix
  QFileInfo finfo(fileName);
  fmt=fromSuffix(finfo.suffix());
  if(fmt.id()!=Unknown) return fmt;
  // User custom formats
  fmt=GeopsyCoreEngine::instance()->customFileFormats()->fromContent(fileName);
  return fmt;
}

/*!
  Get file format from a non-existing file, only from extension.
  This function is used only for exporting files.
*/
SignalFileFormat SignalFileFormat::fromSuffix(QString suffix)
{
  TRACE;
  SignalFileFormat fmt=Unknown;
  suffix=suffix.toLower();
  if(!suffix.isEmpty()) {
    switch(suffix[0].unicode()) {
    case 'a':
      if(suffix=="arr" ) {
        fmt=Tomo;
      }
      break;
    case 'd':
      if(suffix=="dzt" ) {
        fmt=Radan;
      }
      break;
    case 'f':
      if(suffix=="fourier" ) {
        fmt=Fourier;
      }
      break;
    case 'g':
      if(suffix== "gse") {
        fmt=MultiGse2;
      }
      if(suffix== "gcf") {
        fmt=GuralpGcf;
      }
      break;
    case 'm':
      if(suffix=="msd" || suffix=="mseed") {
        fmt=MiniSeed;
      }
      break;
    case 'n':
      if(suffix=="ndx" ) {
        fmt=Sismalp;
      }
      break;
    case 'r':
      if(suffix=="rd3" ) {
        fmt=RD3;
      }
      break;
    case 's':
      switch(suffix.count()) {
      case 2:
        if(suffix=="su" ) {
          #if Q_BYTE_ORDER==Q_BIG_ENDIAN
          fmt=SuBigEndian;
          #else
          fmt=SuLittleEndian;
          #endif
        }
        break;
      case 3:
        switch(suffix[2].unicode()) {
        case '2':
          if(suffix=="sg2") {
            fmt=Seg2;
          }
          break;
        case 'c':
          if(suffix=="sac" ) {
            #if Q_BYTE_ORDER==Q_BIG_ENDIAN
            fmt=SacBigEndian;
            #else
            fmt=SacLittleEndian;
            #endif
          }
          break;
        case 'd':
          if(suffix=="sgd") {
            fmt=SegD;
          }
          break;
        case 'f':
          if(suffix=="saf") {
            fmt=Saf;
          }
          break;
        case 'r':
          if(suffix=="smr") {
            fmt=SyscomSmr;
          }
          break;
        case 's':
          if(suffix=="sis") {
            fmt=Sismalp;
          }
          break;
        case 'y':
          if(suffix=="sgy" ) {
            #if Q_BYTE_ORDER==Q_BIG_ENDIAN
            fmt=SegYBigEndian;
            #else
            fmt=SegYLittleEndian;
            #endif
         }
          break;
        }
        break;
      case 4:
        switch(suffix[3].unicode()) {
        case '2':
          if(suffix=="seg2") {
            fmt=Seg2;
          }
          break;
        case 'd':
          if(suffix=="segd") {
            fmt=SegD;
          }
          break;
        case 'y':
          if(suffix=="segy") {
            #if Q_BYTE_ORDER==Q_BIG_ENDIAN
            fmt=SegYBigEndian;
            #else
            fmt=SegYLittleEndian;
            #endif
          }
          break;
        }
        break;
      }
      break;
    case 'v':
      if(suffix=="vmr" || suffix=="vmx") {
        fmt=SyscomVmrx;
      }
      break;
    case 'w':
      if(suffix=="wav" ) {
        fmt=Wav;
      }
      break;
    case 'x':
      if(suffix=="xmr" ) {
        fmt=SyscomXmr;
      }
      break;
    }
  }
  if(fmt==Unknown) {
    return GeopsyCoreEngine::instance()->customFileFormats()->fromSuffix(suffix, fmt);
  } else {
    return fmt;
  }
}


/*!
  Returns true if it is a one signal per file format
  (GSE, SAC)
*/
SignalFileFormat::Storage SignalFileFormat::storage() const
{
  switch (_id) {
  case SacLittleEndian:
  case SacBigEndian:
  case Gse2:
    return Single;
  default:
    return Multi;
  }
}

} // namespace GeopsyCore
