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

//============================================================================
//
//  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 2.1 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
//
//============================================================================
//============================================================================
//
//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.
//
//=============================================================================

#ifndef GPSTK_RINEXOBSID_HPP
#define GPSTK_RINEXOBSID_HPP

/**
 * @file RinexObsID.hpp
 * gpstk::RinexObsID - A specialization of ObsID that has only RINEX-specific
 * observation identifiers.
 */

#include "ObsID.hpp"
#include "RinexObsHeader.hpp"

namespace gpstk
{
   /// Determine if the given ObsID is valid. If the input string is 3 
   /// characters long, the system is unknown and the string is tested with all RINEX
   /// If this string is 4 characters long, the first character is the system
   /// character as described in the Rinex 3 specification.
   bool isValidRinexObsID(const std::string& id);

   /// Determine if the given ObsID is valid, for the given system
   bool isValidRinexObsID(const std::string& id, const char syschar);

   class RinexObsID;
   namespace StringUtils
   {
      /// convert this object to a string representation
      std::string asString(const RinexObsID& id);
   }

   /// class RinexObsID is the set of ObsID's which are valid in RINEX 3.01.
   /// This class simply limits possible values of ObsID, plus a little functionality.
   /// Note it depends critically on map validRinexTrackingCodes, from class ObsID.
   /// This map[sys][freq] = valid codes; e.g.  valid['G'][1]="CSLXPWYMN"
   /// Only exception is there is no pseudorange (C) on GPS L1/L2 N (codeless)
   /// RINEX 3.01 document, section 5.1
   /// sys  freq  code                    ObsID = sys+type+freq+code
   /// GPS   L1   C,S,L,X,P,W,Y,M,N       G CLDS 1 CSLXPWYMN (but not C1N)
   ///       L2   C,D,S,L,X,P,W,Y,M,N     G CLDS 2 CDSLXPWYMN (but not C2N)
   ///       L5   I,Q,X                   G CLDS 5 IQX
   /// GLO   G1   C,P                     R CLDS 1 CP
   ///       G2   C,P                     R CLDS 2 CP
   /// GAL   E1   A,B,C,X,Z               E CLDS 1 ABCXZ
   ///       E5a  I,Q,X                   E CLDS 5 IQX
   ///       E5b  I,Q,X                   E CLDS 7 IQX
   ///       E5ab I,Q,X                   E CLDS 8 IQX
   ///       E6   A,B,C,X,Z               E CLDS 6 ABCXZ
   /// SBAS  L1   C                       S CLDS 1 C
   ///       L5   I,Q,X                   S CLDS 5 IQX
   /// COM   E1   -                       C CLDS 1 -
   ///       E2   I,Q,X                   C CLDS 2 IQX
   ///       E5b  I,Q,X                   C CLDS 7 IQX
   ///       E6   I,Q,X                   C CLDS 6 IQX
   class RinexObsID : public ObsID
   {
   public:
      /// empty constructor, creates an invalid object
      RinexObsID() : ObsID() {};

      /// Explicit constructior
      RinexObsID(ObservationType ot, CarrierBand cb, TrackingCode tc)
         : ObsID(ot, cb, tc) {};
      
      /// Construct this object from the string specifier
      RinexObsID(const std::string& strID) throw(InvalidParameter);

      /// Constructor from ObsID
      RinexObsID(const ObsID& oid) throw(InvalidParameter)
      {
         type=oid.type; band=oid.band; code=oid.code;
         std::string str(this->asString());
         if(!isValidRinexObsID(str)) {
            InvalidParameter ip("Invalid RinexObsID: " + str);
            GPSTK_THROW(ip);
         }
      }

      /// a conversion constructor, giving a fixed one-way mapping from RINEX ver 2
      /// obstypes to RinexObsIDs.
      /// L1 -> L1P; P1 -> C1P; C1 -> C1C; S1 -> S1P; D1 -> D1P
      /// L2 -> L2P; P2 -> C2P; C2 -> C2X; S2 -> S2P; D2 -> D2P
      /// Note that RinexHeader does the conversion with more care for tracking code,
      /// and does NOT USE THIS ROUTINE.
      RinexObsID(const RinexObsHeader::RinexObsType& rot);

      /// This returns a representation of this object using the observation
      /// codes described in section 5.1 of the Rinex 3 specification. Note that
      /// this always returns a three character identifier so some information
      /// is lost because some codes are shared between satellite systems.
      std::string asString() const;

      // see ObsID for definition of validRinexTrackingCodes and validRinexSystems.
      //static std::map<char, std::map<char, std::string> > validRinexTrackingCodes;
      // This string contains the system characters for all valid RINEX systems.
      //static std::string validRinexSystems;

   }; // end class RinexObsID

} // namespace gpstk

#endif
