/***************************************************************************
**
**  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: 2007-05-15
**  Copyright: 2007-2019
**    Marc Wathelet
**    Marc Wathelet (LGIT, Grenoble, France)
**
***************************************************************************/

#include <QGpCoreTools.h>

#include "FilterParameters.h"

namespace GeopsyCore {

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

    Full description of class still missing
  */

  FilterParameters::FilterParameters()
  {
    _fmin=1.0;
    _fmax=1.0;
    _band=LowPass;
    _method=FrequencyWindow;
    _window.setShape(WindowFunctionParameters::Cosine);
    _width=0.1;
  }

  FilterParameters::FilterParameters(const FilterParameters &o)
    : AbstractParameters(o),
      _window(o._window)
  {
    _band=o._band;
    setFrequencyRange(o._fmin, o._fmax);
    _method=o._method;
    _order=o._order;
    _width=o._width;
  }

  void FilterParameters::setBand(Band b)
  {
    _band=b;
    setFrequencyRange(_fmin, _fmax);
    _window.setReversed(_band==BandReject);
  }

  void FilterParameters::setFrequencyRange(double min, double max)
  {
    TRACE;
    switch(_band) {
    case LowPass:
    case HighPass:
      _fmin=min;
      _fmax=max;
      break;
    case BandPass:
    case BandReject:
      if(min<max) {
        _fmin=min;
        _fmax=max;
      } else {
        _fmin=max;
        _fmax=min;
      }
      break;
    }
  }

  QString FilterParameters::bandString() const
  {
    switch(_band) {
    case LowPass:
      break;
    case HighPass:
      return "HighPass";
    case BandPass:
      return "BandPass";
    case BandReject:
      return "BandReject";
    }
    return "LowPass";
  }

  void FilterParameters::setBand(const QString& b)
  {
    if(!b.isEmpty()) {
      QString bl=b.toLower();
      switch(bl[0].unicode()) {
      case 'l':
        setBand(LowPass);
        break;
      case 'h':
        setBand(HighPass);
        break;
      case 'b':
        if(bl=="bandpass" ||
           bl=="band pass") {            // For compatibility
          setBand(BandPass);
        } else if(bl=="bandreject" ||
                  bl=="band reject") {   // For compatibility
          setBand(BandReject);
        }
        break;
      default:
        break;
      }
    }
  }

  QString FilterParameters::methodString() const
  {
    switch(_method) {
    case Butterworth:
      break;
    case FrequencyWindow:
      return "FrequencyWindow";
    }
    return "Butterworth";
  }

  void FilterParameters::setMethod(const QString& m)
  {
    if(!m.isEmpty()) {
      QString ml=m.toLower();
      switch(ml[0].unicode()) {
      case 'b':
        if(ml=="butterworth") {
          _method=Butterworth;
          return;
        }
        break;
      case 'c':
        if(ml=="frequencywindow" ||
           ml=="convolution" ||  // For compatibility
           ml=="cosineTaper") {
          _method=FrequencyWindow;
          return;
        }
        break;
      default:
        break;
      }
    }
    App::log(tr("Bad filter method '%1'.\n").arg(m) );
  }

  void FilterParameters::setVersion(PARAMETERS_SETVERSION_ARGS)
  {
    TRACE;
    _window.setVersion(version);
    AbstractParameters::setVersion(version);
  }

  int FilterParameters::keywordCount(PARAMETERS_KEYWORDCOUNT_ARGS) const
  {
    return 7+AbstractParameters::keywordCount();
  }

  int FilterParameters::totalKeywordCount(PARAMETERS_TOTALKEYWORDCOUNT_ARGS) const
  {
    return AbstractParameters::totalKeywordCount()
        +_window.totalKeywordCount();
  }

  void FilterParameters::collectKeywords(PARAMETERS_COLLECTKEYWORDS_ARGS)
  {
    TRACE;
    int baseIndex=AbstractParameters::keywordCount();
    keywords.add(prefix+"FILTER_TYPE"+suffix, this, baseIndex);
    keywords.add(prefix+"FILTER_METHOD"+suffix, this, baseIndex+1);
    keywords.add(prefix+"FILTER_MIN_FREQUENCY"+suffix, this, baseIndex+2);
    keywords.add(prefix+"FILTER_MAX_FREQUENCY"+suffix, this, baseIndex+3);
    keywords.add(prefix+"FILTER_CAUSAL"+suffix, this, baseIndex+4);
    keywords.add(prefix+"FILTER_ORDER"+suffix, this, baseIndex+5);
    keywords.add(prefix+"FILTER_WIDTH"+suffix, this, baseIndex+6);
    _window.collectKeywords(keywords, prefix+"FILTER_", suffix);
  }

  bool FilterParameters::setValue(PARAMETERS_SETVALUE_ARGS)
  {
    TRACE;
    switch(index-AbstractParameters::keywordCount()) {
    case 0:
      setBand(value);
      return true;
    case 1:
      setMethod(value);
      return true;
    case 2:
      _fmin=value.toDouble();
      return true;
    case 3:
      _fmax=value.toDouble();
      return true;
    case 4:
      setCausal(value=="y");
      return true;
    case 5:
      setOrder(value.toInt());
      return true;
    default:
      break;
    }
    return AbstractParameters::setValue(index, value, unit, keywords);
  }

  QString FilterParameters::toString(PARAMETERS_TOSTRING_ARGS_IMPL) const
  {
    TRACE;
    QString log;
    log+=prefix+"FILTER_TYPE"+suffix+"="+bandString()+"\n";
    log+=prefix+"FILTER_METHOD"+suffix+"="+methodString()+"\n";
    log+=prefix+"FILTER_MIN_FREQUENCY"+suffix+" (Hz)="+QString::number(_fmin)+"\n";
    log+=prefix+"FILTER_MAX_FREQUENCY"+suffix+" (Hz)="+QString::number(_fmax)+"\n";
    switch(_method) {
    case Butterworth:
      log+=prefix+"FILTER_CAUSAL"+suffix+" (y/n)="+(causal() ? "y" : "n")+"\n";
      log+=prefix+"FILTER_ORDER"+suffix+"="+QString::number(_order)+"\n";
      break;
    case FrequencyWindow:
      log+=_window.toString(prefix+"FILTER_", suffix);
      log+=prefix+"FILTER_WIDTH"+suffix+"="+QString::number(_width);
      break;
    }
    return log;
  }

} // namespace GeopsyCore
