/***************************************************************************
**
**  This file is part of GeopsySLink.
**
**  GeopsySLink 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.
**
**  GeopsySLink 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-04-24
**  Copyright: 2007-2019
**    Marc Wathelet
**    Marc Wathelet (LGIT, Grenoble, France)
**
***************************************************************************/

#include <GeopsyCore.h>

#include "SeedLinkStream.h"
#include "SeedLinkStation.h"
#include "SeedLinkServer.h"

namespace GeopsySLink {

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

  Full description of class still missing
*/

const QString SeedLinkStream::xmlSeedLinkStreamTag="stream";

SeedLinkStream::SeedLinkStream(SeedLinkStation * station)
{
  TRACE;
  _station=station;
  _location="  ";
  _signal=nullptr;
  _listening=false;
}

void SeedLinkStream::xml_attributes(XML_ATTRIBUTES_ARGS) const
{
  TRACE;
  Q_UNUSED(context)
  static const QString keys[]={ "location", "seedname", "type", "begin_time", "end_time", "begin_recno", "end_recno", "gap_check", "gap_threshold" };
  attributes.add(keys[0], _location);
  attributes.add(keys[1], _seedName);
  attributes.add(keys[2], _type);
  attributes.add(keys[3], _beginTime);
  attributes.add(keys[4], _endTime);
  attributes.add(keys[5], QString::number(_beginRecNo) );
  attributes.add(keys[6], QString::number(_endRecNo) );
  attributes.add(keys[7], _gapCheck ? "enabled" : "disabled" );
  attributes.add(keys[8], QString::number(_gapThreshold) );
}

bool SeedLinkStream::xml_setAttributes(XML_SETATTRIBUTES_ARGS)
{
  TRACE;
  Q_UNUSED(context)
  for(XMLRestoreAttributeIterator it=attributes.begin(); it!= attributes.end(); it++ ) {
    const StringSection& att=it.key();
    if(att.size()<1) return false;
    switch (att[0].unicode()) {
    case 'l':
      if(att=="location" ) _location=it.value().toString(); else return false;
      break;
    case 's':
      if(att=="seedname" ) _seedName=it.value().toString(); else return false;
      break;
    case 't':
      if(att=="type" ) _type=it.value().toString(); else return false;
      break;
    case 'b':
      if(att=="begin_time" ) _beginTime=it.value().toString();
      else if(att=="begin_recno" ) _beginRecNo=it.value().toInt(); else return false;
      break;
    case 'e':
      if(att=="end_time" ) _endTime=it.value().toString();
      else if(att=="end_recno" ) _endRecNo=it.value().toInt(); else return false;
      break;
    case 'g':
      if(att=="gap_check" ) _gapCheck=it.value()=="enabled";
      else if(att=="gap_treshold" ) _gapThreshold=it.value().toInt(); else return false;
      break;
    default:
      return false;
    }
  }
  setTag();
  return true;
}

void SeedLinkStream::setTag()
{
  TRACE;
  _tag=_station->network().left(2).toLatin1();
  _tag+="_";
  _tag+=_station->name().leftJustified(5,' ',true).toLatin1();
  _tag+=_location.left(2).leftJustified(2,' ',true).toLatin1();
  _tag+=_seedName.left(3).leftJustified(3,' ',true).toLatin1();
}

/*!
  Initialize internal signal starting at \a t.
*/
void SeedLinkStream::initSignal(const DateTime& t, double samplingFrequency)
{
  TRACE;
  if(createSignal()) {
    _signal->setSamplingFrequency(samplingFrequency);
    _signal->setStartTime(t);
  }
}

bool SeedLinkStream::createSignal()
{
  TRACE;
  SignalDatabase * db=_station->server()->database();
  if(db) {
    _signal=new DynamicSignal(db);
    _signal->setName(_station->network() + "_" + _station->name());
    if(seedName().endsWith( "Z" ))
      _signal->setComponent(Signal::Vertical);
    else if(seedName().endsWith( "E" ))
      _signal->setComponent(Signal::East);
    else if(seedName().endsWith( "N" ))
      _signal->setComponent(Signal::North);
    else
      _signal->setComponent(Signal::UndefinedComponent);
    _signal->setType(Signal::Waveform);
    _signal->setHeaderModified(true);
    _signal->setReadOnlySamples(true);
    return true;
  } else {
    App::log(tr("In SeedLinkStream::createSignal(), no database specified.\n") );
    return false;
  }
}

/*!
  \a t is the number of seconds counted from time reference.

  \a maxTime is the maximum expected duration when applicable (rotate, createNew)
*/
void SeedLinkStream::set(const DateTime& t, int * samples, int nSamples, BufferType bt, double maxTime)
{
  TRACE;
  switch (bt) {
  case Unlimited:
    _signal->set(t, samples, nSamples);
    break;
  case CreateNew: {
      if(maxTime==0.0) return;
      double availableTime=maxTime-_signal->startTime().secondsTo(t);
      if((nSamples*_signal->samplingPeriod())>availableTime) {
        int nSamplesOld=qFloor(availableTime/_signal->samplingPeriod());
        _signal->set(t, samples, nSamplesOld);
        DynamicSignal * oldSignal=_signal;
        if(createSignal()) {
          _signal->setStartTime(oldSignal->endTime());
          _signal->setSamplingPeriod(oldSignal->samplingPeriod());
          _signal->set(_signal->startTime(), samples+nSamplesOld, nSamples-nSamplesOld);
        }
      } else {
        _signal->set(t, samples, nSamples);
      }
    }
    break;
  case Rotate: {
      if(maxTime==0.0) return;
      double availableTime=maxTime-_signal->startTime().secondsTo(t);
      if((nSamples*_signal->samplingPeriod())>availableTime) {
        int n=nSamples-qFloor(availableTime/_signal->samplingPeriod());
        _signal->shiftStartTime(n);
      }
      _signal->set(t, samples, nSamples);
    }
    break;
  }
}

} // namespace GeopsySLink
