/***************************************************************************
**
**  This file is part of HVCore.
**
**  HVCore 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.
**
**  HVCore 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: 2020-02-18
**  Copyright: 2020
**    Marc Wathelet (ISTerre, Grenoble, France)
**
***************************************************************************/

#include "AbstractStation.h"
#include "AbstractResults.h"
#include "HVParameters.h"

namespace HVCore {

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

    Full description of class still missing
  */

  /*!
    Description of constructor still missing
  */
  AbstractStation::AbstractStation(StationProcessSignals * sig)
    : QObject(nullptr)
  {
    TRACE;
    _signals=sig;
    _windowsChanged=false;
    _keep=nullptr;
  }

  /*!
    Description of destructor still missing
  */
  AbstractStation::~AbstractStation()
  {
    TRACE;
    delete _signals;
    delete _keep;
    qDeleteAll(_results);
  }

  QString AbstractStation::shortFileName() const
  {
    TRACE;
    Signal * sig=_signals->originalSignals()->firstValidSignal();
    if(sig) {
      SignalFile * file=sig->file();
      if(file)
        return file->shortName();
      else
        return "### temporary signal ###";
    } else {
      return "Error: empty station";
    }
  }

  void AbstractStation::addResults()
  {
    _results.append(nullptr);
    AbstractResults *& r=_results.last();
    r=createResults();
    r->setCoordinates(originalSignals()->coordinates());
  }

  void AbstractStation::clearResults()
  {
    TRACE;
    int nResults=_results.count();
    for(int i=0; i<nResults; i++) {
      _results[i]->clear();
    }
  }

  void AbstractStation::initResults(int windowCount, const HVParameters& param)
  {
    TRACE;
    int nResults=_results.count();
    for(int i=0; i<nResults; i++) {
      _results[i]->setWindows(windowCount, param);
    }
  }


  /*!
    Compute the local keep of this station.
  */
  SparseKeepSignal * AbstractStation::keep(const TimeRange& r, const WindowingParameters& param, int stationIndex) const
  {
    TRACE;
    SparseTimeRange sr=timeRange(r);
    SparseKeepSignal * keep=new SparseKeepSignal(sr);
    setSampling(keep);
    keep->initValues(1);
    setKeep(keep, param, stationIndex);
    return keep;
  }

  bool AbstractStation::addWindows(QTextStream& s, const QString& beginPattern, const QString& endPattern)
  {
    _windowsChanged=true;
    return _timeWindows.add(s, beginPattern, endPattern);
  }

  void AbstractStation::addWindows(const TimeRange& r, const WindowingParameters& param, const SparseKeepSignal& keep)
  {
    TRACE;
    if(_timeWindows.isEmpty()) {
      // Enter a fake frequency of 1 (Freq. dep. option should not be used here)
      _timeWindows.add(1, param, keep, r);
    } else {
      // Enter a fake frequency of 1 (Freq. dep. option should not be used here)
      _timeWindows.addBlanks(1, param, keep, r);
    }
    _windowsChanged=true;
  }

  void AbstractStation::removeWindows(const TimeRange& r)
  {
    TRACE;
    _timeWindows.remove(r);
    _windowsChanged=true;
  }


  void AbstractStation::inverseWindows(const TimeRange& r, const WindowingParameters& param, const SparseKeepSignal& keep)
  {
    TRACE;
    // Enter a fake frequency of 1 (Freq. dep. option should not be used here)
    _timeWindows.inverse(1, param, keep, r);
    _windowsChanged=true;
  }

  void AbstractStation::clearAllWindows()
  {
    if(_timeWindows.clear()) {
      _windowsChanged=true;
    }
  }

  void AbstractStation::clearGrayWindows()
  {
    TRACE;
    Color c(Qt::gray);
    for(int i=_timeWindows.count()-1; i>=0; i--) {
      if(_timeWindows.at(i).color()==c) {
        _timeWindows.remove(i);
        _windowsChanged=true;
      }
    }
  }

  void AbstractStation::setWindowColors()
  {
    TRACE;
    ColorMap map;
    map.generateColorScale(_timeWindows.count(), ColorPalette::Hsv);
    for(int i=_timeWindows.count()-1; i>=0; i--) {
      _timeWindows.at(i).setColor(map.color(i));
    }
  }

  bool AbstractStation::hasGrayWindows()
  {
    TRACE;
    Color c(Qt::gray);
    for(int i=_timeWindows.count()-1; i>=0; i--) {
     const TimeWindow& w=windowAt(i);
      if(w.color()==c) {
        return true;
      }
    }
    return false;
  }

  void AbstractStation::changeColors(const QVector<int>* selCurves, const Color &col)
  {
    TRACE;
    if(_windowsChanged) {
      App::log(tr("Changing color of windows: "
                  "window set has changed since last calculation. "
                  "Re-process your windows before editing the spectra."));
      return;
    }
    QVector<int>::const_iterator it;
    for(it=selCurves->begin(); it!=selCurves->end(); ++it) {
      _timeWindows.at(*it).setColor(col);
    }
    int nResults=_results.count();
    for(int i=0; i<nResults; i++) {
      _results[i]->setWindowColor(selCurves, col);
    }
    emit windowsChanged();
  }

  bool AbstractStation::save(QDir outputDir, const HVParameters& param)
  {
    TRACE;
    int nResults=_results.count();
    for(int i=0; i<nResults; i++) {
      if(!save(i, outputDir, param)) {
        return false;
      }
    }
    return true;
  }

  double AbstractStation::resultMaxAmplitude() const
  {
    TRACE;
    double max=-std::numeric_limits<double>::infinity();
    int nResults=_results.count();
    for(int i=0; i<nResults; i++) {
      double statMax=_results[i]->maximumAmplitude();
      if(statMax>max) max=statMax;
    }
    return max;
  }

  SignalDatabase * AbstractStation::database() const
  {
    TRACE;
    Signal * sig=_signals->originalSignals()->firstValidSignal();
    if(sig) {
      return sig->database();
    } else {
      return 0;
    }
  }

  void AbstractStation::setStatistics()
  {
    int nResults=_results.count();
    for(int i=0; i<nResults; i++) {
      _results[i]->setStatistics();
    }
  }

  void AbstractStation::setPeaks()
  {
    int nResults=_results.count();
    for(int i=0; i<nResults; i++) {
      _results[i]->setPeaks();
    }
  }

  QString AbstractStation::log(const HVParameters& param) const
  {
    TRACE;
    QString log;
    QTextStream s(&log);
    s << "# HV LOG FORMAT RELEASE 1.0\n";
    CoreApplication::signature(s);
    s << "#\n"
         "# BEGIN SIGNAL LIST\n"
         "#\n";
    SignalDatabase * db=_signals->originalSignals()->firstValidSignal()->database();
    if(db->name().isEmpty()) {
      db=nullptr;
    } else {
      s << "DATA_BASE=" << db->name() << "\n";
    }
    for(int i=0; i<_signals->nComponents(); i++) {
      const SubSignalPool& subpool=_signals->originalSignals()->originals(i);
      for(int j=0; j<subpool.count(); j++) {
        Signal * sig=subpool.at(j);
        s << sig->file()->name() << " at index " << sig->numberInFile();
        if(db) {
          s << " (ID=" << sig->id() << ")";
        }
        s << "\n";
      }
    }
    s << "#\n"
         "# END SIGNAL LIST\n"
         "#\n"
         "#\n"
         "# BEGIN PARAMETERS\n"
         "#\n";
    s << param.toString();
    s << "#\n"
         "# END PARAMETERS\n"
         "#\n"
         "#\n"
         "# BEGIN WINDOWING LOG\n"
         "#\n";
    s << _winLog;
    s << "#\n"
         "# END WINDOWING LOG\n"
         "#\n"
         "#\n"
         "# BEGIN WINDOW LIST\n"
         "#\n";
    s << _timeWindows.toString();
    s << "#\n"
         "# END WINDOW LIST\n"
         "#\n";
    return log;
  }

} // namespace HVCore

