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

#ifndef SIMSLATE_H_
#define SIMSLATE_H_

#include "units/Unit.h"
#include "utils/FastMap.h"
#include "utils/Mutex.h"
#include "utils/Str.h"
#include "utils/Timestamp.h"
#include "simulatorModule/SimAhrsStruct.h"
#include "simulatorModule/SimBatteryStruct.h"
#include "simulatorModule/SimDvlStruct.h"

/**
 *  SimSlate is a simple, non-logging slate for
 *  transferring data between the external simulator
 *  and other modules, without worrying about module
 *  dependencies.
 *
 *  This was created to make interactions with the
 *  simulator as transparent as possible.
 *
 *  \ingroup data
 */
class SimSlate
{
public:

    typedef enum
    {
        ALTITUDE_METER,  // Written by Bathymetry & read by DVL
        BUOYANCY_POSITION_CUBIC_METER,  // Used in BuoyancyServo
        DENSITY_KILOGRAM_PER_CUBIC_METER, // Used in CTDs
        DEPTH_METER,  // Used in Depth_MSI_US4300
        EASTWARD_WATER_VELOCITY_METER_PER_SECOND, // Used in DVL
        ELEVATOR_ANGLE_RADIAN, // Used in MotorServo
        LATITUDE_DEGREE, // Used in NAL_9602
        LONGITUDE_DEGREE, // Used in NAL_9602
        MAGNETIC_VARIATION_DEGREE, // Used in MagneticVariation
        MASS_CONCENTRATION_OF_CHLOROPHYLL_UG_PER_L,
        MASS_CONCENTRATION_OF_OXYGEN_UG_PER_L,
        MASS_CONCENTRATION_OF_PETROLEUM_HYDROCARBON_KG_PER_CUBIC_METER,
        MASS_POSITION_METER, // Used in MotorServo
        MOLE_CONCENTRATION_OF_NITRATE_UMOLE_PER_L,
        NORTHWARD_WATER_VELOCITY_METER_PER_SECOND, // Used in DVL
        PROPELLER_OMEGA_RADIAN_PER_SECOND, // Used in MotorServo
        RUDDER_ANGLE_RADIAN, // Used in MotorServo
        SALINITY_PART_PER_THOUSAND, // Used in CTDs
        SOUND_SPEED_METER_PER_SECOND, // Used in CTDs
        TEMPERATURE_DEGREE_CELSIUS, // Used in CTDs
        VELOCITY_X_WRT_GROUND_METER_PER_SECOND, // Used in DVL
        VELOCITY_Y_WRT_GROUND_METER_PER_SECOND, // Used in DVL
        VELOCITY_Z_WRT_GROUND_METER_PER_SECOND, // Used in DVL
        WATER_VELOCITY_X_METER_PER_SECOND, // Used in DVL
        WATER_VELOCITY_Y_METER_PER_SECOND, // Used in DVL
        WATER_VELOCITY_Z_METER_PER_SECOND, // Used in DVL
        HOMING_SENSOR_RANGE_M, // Used in DAT
        HOMING_SENSOR_AZIM_RAD, // Used in DAT
        HOMING_SENSOR_ELEV_RAD, // Used in DAT
        LBL_TRANSPONDER_1_RANGE_M, // Used in LBL
        LBL_TRANSPONDER_2_RANGE_M, // Used in LBL
        LBL_TRANSPONDER_3_RANGE_M, // Used in LBL
        NUM_ENTRIES
    } SimEntryType;

    static bool Clear( SimEntryType simEntryType );

    template<typename T>
    static bool Read( SimEntryType simEntryType, T& value );

    static bool ReadScience( const Str& name, const Unit& unit, float& value );

    static void Read( SimAhrsStruct& ahrs );

    static void Read( SimBatteryStruct& battery );

    static void Read( SimDvlStruct& dvl );

    template<typename T>
    static bool Write( SimEntryType simEntryType, const T& value );

    static bool WriteScience( const Str& name, const Unit& unit, const float value );

    static void Write( const SimAhrsStruct& ahrs );

    static void Write( const SimBatteryStruct& battery );

    static void Write( const SimDvlStruct& dvl );

    static void SendMessage( int destination, int source, const Str& message, float maxDistance = 5000.0f, float delay = 13.0f, float mediumSpeed = 1500.0f );

    static bool ReceiveMessage( int& destination, int& source, Str& message );

    static bool SendRangeRequst( const int destination, const int source, const int numPings = 1 );

    static bool ReceiveRange( int& destination, float& range, float& azimuth, float& elevation, Timestamp& rxTime );

    static void SetAcousticResponseTimeout( const Timespan& acousticResponseTimeout );

    static void SetLocalAddress( const Str& vehicleName, int modemAddress );

    static const char* ToString( SimEntryType simEntryType );

    class ScienceEntry
    {
    private:
        const Unit& unit_;
        float value_;
    public:
        ScienceEntry( const Unit& unit, float value );
        void set( float value );
        void get( const Unit&, float& value );
    };

    /// Holds simulated AHRS data
    class AhrsEntry
    {
    private:
        SimAhrsStruct ahrs_;
        Mutex ahrsMutex_;
    public:
        /// Constructor
        AhrsEntry()
            : ahrs_()
        {}
        void set( const SimAhrsStruct& ahrsStruct );
        void get( SimAhrsStruct& ahrsStruct );
    };

    // Holds simulated battery data
    class BatteryEntry
    {
    private:
        SimBatteryStruct battery_;
        Mutex batteryMutex_;
    public:
        void set( const SimBatteryStruct& batteryStruct );
        void get( SimBatteryStruct& batteryStruct );
    };

    /// Holds simulated DVL data
    class DvlEntry
    {
    private:
        SimDvlStruct dvl_;
        Mutex dvlMutex_;
    public:
        /// Constructor
        DvlEntry()
            : dvl_()
        {}
        void set( const SimDvlStruct& dvlStruct );
        void get( SimDvlStruct& dvlStruct );
    };

    static void Uninitialize();

private:
    SimSlate()
    {}

    static AhrsEntry ahrsEntry_;

    static BatteryEntry batteryEntry_;

    static DvlEntry dvlEntry_;

    static FastMap<const Str, ScienceEntry*> ScienceEntries_;

    static double Entries_[];

    /// Makes sure that static _entries are initialized
    class StaticInitializer
    {
    public:
        StaticInitializer();
    };

    /// Static instance of StaticDestructor
    static SimSlate::StaticInitializer StaticInitializer_;
};

#endif /* SIMSLATE_H_ */
