#include "NMEA.h"
#include "BicamConsts.h"
#include "stdio.h"
/** \file GPRMC.cc */

/****************************************************************************/
/* Copyright (c) 2008 MBARI                                                 */
/* MBARI Proprietary Information. All rights reserved.                      */
/****************************************************************************/
/* Summary  :                                                               */
/* Filename : GPRMC.cc                                                      */
/* Author   : K Headley                                                     */
/* Project  : Benthic Imaging AUV                                           */
/* Created  : 04/01/2008                                                    */
/****************************************************************************/
/* Modification History:                                                    */
/*  $Id: GPRMC.cc,v 1.4 2009/04/09 23:35:21 rob Exp $   */
/*  $Name: FastSim $ */
/****************************************************************************/

/** Default no argument constructor */
GPRMC::GPRMC(){
  time_t tm;
  struct timeval tv;

  // set message type 
  _type=t_GPRMC;

  // initialze fields
  _fields[RMCMSG].setValue("$GPRMC");

  time(&tm);
  tv.tv_sec=tm;
  tv.tv_usec=0;

  _fields[RMCTIME].setValue((time_t)tm);
  _fields[RMCTVTIME].setValue((struct timeval)tv);
  _fields[RMCSTAT].setValue((char)'?');
  _fields[RMCLATD].setValue((int)0);
  _fields[RMCLATM].setValue((double)0.0);
  _fields[RMCLATH].setValue((char)'?');
  _fields[RMCLOND].setValue((int)0);
  _fields[RMCLONM].setValue((double)0.0);
  _fields[RMCLONH].setValue((char)'?');
  _fields[RMCSOG].setValue((double)0.0);
  _fields[RMCCOG].setValue((double)0.0);
  _fields[RMCDATE].setValue((time_t)tm);
  _fields[RMCMVM].setValue((double)0);
  _fields[RMCMVD].setValue((double)0);
  _fields[RMCCHK].setValue((unsigned char)0);
}

/** Set time field
    @param time new value
    @return OK on success, ERROR otherwise
 */
int GPRMC::setTIME(time_t time){
  setField(NMEA::FIELD_1,time);
  return 0;
}
/** Set status field
    @param stat new value
    @return OK on success, ERROR otherwise
 */
int GPRMC::setSTAT(char stat){
  if(stat!='A' && stat!='V')
    return ERROR;
  setField(NMEA::FIELD_2,stat);
  return OK;
}
/** Set lat degrees field
    @param latd new value
    @return OK on success, ERROR otherwise
 */
int GPRMC::setLATD(int latd){
  if(latd>90 || latd<-90)
    return ERROR;
  setField(NMEA::FIELD_3,latd);
  return OK;
}
/** Set lat minutes field
    @param latm new value
    @return OK on success, ERROR otherwise
 */
int GPRMC::setLATM(double latm){
  if(latm<0.0000 || latm>59.9999)
    return ERROR;
  setField(NMEA::FIELD_4,latm);
  return OK;
}
/** Set lat hemisphere field
    @param lath new value
    @return OK on success, ERROR otherwise
 */
int GPRMC::setLATH(char lath){
  if(lath!='S' && lath!='N')
    return ERROR;
  setField(NMEA::FIELD_5,lath);
  return OK;
}
/** Set lon degrees field
    @param lond new value
    @return OK on success, ERROR otherwise
 */
int GPRMC::setLOND(int lond){
  if(lond>180 || lond<-180)
    return ERROR;
  setField(NMEA::FIELD_6,lond);
  return OK;
}
/** Set lon min field
    @param lonm new value
    @return OK on success, ERROR otherwise
 */
int GPRMC::setLONM(double lonm){
  if(lonm<0.0000 || lonm>59.9999)
    return ERROR;
    setField(NMEA::FIELD_7,lonm);
  return OK;
}
/** Set lon hemisphere field
    @param lonh new value
    @return OK on success, ERROR otherwise
 */
int GPRMC::setLONH(char lonh){
  if(lonh!='E' && lonh!='W')
    return ERROR;
  setField(NMEA::FIELD_8,lonh);
  return OK;
}
/** Set speed over ground field
    @param sog new value
    @return OK on success, ERROR otherwise
 */
int GPRMC::setSOG(double sog){
  if(sog<000.0 || sog>999.9)
    return ERROR;
  setField(NMEA::FIELD_9,sog);
  return OK;
}
/** Set course over ground field
    @param cog new value
    @return OK on success, ERROR otherwise
 */
int GPRMC::setCOG(double cog){
  if(cog<0000.0 || cog>359.9)
    return ERROR;
  setField(NMEA::FIELD_10,cog);
  return OK;
}
/** Set date field
    @param date new value
    @return OK on success, ERROR otherwise
 */
int GPRMC::setDATE(time_t date){
  setField(NMEA::FIELD_11,date);
  return 0;
}
  /** Set Magnetic Variation Magnitude
    @param mvm (0.0-180.0 degrees)
    @return OK on success, ERROR otherwise (may indicate input range error)
  */
int GPRMC::setMVM(double mvm){
  if(mvm<000.0 || mvm>180.0)
    return ERROR;
  setField(NMEA::FIELD_12,mvm);
  return OK;
}
/** Set Magnetic Variation Direction
    @param mvd ('E':East|'W':West)
    @return OK on success, ERROR otherwise (may indicate input range error)
*/
int GPRMC::setMVD(char mvd){
  if(mvd!='E' && mvd!='W')
    return ERROR;
  setField(NMEA::FIELD_13,mvd);
  return OK;
}
/** Set time field
    @param time new value
    @return OK on success, ERROR otherwise
 */
int GPRMC::setTIME(struct timeval time){
  setField(NMEA::FIELD_15,(struct timeval)time);
  return OK;
}
/** Generate NMEA string from current field values
    @return string representation of NMEA message. 
*/
const char *GPRMC::toString(){
   return toString(NMEA::NOTERM);
 }
const char *GPRMC::toString(NMEA::LineEnd lineEnd){
  int hours;
  int min;
  int mon,day,year;
  double sec;
  struct tm *pt;
  struct timeval tvtime;

  char *bp=_outputBuf;
  unsigned int chksum;

  Field f=this->_fields[GPRMC::RMCTVTIME];
  tvtime=f.tvalValue();
  pt=gmtime( &tvtime.tv_sec );
  hours= pt->tm_hour;
  min  = pt->tm_min;
  sec  = (double)pt->tm_sec+((double)tvtime.tv_usec/1000000.0);
  mon  = pt->tm_mon+1;
  day  = pt->tm_mday;
  year = pt->tm_year;

  while(year>100)
    year-=100;
  
  sprintf(bp,"%6s,",this->_fields[GPRMC::RMCMSG].pcharValue());
  bp=_outputBuf+strlen(_outputBuf);
  sprintf(bp,"%02d%02d%0*.*f,",hours,min,(_timestampRes+3),_timestampRes,sec);
  bp=_outputBuf+strlen(_outputBuf);
  sprintf(bp,"%c,",this->_fields[GPRMC::RMCSTAT].charValue());
  bp=_outputBuf+strlen(_outputBuf);
  sprintf(bp,"%d%07.4f,%c,",this->_fields[GPRMC::RMCLATD].intValue(),this->_fields[GPRMC::RMCLATM].doubleValue(),this->_fields[GPRMC::RMCLATH].charValue());
  bp=_outputBuf+strlen(_outputBuf);
  sprintf(bp,"%d%07.4f,%c,",this->_fields[GPRMC::RMCLOND].intValue(),this->_fields[GPRMC::RMCLONM].doubleValue(),this->_fields[GPRMC::RMCLONH].charValue());
  bp=_outputBuf+strlen(_outputBuf);
  sprintf(bp,"%05.1f,",this->_fields[GPRMC::RMCSOG].doubleValue());
  bp=_outputBuf+strlen(_outputBuf);
  sprintf(bp,"%05.1f,",this->_fields[GPRMC::RMCCOG].doubleValue());
  bp=_outputBuf+strlen(_outputBuf);
  sprintf(bp,"%02d%02d%02d,",day,mon,year);
  bp=_outputBuf+strlen(_outputBuf);
  sprintf(bp,"%05.1f,",this->_fields[GPRMC::RMCMVM].doubleValue());
  bp=_outputBuf+strlen(_outputBuf);
  sprintf(bp,"%c*",this->_fields[GPRMC::RMCMVD].charValue());
  bp=_outputBuf+strlen(_outputBuf);

  chksum=this->checksum(_outputBuf);

  sprintf(bp,"%02x",chksum);

  if(lineEnd!=NMEA::NOTERM){
    bp=_outputBuf+strlen(_outputBuf);
    sprintf(bp,"\r\n");
  }

  return _outputBuf;
  
}

/** output stream operator.
    Formats object for output stream insertion
    @param output output stream handle
    @param n Field object pointer
   
*/
ostream& operator<<(ostream& output,GPRMC& n) {
  /*
#ifdef _QNX
  char buf[128];
  ostrstream outs(buf,128);
#else
  ostringstream outs;
#endif
  output<<n.toString();
  */
  // for multiple << operators.
  return output;  
#ifdef _QNX
  output<<n.toString()<<ends;
#else
  output<<n.toString();
#endif
  return output;  // for multiple << operators.

}
