#pragma ident "$Id: RinexClockHeader.hpp 3140 2012-06-18 15:03:02Z susancummins $"

/**
 * @file RinexClockHeader.hpp
 * Encapsulate header of RinexClock file data, including I/O
 */

#ifndef GPSTK_RINEX_CLOCK_HEADER_HPP
#define GPSTK_RINEX_CLOCK_HEADER_HPP

#include <string>
#include <vector>
#include <map>
#include "RinexClockBase.hpp"
#include "RinexSatID.hpp"
#include "TimeSystem.hpp"

namespace gpstk
{
   /** @addtogroup RinexClock */
   //@{

      /// This class models the header for a RINEX Clock file.
      /// @sa gpstk::RinexClockStream and gpstk::RinexClockData for more information.
      /// @sa ?.cpp for an example.
   class RinexClockHeader : public RinexClockBase
   {
   public:

         /// constructor
      RinexClockHeader() : version(3.0), leapSeconds(0), timeSystem(TimeSystem::Any),
                    pcvsSystem(1, RinexSatID::systemGPS),
                    numSolnStations(0), numSolnSatellites(0)
                    {}

         /**
          * @name RinexClockHeaderFormatStrings
          * RINEX Clock Header Formatting Strings
          */
         //@{
      static const std::string versionString;         ///< "RINEX VERSION / TYPE"
      static const std::string runByString;           ///< "PGM / RUN BY / DATE"
      static const std::string commentString;         ///< "COMMENT"
      static const std::string sysString;             ///< "SYS / # / OBS TYPES"
      static const std::string timeSystemString;      ///< "TIME SYSTEM ID"
      static const std::string leapSecondsString;     ///< "LEAP SECONDS"
      static const std::string sysDCBString;          ///< "SYS / DCBS APPLIED"
      static const std::string sysPCVString;          ///< "SYS / PCVS APPLIED"
      static const std::string numDataString;         ///< "# / TYPES OF DATA"
      static const std::string stationNameString;     ///< "STATION NAME / NUM"
      static const std::string stationClockRefString; ///< "STATION CLK REF"
      static const std::string analysisCenterString;  ///< "ANALYSIS CENTER"
      static const std::string numClockRefString;     ///< "# OF CLK REF"
      static const std::string analysisClkRefrString; ///< "ANALYSIS CLK REF"
      static const std::string numReceiversString;    ///< "# OF SOLN STA / TRF"
      static const std::string solnStateString;       ///< "SOLN STA NAME / NUM"
      static const std::string numSolnSatsString;     ///< "# OF SOLN SATS"
      static const std::string prnListString;         ///< "PRN LIST"
      static const std::string endOfHeaderString;     ///< "END OF HEADER"
         //@}

         /// Validity bits for the RINEX Clock Header (** optional)
      enum validBits
      {
         versionValid            = 0x01, ///< "RINEX VERSION / TYPE"
         runByValid              = 0x02, ///< "PGM / RUN BY / DATE"
         commentValid            = 0x04, ///< "COMMENT" **
         sysValid                = 0x08, ///< "SYS / # / OBS TYPES" **

         timeSystemValid        = 0x010, ///< "TIME SYSTEM ID" **
         leapSecondsValid       = 0x020, ///< "LEAP SECONDS" **
         sysDCBValid            = 0x040, ///< "SYS / DCBS APPLIED" **
         sysPCVValid            = 0x080, ///< "SYS / PCVS APPLIED" **

         numDataValid          = 0x0100, ///< "# / TYPES OF DATA"
         stationNameValid      = 0x0200, ///< "STATION NAME / NUM" **
         stationClockRefValid  = 0x0400, ///< "STATION CLK REF" **
         analysisCenterValid   = 0x0800, ///< "ANALYSIS CENTER"

         numClockRefValid     = 0x01000, ///< "# OF CLK REF" **
         analysisClkRefrValid = 0x02000, ///< "ANALYSIS CLK REF" **
         numReceiversValid    = 0x04000, ///< "# OF SOLN STA / TRF"
         solnStateValid       = 0x08000, ///< "SOLN STA NAME / NUM"

         numSolnSatsValid    = 0x010000, ///< "# OF SOLN SATS"
         prnListValid        = 0x020000, ///< "PRN LIST"
         endOfHeaderValid    = 0x040000, ///< "END OF HEADER"

       //allRequiredValid    = 0x07F9A3, ///< this mask if for all required fields
       //allRequiredValid    = 0x07F903, ///< this mask if for all required fields
         allRequiredValid    = 0x07C903, ///< this mask if for all required fields
         allValid            = 0x07FFFF  ///< all the bits
      };

         /// destructor
      virtual ~RinexClockHeader() {}

         // The next four lines is our common interface
         /// RinexClockHeader is a "header" so this function always returns true.
      virtual bool isHeader() const { return true; }
     
      /// Dump information about the header to an ostream.
      /// @param[in] os ostream to receive the output; defaults to std::cout
      /// @param[in] detail integer level of detail to provide; allowed values are
      ///    0: all the header string except stations and satellites, but their num.
      ///    1: above plus all the stations and satellites
      ///    2: above plus all invalid header strings (dumpValid)
      virtual void dump(std::ostream& s=std::cout, short detail = 0) const throw();

         /// Dump validity bits -> header strings
      void dumpValid(std::ostream& s=std::cout) const throw();

         ///@name data members
         //@{

      double version;                        ///< RinexClock Version or file format
      std::string program;                   ///< Program name
      std::string runby;                     ///< Run by string
      std::vector<std::string> dataTypes;    ///< list of data types
      int leapSeconds;                       ///< Leap seconds
      TimeSystem timeSystem;                 ///< Time system

      std::string analCenterDesignator;      ///< Analysis center designator (3 char)
      std::string analysisCenter;            ///< Analysis center
      std::string terrRefFrame;              ///< Terr Ref Frame or SINEX solution
      RinexSatID pcvsSystem;                 ///< system (G=GPS, R=GLO) for PCVs
      std::string pcvsProgram;               ///< program used to apply PCVs
      std::string pcvsSource;                ///< source of applied PCVs

      int numSolnStations;                   ///< Number of stations in the solution
      std::map<std::string,std::string> stationID; ///< 4-char name, station id
      // NB these coordinates are often more than 32 bits -- cannot store as number!
      std::map<std::string,std::string> stationX;  ///< name, station X coord in mm
      std::map<std::string,std::string> stationY;  ///< name, station Y coord in mm
      std::map<std::string,std::string> stationZ;  ///< name, station Z coord in mm

      int numSolnSatellites;                  ///< Number of satellites in the soln
      std::vector<RinexSatID> satList;        ///< List of sats (PRN LIST)

      std::vector<std::string> commentList;   ///< comments

      unsigned long valid;                    ///< valid bits for this header

         //@}

   protected:
         /// clear out the member data
      void clear(void) {
         version = 3.0;
         program = std::string();
         runby = std::string();
         dataTypes.clear();
         leapSeconds = 0;
         analysisCenter = std::string();
         terrRefFrame = std::string();
         timeSystem = TimeSystem::Any;
         pcvsSystem = RinexSatID(-1, RinexSatID::systemGPS);
         pcvsProgram = std::string();
         pcvsSource = std::string();
         numSolnStations = 0;
         stationID.clear();
         stationX.clear();
         stationY.clear();
         stationZ.clear();
         numSolnSatellites = 0;
         satList.clear();
         commentList.clear();

         valid = 0;
      }

         /// Writes the record formatted to the FFStream \a s.
         /// @throws StringException when a StringUtils function fails
      virtual void reallyPutRecord(FFStream& s) const 
         throw(std::exception, FFStreamError,
               StringUtils::StringException);

         /// This function retrieves the RinexClock header from the given FFStream.
         /// If an error is encountered in the retrieval of the header, the
         /// stream is reset to its original position and its fail-bit is set.
         /// @throws StringException when a StringUtils function fails
         /// @throws FFStreamError when exceptions(failbit) is set and
         ///  a read or formatting error occurs.  This also resets the
         ///  stream to its pre-read position.
      virtual void reallyGetRecord(FFStream& s) 
         throw(std::exception, FFStreamError,
               StringUtils::StringException);

   }; // end class RinexClockHeader

   //@}

}  // namespace

#endif // GPSTK_RINEX_CLOCK_HEADER_HPP

