/** \file
 *
 *  Contains the SimACommsMessage class declaration.
 *
 *  Copyright (c) 2007,2008,2009 MBARI
 *  MBARI Proprietary Information.  All Rights Reserved
 */

#ifndef SIMACOMMSMESSAGE_H_
#define SIMACOMMSMESSAGE_H_

#include <math.h>

#include "utils/Str.h"
#include "utils/Timestamp.h"
#include "utils/FlexArray.h"


enum ACommsQueryState
{
    ACOMMS_QUERY_READY,
    ACOMMS_QUERY_QUEUED,
    ACOMMS_QUERY_SENT,
    ACOMMS_QUERY_RECIEVED,
    ACOMMS_QUERY_DONE,
    ACOMMS_QUERY_INVALID
};

class SimACommsMessage
{
public:
    SimACommsMessage( int destination = -1, int source  = -1, int msgID = 0 );

    ~SimACommsMessage()
    {}

    int getDestination( void )
    {
        return destination_;
    }

    int getID( void )
    {
        return msgID_;
    }

    int getSource( void )
    {
        return source_;
    }

    const ACommsQueryState getState( void )
    {
        return state_;
    }

    Timestamp getTxTime( void )
    {
        return txTime_;
    }

    void setState( ACommsQueryState newState )
    {
        state_ = newState;
    }

    void setTxTime( Timestamp txTime )
    {
        txTime_ = txTime;
    }

    void setAcTimeout( Timespan acTimeout )
    {
        acTimeout_ = acTimeout;
    }

    const Timespan txElapsedTime( void );

    bool isTimedOut( void );

    void clear( void );

protected:
    ACommsQueryState state_;

    int destination_;

    int source_;

    Timestamp txTime_;

    Timestamp rxTime_;

    Timespan acTimeout_;

    unsigned int msgID_;
};


class SimACommsDataMessage : public SimACommsMessage
{
    friend class SimACommsDataGazebo;

public:
    SimACommsDataMessage( int destination, int source, const Str& message, float maxDistance, float delay, float mediumSpeed );

    SimACommsDataMessage( int destination, int source, const Str& message );

    ~SimACommsDataMessage()
    {}

    void read( int& destination, int& source, Str& message, float& maxDistance, float& delay, float& mediumSpeed );

    void read( int& destination, int& source, Str& message );

    void clear( void );

private:

    Str message_;

    float maxDistance_;
    float delay_;
    float mediumSpeed_;
};


class SimACommsRangeMessage : public SimACommsMessage
{
    friend class SimACommsRangeGazebo;

public:

    SimACommsRangeMessage();

    SimACommsRangeMessage( int destination, int source, int msgID, int numPings = 1 );

    ~SimACommsRangeMessage()
    {}

    void clear( void );

    void writeOutgoing( int destination, int source, int numPings = 1 );

    void readOutgoing( int& destination, int& source, int& numPings, int& msgID );

    void writeIncoming( float range, float azimuth, float elevation, const Timestamp& rxTime );

    void readIncoming( float& range, float& azimuth, float& elevation, Timestamp& rxTime );

private:

    class RangeResponse
    {
    public:
        RangeResponse( float range, float azimuth, float elevation, const Timestamp& rxTime )
            : range__( range ),
              azimuth__( azimuth ),
              elevation__( elevation ),
              rxTime__( rxTime )
        {}

        void read( float& range, float& azimuth, float& elevation, Timestamp& rxTime )
        {
            range = range__;
            azimuth = azimuth__;
            elevation = elevation__;
            rxTime = rxTime__;
        }

    private:
        double range__;

        double azimuth__;

        double elevation__;

        Timestamp rxTime__;
    };

    FlexArray<RangeResponse*> rangeResponses_;

    int numRecieved_;

    int numPings_;
};

#endif /* SIMACOMMSHANDLER_H_ */
