/***************************************************************************
**
**  This file is part of QGpCoreMath.
**
**  This library is free software; you can redistribute it and/or
**  modify it under the terms of the GNU Lesser General Public
**  License as published by the Free Software Foundation; either
**  version 2.1 of the License, or (at your option) any later version.
**
**  This file 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 Lesser General Public
**  License for more details.
**
**  You should have received a copy of the GNU Lesser General Public
**  License along with this library; if not, write to the Free Software
**  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
**
**  See http://www.geopsy.org for more information.
**
**  Created: 2007-02-23
**  Copyright: 2007-2019
**    Marc Wathelet
**    Marc Wathelet (LGIT, Grenoble, France)
**
***************************************************************************/


#include "SmoothingParameters.h"

namespace QGpCoreMath {

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

    Full description of class still missing
  */

  /*!
    Description of constructor still missing
  */
  SmoothingParameters::SmoothingParameters()
    : AbstractParameters()
  {
    TRACE;
    _method=Function;
    _widthType=Constant;
    _width=1.0;
    _order=2;
    _scaleType=SamplingParameters::Linear;
  }

  /*!
    Description of constructor still missing
  */
  SmoothingParameters::SmoothingParameters(const SmoothingParameters& o)
    : AbstractParameters(o),
      _windowFunction(o._windowFunction)
  {
    TRACE;
    _method=o._method;
    _widthType=o._widthType;
    _width=o._width;
    _order=o._order;
    _scaleType=o._scaleType;
  }

  double SmoothingParameters::minimum(double x0) const
  {
    switch(_widthType) {
    case Constant:
      break;
    case Proportional:
      return x0*(1.0-_width);
    case Log:
      return x0/(1.0+_width);
    }
    return x0-0.5*_width;
  }

  double SmoothingParameters::maximum(double x0) const
  {
    switch(_widthType) {
    case Constant:
      break;
    case Proportional:
    case Log:
      return x0*(1.0+_width);
    }
    return x0+0.5*_width;
  }

  QString SmoothingParameters::widthTypeString() const
  {
    switch(_widthType) {
    case Constant:
      break;
    case Proportional:
      return "Proportional";
    case Log:
      return "Log";
    }
    return "Constant";
  }

  void SmoothingParameters::setWidthType(const QString& t)
  {
    if(!t.isEmpty()) {
      QString tl=t.toLower();
      switch(tl[0].unicode()) {
      case 'c':
        if(tl=="constant") {
          _widthType=Constant;
          return;
        }
        break;
      case 'l':
        if(tl=="log") {
          _widthType=Log;
          return;
        }
        break;
      case 'p':
        if(tl=="proportional") {
          _widthType=Proportional;
        }
      default:
        break;
      }
    }
    App::log(tr("Bad width type '%1'.\n").arg(t));
  }

  QString SmoothingParameters::methodString() const
  {
#ifdef SAVITZKY_GOLAY
    switch(_method) {
    case Function:
      break;
    case SavitzkyGolay:
      return "SavitzkyGolay";
    }
#endif
    return "Function";
  }

  void SmoothingParameters::setMethod(const QString& t)
  {
    if(!t.isEmpty()) {
      QString tl=t.toLower();
      switch(tl[0].unicode()) {
      case 'f':
        if(tl=="function") {
          _method=Function;
          return;
        }
        break;
      case 's':
        if(tl=="savitzkygolay") {
#ifdef SAVITZKY_GOLAY
          _method=SavitzkyGolay;
#endif
          return;
        }
        break;
      default:
        break;
      }
    }
    App::log(tr("Bad method '%1'.\n").arg(t));
  }

  void SmoothingParameters::setWidthTypeCompatibility(const QString& t)
  {
    if(!t.isEmpty()) {
      QString tl=t.toLower();
      switch(tl[0].unicode()) {
      case 'c':
        if(tl=="constant") {
          _method=Function;
          _widthType=Constant;
          _windowFunction.setShape(WindowFunctionParameters::Bartlett);
          return;
        }
        break;
      case 'k':
        if(tl=="konnoomachi" ||
           tl=="konnoohmachi") { // Kept for compatibility
          _method=Function;
          _widthType=Log;
          _windowFunction.setShape(WindowFunctionParameters::KonnoOhmachi);
          return;
        }
        break;
      case 'p':
        if(tl=="proportional") {
          _method=Function;
          _widthType=Proportional;
          _windowFunction.setShape(WindowFunctionParameters::Bartlett);
        }
      case 'n':
        if(tl=="nosmoothing") {
          _method=Function;
          _widthType=Constant;
          _windowFunction.setShape(WindowFunctionParameters::Rectangular);
          _width=0.0;
        }
      default:
        break;
      }
    }
    App::log(tr("Bad width type '%1'.\n").arg(t));
  }

  void SmoothingParameters::setWidthCompatibility(double w)
  {
    switch(_widthType) {
    case Constant:
    case Proportional:
      _width=w;
      break;
    case Log:
      _width=pow(10.0, M_PI/w)-1.0;
      break;
    }
  }

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

  int SmoothingParameters::totalKeywordCount(PARAMETERS_TOTALKEYWORDCOUNT_ARGS) const
  {
    return AbstractParameters::totalKeywordCount()+
           _windowFunction.totalKeywordCount();
  }

  void SmoothingParameters::collectKeywords(PARAMETERS_COLLECTKEYWORDS_ARGS)
  {
    TRACE;
    int baseIndex=AbstractParameters::keywordCount();
    keywords.add(prefix+"SMOOTHING_WIDTH_TYPE"+suffix, this, baseIndex);
    keywords.add(prefix+"SMOOTHING_WIDTH"+suffix, this, baseIndex+1);
    keywords.add(prefix+"SMOOTHING_TYPE"+suffix, this, baseIndex+2);        // Kept for compatibility
    keywords.add(prefix+"SMOOTHING_CONSTANT"+suffix, this, baseIndex+3);    // Kept for compatibility
    keywords.add(prefix+"SMOOTHING_METHOD"+suffix, this, baseIndex+4);
    keywords.add(prefix+"SMOOTHING_ORDER"+suffix, this, baseIndex+5);
    keywords.add(prefix+"SMOOTHING_SCALE_TYPE"+suffix, this, baseIndex+6);
    _windowFunction.collectKeywords(keywords, prefix+"SMOOTHING_", suffix);
  }

  bool SmoothingParameters::setValue(PARAMETERS_SETVALUE_ARGS)
  {
    TRACE;
    bool ok=true;
    switch(index-AbstractParameters::keywordCount()) {
    case 0:
      setWidthType(value);
      return true;
    case 1:
      setWidth(value.toDouble());
      return true;
    case 2:                           // Kept for compatibility
      obsoleteKeyword(keywords, 2);
      setWidthTypeCompatibility(value);
      return true;
    case 3:                           // Kept for compatibility
      obsoleteKeyword(keywords, 3);
      setWidthCompatibility(value.toDouble());
      return true;
    case 4:
      setMethod(value);
      return true;
    case 5:
      setOrder(value.toInt(&ok));
      return ok;
    case 6:
      setScaleType(SamplingParameters::type(value));
      return true;
    default:
      break;
    }
    return AbstractParameters::setValue(index, value, unit, keywords);
  }

  QString SmoothingParameters::toString(PARAMETERS_TOSTRING_ARGS_IMPL) const
  {
    TRACE;
    QString log;
    log+=prefix+"SMOOTHING_METHOD"+suffix+"="+methodString()+"\n";
    log+=prefix+"SMOOTHING_WIDTH_TYPE"+suffix+"="+widthTypeString()+"\n";
    log+=prefix+"SMOOTHING_WIDTH"+suffix+"="+QString::number(_width)+"\n";
    log+=prefix+"SMOOTHING_SCALE_TYPE"+suffix+"="+SamplingParameters::type(scaleType())+"\n";
#ifdef SAVITZKY_GOLAY
    log+=prefix+"SMOOTHING_ORDER"+suffix+"="+QString::number(_order)+"\n";
#endif
    log+=_windowFunction.toString(prefix+"SMOOTHING_", suffix);
    return log;
  }

} // namespace QGpCoreMath
