/* -------------------------------------------------------------------------
 * BKG NTRIP Client
 * -------------------------------------------------------------------------
 *
 * Class:      t_pppEphPool
 *
 * Purpose:    Buffer with satellite ephemerides
 *
 * Author:     L. Mervart
 *
 * Created:    29-Jul-2014
 *
 * Changes:
 *
 * -----------------------------------------------------------------------*/

#include <iostream>
#include <iomanip>
#include "pppEphPool.h"
#include "pppInclude.h"
#include "pppClient.h"

using namespace BNC_PPP;
using namespace std;

//
/////////////////////////////////////////////////////////////////////////////
void t_pppEphPool::putEphemeris(t_eph* eph) {
  if (eph && (eph->checkState() != t_eph::bad ||
              eph->checkState() != t_eph::unhealthy ||
              eph->checkState() != t_eph::outdated))  {
    _satEphPool[eph->prn().toInt()].putEphemeris(_maxQueueSize, eph);
  }
  else {
    delete eph;
  }
}

//
/////////////////////////////////////////////////////////////////////////////
void t_pppEphPool::putOrbCorrection(t_orbCorr* corr) {
  if (corr) {
    _satEphPool[corr->_prn.toInt()].putOrbCorrection(corr);
    if (OPT->_logMode > t_pppOptions::normal) {
      LOG << "orbCorr " << string(corr->_time) << ' ' << corr->_prn.toString() << endl;
    }
  }
}

//
/////////////////////////////////////////////////////////////////////////////
void t_pppEphPool::putClkCorrection(t_clkCorr* corr) {
  if (corr) {
    _satEphPool[corr->_prn.toInt()].putClkCorrection(corr);
    if (OPT->_logMode > t_pppOptions::normal) {
      LOG.setf(ios::fixed);
      LOG << "clkCorr " << string(corr->_time) << ' ' << corr->_prn.toString() << ' '
          << setw(7) << setprecision(3) << corr->_dClk * t_CST::c << endl;
    }
  }
}

//
/////////////////////////////////////////////////////////////////////////////
t_irc t_pppEphPool::getCrd(const t_prn& prn, const bncTime& tt,
                             ColumnVector& xc, ColumnVector& vv) const {
  return _satEphPool[prn.toInt()].getCrd(tt, xc, vv);
}

//
/////////////////////////////////////////////////////////////////////////////
int t_pppEphPool::getChannel(const t_prn& prn) const {
  return _satEphPool[prn.toInt()].getChannel();
}

//
/////////////////////////////////////////////////////////////////////////////
void t_pppEphPool::t_satEphPool::putEphemeris(unsigned maxQueueSize, t_eph* eph) {
  if (_ephs.empty() || eph->isNewerThan(_ephs.front())) {
    _ephs.push_front(eph);
    if (maxQueueSize > 0 && _ephs.size() > maxQueueSize) {
      delete _ephs.back();
      _ephs.pop_back();
    }
  }
  else {
    delete eph;
  }
}

//
/////////////////////////////////////////////////////////////////////////////
void t_pppEphPool::t_satEphPool::putOrbCorrection(t_orbCorr* corr) {
  if (_ephs.empty()) {
    return;
  }

  for (unsigned ii = 0; ii < _ephs.size(); ii++) {
    t_eph* eph = _ephs[ii];
    if (eph->IOD() == corr->_iod) {
      eph->setOrbCorr(corr);
    }
    else {
      LOG << "putOrbCorrection " << corr->_prn.toString() << " corrIOD = " << corr->_iod << " ephIODs = ";
      for (auto* e : _ephs) LOG << e->IOD() << " ";
      LOG << endl;
    }
  }
  delete corr;
}

//
/////////////////////////////////////////////////////////////////////////////
void t_pppEphPool::t_satEphPool::putClkCorrection(t_clkCorr* corr) {
  if (_ephs.empty()) {
    return;
  }

  for (unsigned ii = 0; ii < _ephs.size(); ii++) {
    t_eph* eph = _ephs[ii];
    if (eph->IOD() == corr->_iod) {
      eph->setClkCorr(corr);
    }
    else {
      LOG << "putClockCorrection " << corr->_prn.toString() << " corrIOD = " << corr->_iod << " ephIODs = ";
      for (auto* e : _ephs) LOG << e->IOD() << " ";
      LOG << endl;
    }
  }
  delete corr;
}

//
/////////////////////////////////////////////////////////////////////////////
t_irc t_pppEphPool::t_satEphPool::getCrd(const bncTime& tt, ColumnVector& xc,
                                           ColumnVector& vv) const {
  if (_ephs.empty()) {
    return failure;
  }

  for (unsigned ii = 0; ii < _ephs.size(); ii++) {
    const t_eph* eph = _ephs[ii];
    t_irc irc = eph->getCrd(tt, xc, vv, OPT->useOrbClkCorr());
    if (irc == success) {
        if (outDatedBcep(eph, tt)) {
          continue;
      }
      return irc;
    }
  }
  return failure;
}

//
/////////////////////////////////////////////////////////////////////////////
int t_pppEphPool::t_satEphPool::getChannel() const {
  if (!_ephs.empty()) {
    return _ephs[0]->slotNum();
  }
  return 0;
}
