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

#include "MiniSeedTrace.h"

namespace GeopsyCore {

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

  Represents a Mini Seed trace.
  This class is used only while reading a new file.
  Function records() returns a compact description of records to be stored in Signal.
*/

/*!
  Description of constructor still missing
*/
MiniSeedTrace::MiniSeedTrace(LibMSeed::MSRecord * msr)
{
  TRACE;
  _network=msr->network;
  _station=msr->station;
  _location=msr->location;
  _channel=msr->channel;
  _samplingFrequency=msr->samprate;
  _deltaT=1.0/_samplingFrequency;
  _sorted=false;
}

/*!
  Description of constructor still missing
*/
MiniSeedTrace::MiniSeedTrace(const MiniSeedTrace& t)
{
  TRACE;
  _network=t._network;
  _station=t._station;
  _location=t._location;
  _channel=t._channel;
  _samplingFrequency=t._samplingFrequency;
  _deltaT=t._deltaT;
  _sorted=true;
}

MiniSeedTrace::~MiniSeedTrace()
{
  TRACE;
  qDeleteAll(_records);
}

/*!
  Add new samples from record \a msr located at position \a pos in mseed volume.
*/
void MiniSeedTrace::addRecord(LibMSeed::MSRecord * msr, off_t pos)
{
  TRACE;
  Record * rec=new Record;
  _records.append(rec);
  LibMSeed::BTime& t=msr->fsdh->start_time;
  rec->_startTime=DateTime(QDate(t.year, 1, 1), 0, 0.0);
  rec->_startTime.addDays(t.day-1);
  // Time is stored with a precision of 100 us in seed blocket
  // t.fract is the fractional second from 0 to 9999
  rec->_startTime.setTime(t.hour, t.min, t.sec);
  rec->_startTime.addFewSeconds(t.fract*0.0001);
  rec->_nSamples=msr->samplecnt;
  rec->_byteLength=msr->reclen;
  rec->_pos=pos;
  /*printf("Adding record to %s_%s:%s\t\t%i\t%i\t%li\t%s\t%lf\n",
         _network.toLatin1().data(), _station.toLatin1().data(), _channel.toLatin1().data(),
         rec->_nSamples, rec->_byteLength, rec->_pos,
         rec->_startTime.toString("yyyy-MM-dd hh:mm:ssz").toLatin1().data());*/
}

bool MiniSeedTrace::belongsTo(LibMSeed::MSRecord * msr)
{
  TRACE;
  return _network==msr->network &&
         _station==msr->station &&
         _location==msr->location &&
         _channel==msr->channel &&
         _samplingFrequency==msr->samprate;
}

int MiniSeedTrace::nSamples() const
{
  TRACE;
  int n=0;
  for(QList<Record*>::const_iterator it=_records.begin(); it!=_records.end(); it++) {
    n+=(*it)->_nSamples;
  }
  return n;
}

MiniSeedRecords MiniSeedTrace::records() const
{
  TRACE;
  int n=_records.count();
  MiniSeedRecords recs;
  for(int i=0; i<n; i++) {
    const Record& r=*_records.at(i);
    recs.add(r._pos, r._byteLength);
  }
  return recs;
}

/*!
  Slit non-continuous trace, does nothing except sorting records by increasing time
  if the trace is continous.
*/
MiniSeedTrace * MiniSeedTrace::split()
{
  TRACE;
  if(!_sorted) {
    std::sort(_records.begin(), _records.end(), Record::lessThan);
    _sorted=true;
  }
  int n=_records.count();
  Record * last=_records.at(0);
  for(int i=1; i<n;i++) {
    Record * current=_records.at(i);
    double elapsed=last->_startTime.secondsTo(current->_startTime);
    /*printf("Checking continuity of %s_%s:%s\t\t%i\t%lf\t%s\t%lf\n",
          _network.toLatin1().data(), _station.toLatin1().data(), _channel.toLatin1().data(),
          current->_nSamples, fabs(nElapsed - last->_nSamples),
          current->_startTime.toString("yyyy-MM-dd hh:mm:ss").toLatin1().data(), current->_t0);*/
    double duration=_deltaT*last->_nSamples;
    if(fabs(elapsed-duration)>=0.0001) { // MiniSeed has a 100 us presicion on times
      if(elapsed>duration) {
        MiniSeedTrace * sig=new MiniSeedTrace(*this);
        // Move all remaining records including the current to the new trace
        for(int j=i; j<n; j++) {
          sig->_records.append(_records.at(j));
        }
        for(int j=i; j<n; j++) {
          _records.removeLast();
        }
        return sig;
      } else {
        // overlaping records: look for matching records further in the list
        MiniSeedTrace * sig=new MiniSeedTrace(*this);
        splitOverlapping(i, sig);
        /*printf("After split overlapping new sig[%i] starts at %s %lf and ends at %s %lf\n", sig->nSamples(),
               sig->_records.first()->_startTime.toString("yyyy-MM-dd hh:mm:ss").toLatin1().data(), sig->_records.first()->_t0,
               sig->_records.last()->_startTime.toString("yyyy-MM-dd hh:mm:ss").toLatin1().data(), sig->_records.last()->_t0);
        printf("After split overlapping this sig[%i] starts at %s %lf and ends at %s %lf\n", nSamples(),
               _records.first()->_startTime.toString("yyyy-MM-dd hh:mm:ss").toLatin1().data(), _records.first()->_t0,
               _records.last()->_startTime.toString("yyyy-MM-dd hh:mm:ss").toLatin1().data(), _records.last()->_t0);*/
        return sig;
      }
    } else {
      last=current;
    }
  }
  return nullptr;
}

/*!
  Splits overlapping traces, grab all matching records for this trace and leave all other to sig.
  The record list of sig is supposed to be empty. \a firstRecord is the index of the first overlapping
  record.
*/
void MiniSeedTrace::splitOverlapping(int firstRecord, MiniSeedTrace * sig)
{
  TRACE;
  int n=_records.count();
  Record * last=_records.at(firstRecord-1);
  for(int i=firstRecord; i<n;i++) {
    Record * current=_records.at(i);
    double elapsed=last->_startTime.secondsTo(current->_startTime);
    /*printf("Overlapping of %s_%s:%s\t\t%i\t%lf\t%s\t%lf\n",
          _network.toLatin1().data(), _station.toLatin1().data(), _channel.toLatin1().data(),
          current->_nSamples, fabs(nElapsed - last->_nSamples),
          current->_startTime.toString("yyyy-MM-dd hh:mm:ss").toLatin1().data(), current->_t0);*/
    double duration=_deltaT*last->_nSamples;
    if(fabs(elapsed-duration)>=0.0001) { // MiniSeed has a 100 us presicion on times
      if(elapsed>duration) {
        // Move all remaining records including the current to trace sig
        for(int j=i; j<n; j++) {
          sig->_records.append(_records.at(j));
         }
        for(int j=i; j<n; j++) {
          _records.removeLast();
        }
        return;
      } else {
        // still overlapping, move this record to sig
        sig->_records.append(current);
        _records.removeAt(i);
        n--;
        i--;
      }
    } else {
      last=current;
    }
  }
}

} // namespace GeopsyCore
