#ifndef SATOBS_H
#define SATOBS_H

#include <string>
#include <map>
#include <newmat.h>
#include "ppp.h"
#include "bnctime.h"

namespace BNC {

typedef std::string t_obsType;

class t_station;

class t_satObs {
 public:
  t_satObs(const t_pppSatObs& pppSatObs);
  ~t_satObs();
  bool                isValid() const {return _valid;}
  void                prepareObs();
  const t_prn&        prn() const {return _prn;}
  const ColumnVector& xc() const {return _xcSat;}
  const bncTime&      time() const {return _time;}
  t_irc               cmpModel(const t_station* station);
  double              obsValue(t_lc::type tLC) const;
  double              cmpValue(t_lc::type tLC) const;
  double              cmpValueForBanc(t_lc::type tLC) const;
  double              rho() const {return _model._rho;}
  double              sagnac() const {return _model._sagnac;}
  double              eleSat() const {return _model._eleSat;}
  bool                modelSet() const {return _model._set;}
  void                printModel() const;
  t_irc               createDifference(const t_satObs* obsBase);
  double              lc(t_lc::type tLC, double L1, double L2, 
                         double C1, double C2, ColumnVector* coeff = 0) const;
  double              lambda(t_lc::type tLC) const;
  double              sigma(t_lc::type tLC) const;
  bool                outlier() const {return _outlier;}
  void                setOutlier() {_outlier = true;}
  int                 channel() const {return _channel;}
  void                setRes(t_lc::type tLC, double res);
  double              getRes(t_lc::type tLC) const;

  bool slip() const {
    std::map<t_obsType, t_obs*>::const_iterator it;
    for (it = _allObs.begin(); it != _allObs.end(); it++) {
      if (it->second->_slip) {
        return true;
      }
    }
    return false;
  }

  int slipCounter() const {
    int cnt = -1;
    std::map<t_obsType, t_obs*>::const_iterator it;
    for (it = _allObs.begin(); it != _allObs.end(); it++) {
      if (it->second->_slipCounter > cnt) {
        cnt = it->second->_slipCounter;
      }
    }
    return cnt;
  }

  int biasJumpCounter() const {
    int jmp = -1;
    std::map<t_obsType, t_obs*>::const_iterator it;
    for (it = _allObs.begin(); it != _allObs.end(); it++) {
      if (it->second->_biasJumpCounter > jmp) {
        jmp = it->second->_biasJumpCounter;
      }
    }
    return jmp;
  }

 private:
  class t_model {
   public:
    t_model() {reset();}
    ~t_model() {}
    void reset() {
      _set     = false;
      _rho     = 0.0;
      _eleSat  = 0.0;
      _azSat   = 0.0;
      _recClkM = 0.0;
      _satClkM = 0.0;
      _sagnac  = 0.0;
      _antEcc  = 0.0;
      _tropo   = 0.0;
      _tide    = 0.0;
      _windUp  = 0.0;
      _antPco1 = 0.0;
      _antPco2 = 0.0;
      _biasC1  = 0.0;
      _biasC2  = 0.0;
      _biasL1  = 0.0;
      _biasL2  = 0.0;
    }
    bool   _set;
    double _rho;
    double _eleSat;
    double _azSat;
    double _recClkM;
    double _satClkM;
    double _sagnac;
    double _antEcc;
    double _tropo;
    double _tide;
    double _windUp;
    double _antPco1;
    double _antPco2;
    double _biasC1;
    double _biasC2;
    double _biasL1;
    double _biasL2;
  };

  t_prn                       _prn;
  bncTime                     _time;
  int                         _channel;
  std::map<t_obsType, t_obs*> _allObs;
  bool                        _valid;
  t_obs*                      _validObs1;
  t_obs*                      _validObs2;
  double                      _f1;
  double                      _f2;
  double                      _rawC1;
  double                      _rawC2;
  double                      _rawL1;
  double                      _rawL2;
  ColumnVector                _xcSat;
  ColumnVector                _vvSat;
  t_model                     _model;
  bool                        _outlier;
  std::map<t_lc::type, double> _res;
};

}

#endif
