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

#ifndef SIMCOMMSSTRUCT_H_
#define SIMCOMMSSTRUCT_H_

#include <math.h>
#include <stdint.h>

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

class Simulator;

/**
 *  A struct of values that is passed from the LRAUV to the Simulator, to
 *  run one timestep of the simulator.
 *
 *  \ingroup modules_simulator
 */
struct SimCommsStructToSim
{
    int16_t destinationId_;
    int16_t sourceId_;
    int16_t length_;
    int16_t maxDistance_;   // Outgoing message - maximum distance (in m) of transmission
    float delay_;           // Time for message serializaton/deserialization, second
    float mediumSpeed_;     // Outgoing message - normally speed of sound in water, m/s -- set to zero if instantaneous


    // variable length message begins here, not part of struct

    /// Constructor
    SimCommsStructToSim()
        : destinationId_( 0 ),
          sourceId_( 0 ),
          length_( 0 ),
          maxDistance_( 0 ),
          delay_( 0 ),
          mediumSpeed_( 0 )
    {}
    SimCommsStructToSim( int destinationId, int sourceId, int length, int maxDistance, float delay, float mediumSpeed )
        : destinationId_( destinationId ),
          sourceId_( sourceId ),
          length_( length ),
          maxDistance_( maxDistance ),
          delay_( delay ),
          mediumSpeed_( mediumSpeed )
    {}

};

struct SimCommsStructFromSim
{
    int16_t destinationId_;
    int16_t sourceId_;
    int16_t length_;
    float sourceLatitude_;  // Incoming message source
    float sourceLongitude_;     // Incoming message source
    // variable length message begins here, not part of struct

    /// Constructor
    SimCommsStructFromSim()
        : destinationId_( 0 ),
          sourceId_( 0 ),
          length_( 0 ),
          sourceLatitude_( nanf( "" ) ),
          sourceLongitude_( nanf( "" ) )
    {}

};

class SimCommsEntry
{
public:
    /// Constructor
    SimCommsEntry( const SimCommsStructToSim& toSim, char* message, const double& latitude, const double& longitude )
        : destinationId_( toSim.destinationId_ ),
          sourceId_( toSim.sourceId_ ),
          length_( toSim.length_ ),
          message_( message, toSim.length_ ),
          sourceLatitude_( latitude ),
          sourceLongitude_( longitude ),
          sims_( true )
    {
    }

    const Str& getMessage()
    {
        return message_;
    }

    void addSim( Simulator* sim, Timespan delay )
    {
        SimCommsItem* commsItem = new SimCommsItem();
        commsItem->sim_ = sim;
        commsItem->arrivesAt_ = Timestamp::Now() + delay;
        sims_.push( commsItem );
    }

    bool dataForSim( Simulator* sim, const Timestamp& now )
    {
        for( int i = ( int )sims_.size() - 1; i >= 0; --i )
        {
            SimCommsItem* commsItem = sims_.get( i );
            if( commsItem->sim_ == sim && commsItem->arrivesAt_ < now )
            {
                delete sims_.pop( i );
                return true;
            }
            if( commsItem->arrivesAt_ - now > Timespan( 30 ) )
            {
                delete sims_.pop( i );
            }
        }
        return false;
    }

    bool hasSims()
    {
        return !sims_.isEmpty();
    }

    void fillCommsStructFromSim( SimCommsStructFromSim& commsOut )
    {
        commsOut.destinationId_ = destinationId_;
        commsOut.sourceId_ = sourceId_;
        commsOut.length_ = length_;
        commsOut.sourceLatitude_ = sourceLatitude_;
        commsOut.sourceLongitude_ = sourceLongitude_;
    }

private:

    struct SimCommsItem
    {
        Timestamp arrivesAt_;
        Simulator* sim_;
    };

    int16_t destinationId_;
    int16_t sourceId_;
    int16_t length_;
    Str message_;
    float sourceLatitude_;  // Incoming message source
    float sourceLongitude_;     // Incoming message source
    FlexArray<SimCommsItem*> sims_;

};

#endif /* SIMCOMMSSTRUCT_H_ */
