/***************************************************************************
**
**  This file is part of QGpCoreMath.
**
**  QGpCoreMath 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.
**
**  QGpCoreMath 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: 2011-11-18
**  Copyright: 2011-2019
**    Marc Wathelet (ISTerre, Grenoble, France)
**
***************************************************************************/

#include "WindowFunctionParameters.h"

namespace QGpCoreMath {

  /*!
    \class WindowFunctionParameters WindowFunctionParameters.h
    \brief Parameters for taper computation

    The details about each window type is given at
    http://en.wikipedia.org/wiki/Window_function
  */

  /*!
    Defaults to Tukey window or tapered cosine window. This was originally
    the only type of window available in Geopsy.
  */
  WindowFunctionParameters::WindowFunctionParameters()
    : AbstractParameters()
  {
    _shape=Tukey;
    _reversed=false;
    _alpha=0.5;
  }

  WindowFunctionParameters::WindowFunctionParameters(const WindowFunctionParameters &o)
    : AbstractParameters(o)
  {
    _shape=o._shape;
    _reversed=o._reversed;
    _alpha=o._alpha;
  }

  QString WindowFunctionParameters::shapeString() const
  {
    switch(_shape) {
    case Rectangular:
      break;
    case Bartlett:
      return "Bartlett";
    case Triangular:
      return "Triangular";
    case Parzen:
      return "Parzen";
    case Welch:
      return "Welch";
    case Cosine:
      return "Cosine";
    case Hann:
      return "Hann";
    case Hamming:
      return "Hamming";
    case Tukey:
      return "Tukey";
    case Lanczos:
      return "Lanczos";
    case Gaussian:
      return "Gaussian";
    case BartlettHann:
      return "BartlettHann";
    case Blackman:
      return "Blackman";
    case Nuttall:
      return "Nuttall";
    case BlackmanHarris:
      return "BlackmanHarris";
    case BlackmanNuttall:
      return "BlackmanNuttall";
    case FlatTop:
      return "FlatTop";
    case KonnoOhmachi:
      return "KonnoOhmachi";
    }
    return "Rectangular";
  }

  void WindowFunctionParameters::setShape(QString s)
  {
    s=s.toLower();
    if(!s.isEmpty()) {
      switch(s[0].unicode()) {
      case 'b':
        if(s=="bartlett") {
          _shape=Bartlett;
          return;
        } else if(s=="bartlettHann") {
          _shape=BartlettHann;
          return;
        } else if(s=="blackman"){
          _shape=Blackman;
          return;
        } else if(s=="blackmanHarris") {
          _shape=BlackmanHarris;
          return;
        } else if(s=="blackmanNuttall") {
          _shape=BlackmanNuttall;
          return;
        }
        break;
      case 'c':
        if(s=="cosine") {
          _shape=Cosine;
          return;
        }
        break;
      case 'f':
        if(s=="flattop") {
          _shape=FlatTop;
          return;
        }
        break;
      case 'g':
        if(s=="gaussian") {
          _shape=Gaussian;
          return;
        }
        break;
      case 'h':
        if(s=="hann") {
          _shape=Hann;
          return;
        } else if(s=="hamming"){
          _shape=Hamming;
          return;
        }
        break;
      case 'k':
        if(s=="konnoohmachi") {
          _shape=KonnoOhmachi;
          return;
        }
        break;
      case 'l':
        if(s=="lanczos") {
          _shape=Lanczos;
          return;
        }
        break;
      case 'n':
        if(s=="nuttall") {
          _shape=Nuttall;
          return;
        }
        break;
     case 'p':
        if(s=="parzen") {
          _shape=Parzen;
          return;
        }
        break;
      case 'r':
        if(s=="rectangular") {
          _shape=Rectangular;
          return;
        }
        break;
      case 't':
        if(s=="tukey" ||
           s=="tuckey") {   // Kept for compatibility
          _shape=Tukey;
          return;
        } else if(s=="triangular"){
          _shape=Triangular;
          return;
        }
        break;
      case 'w':
        if(s=="welch") {
          _shape=Welch;
          return;
        }
        break;
      default:
        break;
      }
    }
    App::log(tr("Bad taper window '%1'.\n").arg(s) );
  }

  QString WindowFunctionParameters::toString(PARAMETERS_TOSTRING_ARGS_IMPL) const
  {
    TRACE;
    QString log;
    log+=prefix+"WINDOW_TYPE"+suffix+"="+shapeString()+"\n";
    log+=prefix+"WINDOW_REVERSED"+suffix+"="+(_reversed ? "y" : "n")+"\n";
    switch(_shape) {
    case Tukey:
    case Blackman:
      log+=prefix+"WINDOW_ALPHA"+suffix+"="+QString::number(alpha())+"\n";
      break;
    case Gaussian:
      log+=prefix+"WINDOW_SIGMA"+suffix+"="+QString::number(sigma())+"\n";
      break;
    default:
      break;
    }
    return log;
  }

  int WindowFunctionParameters::keywordCount(PARAMETERS_KEYWORDCOUNT_ARGS) const
  {
    return 4+AbstractParameters::keywordCount();
  }

  void WindowFunctionParameters::collectKeywords(PARAMETERS_COLLECTKEYWORDS_ARGS)
  {
    TRACE;
    int baseIndex=AbstractParameters::keywordCount();
    keywords.add(prefix+"WINDOW_TYPE"+suffix, this, baseIndex);
    keywords.add(prefix+"WINDOW_REVERSED"+suffix, this, baseIndex+1);
    keywords.add(prefix+"WINDOW_SIGMA"+suffix, this, baseIndex+2);
    keywords.add(prefix+"WINDOW_ALPHA"+suffix, this, baseIndex+3);
  }

  bool WindowFunctionParameters::setValue(PARAMETERS_SETVALUE_ARGS)
  {
    TRACE;
    bool ok=true;
    switch(index-AbstractParameters::keywordCount()) {
    case 0:
      setShape(value);
      return true;
    case 1:
      setReversed(value=="y");
      return true;
    case 2:
      setSigma(value.toDouble(&ok));
      return ok;
    case 3:
      setAlpha(value.toDouble(&ok));
      return ok;
    default:
      break;
    }
    return AbstractParameters::setValue(index, value, unit, keywords);
  }

  QString WindowFunctionParameters::toShortString() const
  {
    TRACE;
    QString args;
    if(_reversed) {
      args+="reversed ";
    }
    args+=shapeString();
    switch(_shape) {
    case WindowFunctionParameters::Tukey:
    case WindowFunctionParameters::Blackman:
    case WindowFunctionParameters::Gaussian:
      args+=" ";
      args+=QString::number(_alpha);
      break;
    default:
      break;
    }
    return args;
  }

  void WindowFunctionParameters::fromShortString(QString s)
  {
    TRACE;
    // Default value
    _shape=Tukey;
    _alpha=0.2;
    _reversed=false;
    // Remove useless spaces
    s=s.trimmed();
    if(s.startsWith("reversed ")) {
      _reversed=true;
      s=s.mid(9, -1);
    }
    setShape(s.section(QRegExp(" +"), 0, 0));
    switch(_shape) {
    case WindowFunctionParameters::Tukey:
    case WindowFunctionParameters::Blackman:
    case WindowFunctionParameters::Gaussian:
      _alpha=s.section(QRegExp(" +"), 1, 1).toDouble();
      break;
    default:
      break;
    }
  }

} // namespace QGpCoreMath
