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

//============================================================================
//
//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 CODEBUFFER_HPP
#define CODEBUFFER_HPP

   // Library headers
#include "CommonTime.hpp"

   // Project headers
#include "PCodeConst.hpp"

namespace gpstk
{
/// @ingroup code    
//@{
      /** P(Y)-code Buffer class.
       *  Applied Research Laboratories, The University of Texas at Austin
       *  August 2003
       *
       *  CodeBuffer is a helper class designed to store P-code information.
       *  Six seconds of code for a particular satellite is stored in each
       *  object.  The satellite is identified by PRNID and the beginning
       *  time is specified in a CommonTime object.  The code is stored in an
       *  array of unsigned long (assumed 32-bit) integers.  The time order 
       *  started with the MSB of first word of the buffer ([0]) and runs 
       *  through the LSB of the last word of the buffer.
       *
       *  The size of the buffer is probably the most notable feature of 
       *  this class. 1.5s (one Z-count) of P(Y)-code is 15,345,000 bits.  
       *  Therefore, 6 seconds is equal to 4 Z-counts or 4 * 15,345,000 bits
       *  = 61,380,000 bits.  These bits are stored in 1,918,125 unsigned 
       *  long integers.  The fact that 61,380,000 is evenly divisble by 32
       *  is not a coincidence, but part of the design.  The constant 
       *  NUM_6SEC_WORDS is used to hold the value 1,918,125 and located in
       *  PCodeConst.h.
       */
   class CodeBuffer
   {
      public:
           /// Defines the type of code held in the buffer 
         //enum codeType { P_CODE, Y_CODE, BOTH }; 
      
            /**
             * Instantiate and initialize a code buffer for a particular
             * satellite.
             */
         CodeBuffer( const int SVPRNID );
         ~CodeBuffer( );
         CodeBuffer& operator=( const CodeBuffer& c );
         
            /**
             * Update the time associated with the buffer and the designation
             * of the data contained in the buffer as P-code or Y-code.
             */
         void updateBufferStatus( const gpstk::CommonTime& dt, 
                                  const codeType PYFlag );

            /**
             * Update the time associated with the buffer and the designation
             * of the data contained in the buffer as P-code or Y-code.  In this
             * case, the time is not being changed, but the code flag may be 
             * changed.
             */
         void updateBufferStatus( const codeType PYFlag ) { POrYCode = PYFlag; }
         
            /// Accessor returning the current time.
         const gpstk::CommonTime& getCurrentTime( ) { return(currentTime); }
         
            /// Accessor returning the type of code in the buffer (P or Y)
         codeType getPYFlag( ) { return(POrYCode); } 
         
            /// Accessor returing the PRN ID of the buffer
         int getPRNID( ) { return(PRNID); }
            
            /// Set or return the designated word of the code buffer.
         unsigned long& operator[]( int i );
         const unsigned long& operator[]( const int i ) const;
         
            /** Given a bit number between 0 and (NUM_6SEC_WORDS * MAX_BIT) - 1,
             * return the value of the bit as a right justified unsigned 
             * long word (0x00000000 or 0x00000001)..
             */
         unsigned long getBit( const long i ) const;
         
            /** Perform an exclusive-or operation on the bits contained in 
             * this instance of CodeBuffer and the instance referenced by cb.
             */
         CodeBuffer& operator^=( const CodeBuffer& cb );
     
      protected:  
         CodeBuffer( const CodeBuffer& c );
         unsigned long * buffer;
         int PRNID;
         gpstk::CommonTime currentTime;
         codeType POrYCode;
   };

   inline  CodeBuffer::~CodeBuffer( ) { delete [] buffer; }
   inline CodeBuffer& CodeBuffer::operator^=( const CodeBuffer& cb )
   { 
      for (long i=0;i<NUM_6SEC_WORDS;++i) buffer[i] ^= cb.buffer[i];
      return( *this );
   }

   inline unsigned long& CodeBuffer::operator[]( int i )
   {
      return(buffer[i]);
   }

   inline const unsigned long& CodeBuffer::operator[]( int i ) const
   {
      return(buffer[i]);
   }

   inline unsigned long CodeBuffer::getBit( const long i ) const
   {
      unsigned long iret;
      long bNdx = i / MAX_BIT;
      long bitNum = i - (bNdx * MAX_BIT);
      iret = buffer[bNdx];
   
      // Shift LEFT to clear off msbs
      iret <<= bitNum;
      // Then shift RIGHT to clear off lsbs
      iret >>= (MAX_BIT-1);
   
      return iret;
   }
   //@}
}     // end of namespace
#endif // CODEBUFFER_HPP
