//============================================================================
//
//  This file is part of GPSTk, the GPS Toolkit.
//
//  The GPSTk is free software; you can redistribute it and/or modify
//  it under the terms of the GNU Lesser General Public License as published
//  by the Free Software Foundation; either version 3.0 of the License, or
//  any later version.
//
//  The GPSTk 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 Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with GPSTk; if not, write to the Free Software Foundation,
//  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
//  
//  Copyright 2004, The University of Texas at Austin
//  Dagoberto Salazar - gAGE ( http://www.gage.es ). 2007, 2008, 2011
//
//============================================================================

//============================================================================
//
//This software developed by Applied Research Laboratories at the University of
//Texas at Austin, under contract to an agency or agencies within the U.S. 
//Department of Defense. The U.S. Government retains all rights to use,
//duplicate, distribute, disclose, or release this software. 
//
//Pursuant to DoD Directive 523024 
//
// DISTRIBUTION STATEMENT A: This software has been approved for public 
//                           release, distribution is unlimited.
//
//=============================================================================

/**
 * @file PhaseCodeAlignment.hpp
 * This class aligns phase with code measurements.
 */

#ifndef GPSTK_PHASECODEALIGNMENT_HPP
#define GPSTK_PHASECODEALIGNMENT_HPP

#include "ProcessingClass.hpp"



namespace gpstk
{

      /// @ingroup GPSsolutions 
      //@{


      /** This class aligns phase with code measurements.
       *
       * This class is meant to be used with the GNSS data structures objects
       * found in "DataStructures" class.
       *
       * A typical way to use this class follows:
       *
       * @code
       *      // INITIALIZATION PART
       *
       *      // EBRE station nominal position
       *   Position nominalPos(4833520.192, 41537.1043, 4147461.560);
       *   RinexObsStream rin("ebre0300.02o");  // Data stream
       *
       *      // Load all the SP3 ephemerides files
       *   SP3EphemerisStore SP3EphList;
       *   SP3EphList.loadFile("igs11512.sp3");
       *   SP3EphList.loadFile("igs11513.sp3");
       *   SP3EphList.loadFile("igs11514.sp3");
       *
       *      // More declarations here: ComputeMOPSWeights, SimpleFilter,
       *      // LICSDetector, MWCSDetector, SolidTides, OceanLoading,
       *      // PoleTides, CorrectObservables, ComputeWindUp, ComputeLinear,
       *      // LinearCombinations, SolverPPP, etc...
       *
       *      // Object to align phase (LC) with code (PC) measurements
       *   PhaseCodeAlignment phaseAlign;
       *
       *     // PROCESSING PART
       *
       *   gnssRinex gRin;
       *
       *   while(rin >> gRin)
       *   {
       *      try
       *      {
       *         gRin  >> basicM
       *               >> correctObs
       *               >> compWindup
       *               >> computeTropo
       *               >> linear
       *               >> pcFilter
       *               >> markCSLI
       *               >> markCSMW
       *               >> markArc
       *               >> phaseAlign
       *               >> pppSolver;
       *      }
       *      catch(...)
       *      {
       *         cerr << "Unknown exception at epoch: " << time << endl;
       *         continue;
       *      }
       *
       *         // Print results
       *      cout << time.DOYsecond()      << "  "; // Output field #1
       *      cout << pppSolver.solution[1] << "  "; // dx: Output field #2
       *      cout << pppSolver.solution[2] << "  "; // dy: Output field #3
       *      cout << pppSolver.solution[3] << "  "; // dz: Output field #4
       *      cout << pppSolver.solution[0] << "  "; // wetTropo: Out field #5
       *      cout << endl;
       *   }
       * @endcode
       *
       * The "PhaseCodeAlignment" object will visit every satellite in the GNSS
       * data structure that is "gRin" and, if an arc change or cycle slip has
       * happened, it will compute a phase offset in order to take the phase
       * measurement close to the corresponding code measurement.
       *
       * By default, "PhaseCodeAlignment" objects will align the
       * ionosphere-free phase combination (LC) with the corresponding code
       * (PC). Also, it will check changes in satellite arcs in order to know
       * when offset recomputing is necessary. All these defaults may be
       * changed with the appropriate methods.
       *
       * The use of this class is not mandatory; however, it is recommendable
       * given that resulting phase ambiguities are smaller, and it
       * potentially improves the numerical stability of the solver.
       *
       * \warning Be aware that if you change the phase/code pair, you must
       * change the wavelength accordingly.
       *
       * \warning Objects in this class store their internal state, so you
       * MUST NOT use the SAME object to process DIFFERENT data streams.
       *
       * @sa SatArcMarker.hpp, LICSDetector.hpp and MWCSDetector.hpp.
       *
       */
   class PhaseCodeAlignment : public ProcessingClass
   {
      public:

         /// Default constructor.
      PhaseCodeAlignment()
         : phaseType(TypeID::LC), codeType(TypeID::PC),
           phaseWavelength(0.1069533781421467), useSatArcs(true),
           watchCSFlag(TypeID::CSL1)
      { };


         /** Common constructor
          *
          * @param phase            Phase TypeID.
          * @param code             Code TypeID.
          * @param wavelength       Phase wavelength, in meters.
          * @param useArc           Whether satellite arcs will be used or not.
          */
      PhaseCodeAlignment( const TypeID& phase,
                          const TypeID& code,
                          const double wavelength,
                          bool useArc = true );


         /// Method to get the phase TypeID being used.
      virtual TypeID getPhaseType() const
      { return phaseType; };


         /** Method to set the phase TypeID to be used.
          *
          * @param phase            Phase TypeID.
          */
      virtual PhaseCodeAlignment& setPhaseType(const TypeID& phase)
      { phaseType = phase; return (*this); };


         /// Method to get the code TypeID being used.
      virtual TypeID getCodeType() const
      { return codeType; };


         /** Method to set the code TypeID to be used.
          *
          * @param code             Code TypeID.
          */
      virtual PhaseCodeAlignment& setCodeType(const TypeID& code)
      { codeType = code; return (*this); };


         /// Method to get phase wavelength being used.
      virtual double getPhaseWavelength() const
      { return phaseWavelength; };


         /** Method to set the phase wavelength to be used.
          *
          * @param wavelength       Phase wavelength, in meters.
          */
      virtual PhaseCodeAlignment& setPhaseWavelength(double wavelength);


         /// Method to get if this class will use satellite arcs (true) or
         /// cycle slip flags (false).
      virtual bool getUseSatArc() const
      { return useSatArcs; };


         /** Method to set if this class will use satellite arcs (true) or
          *  cycle slip flags (false).
          *
          * @param useArc           Whether this class will use satellite arcs
          *                         (true) or cycle slip flags (false).
          */
      virtual PhaseCodeAlignment& setUseSatArc(bool useArc)
      { useSatArcs = useArc; return (*this); };


         /// Method to get the default CS flag type being used.
      virtual TypeID getCSFlag() const
      { return watchCSFlag; };


         /** Method to set the default CS flag type to be used.
          *
          * @param watchFlag     Cycle slip flag to be watched.
          */
      virtual PhaseCodeAlignment& setCSFlag(const TypeID& watchFlag)
      { watchCSFlag = watchFlag; return (*this); };


         /** Returns a satTypeValueMap object, adding the new data generated
          *  when calling this object.
          *
          * @param epoch     Time of observations.
          * @param gData     Data object holding the data.
          */
      virtual satTypeValueMap& Process( const CommonTime& epoch,
                                        satTypeValueMap& gData )
         throw(ProcessingException);


         /** Returns a gnnsSatTypeValue object, adding the new data generated
          *  when calling this object.
          *
          * @param gData    Data object holding the data.
          */
      virtual gnssSatTypeValue& Process(gnssSatTypeValue& gData)
         throw(ProcessingException);


         /** Returns a gnnsRinex object, adding the new data generated when
          *  calling this object.
          *
          * @param gData    Data object holding the data.
          */
      virtual gnssRinex& Process(gnssRinex& gData)
         throw(ProcessingException);


         /// Returns a string identifying this object.
      virtual std::string getClassName(void) const;


         /// Destructor
      virtual ~PhaseCodeAlignment() {};


   private:


         /// TypeID of phase measurement.
      TypeID phaseType;


         /// TypeID of code measurement.
      TypeID codeType;


         /// Wavelength of phase measurement.
      double phaseWavelength;


         /** Flag indicating if this class will watch for satellite arcs (true)
          *  or cycle slip flags (false).
          */
      bool useSatArcs;


         /// If field 'useSatArcs' is false, cycle slip flag to be watched.
      TypeID watchCSFlag;


         /// Structure used to store SV alignment data.
      struct alignData
      {
            // Default constructor initializing the data in the structure
         alignData() : arcNumber(0.0), offset(0.0) {};

         double arcNumber;       ///< Current arc number
         double offset;          ///< Offset value to be applied
      };


         /// Map holding the information regarding every satellite
      std::map<SatID, alignData> svData;


   }; // End of class 'PhaseCodeAlignment'

      //@}

}  // End of namespace gpstk

#endif   // GPSTK_PHASECODEALIGNMENT_HPP
