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

#ifndef LCMPOLICY_H_
#define LCMPOLICY_H_

#include "stdint.h"
#include "utils/Str.h"
#include "utils/FastMap.h"
#include "utils/FlexArray.h"
#include "logger/Logger.h"

/// @struct LcmAccessS
/// @brief LCM access policy flag container
struct LcmAccessS
{
    /// @var LcmAccessS::oflags_
    /// @brief policy output flags
    uint64_t oflags_;
    /// @var LcmAccessS::iflags_
    /// @brief policy input flags
    uint64_t iflags_;
};

/// @typedef struct LcmAccessS LcmAccess
/// @brief LCM access policy container type
typedef struct LcmAccessS LcmAccess;

/// @typedef FastMap<const Str, LcmAccess*> AccessMap
/// @brief LCM channel to access policy map
typedef FastMap<const Str, LcmAccess*> AccessMap;

/**
 *  Implements Slate access policy for LCM writers
 *
 *  \ingroup data
 */
class LcmPolicy
{
public:
    /// @enum OFLAGS { ONONE = 0x0, SLATE = 0x1, UNIVERSAL = 0x2, LCM = 0x4, OALL = 0x10}
    /// @brief Policy output flags
    enum  OFLAGS { ONONE = 0x0, SLATE = 0x1, UNIVERSAL = 0x2, LCM = 0x4, OALL = 0x10};
    /// @enum IFLAGS { INONE = 0x0, ONLY_VALID = 0x1, ONLY_SOURCES = 0x2, IALL = 0x4}
    /// @brief Policy output flags
    enum  IFLAGS { INONE = 0x0, ONLY_VALID = 0x1, ONLY_SOURCES = 0x2, IALL = 0x4};

    /// @fn LcmPolicy( Str source )
    /// @brief Constructor
    /// @param[in] source data source (one policy per source)
    /// @return new LcmPolicy instance
    LcmPolicy( Str source );
    /// @fn virtual ~LcmPolicy()
    /// @brief Destructor
    /// @return none
    virtual ~LcmPolicy();


    /// @fn int addChannel( Str channel, LcmPolicy::OFLAGS oflags = LcmPolicy::ONONE, LcmPolicy::IFLAGS iflags = LcmPolicy::INONE )
    /// @brief Add channel to policy.
    /// @param[in] channel Channel name
    /// @param[in] oflags Channel output policy flags
    /// @param[in] iflags Channel input policy flags
    /// @return 0 on success, -1 otherwise.
    int addChannel( Str channel, LcmPolicy::OFLAGS oflags = LcmPolicy::ONONE, LcmPolicy::IFLAGS iflags = LcmPolicy::INONE );
    /// @fn int removeChannel( Str channel )
    /// @brief Remove channel from policy.
    /// @param[in] channel Channel name
    /// @return 0 on success, -1 otherwise.
    int removeChannel( Str channel );

    /// @fn int addOut( Str channel, LcmPolicy::OFLAGS flags )
    /// @brief Add output policy for channel.
    /// @param[in] channel Channel name
    /// @param[in] flags Output policy flags
    /// @return 0 on success, -1 otherwise.
    int addOut( Str channel, LcmPolicy::OFLAGS flags );
    /// @fn int removeOut( Str channel, LcmPolicy::OFLAGS flags )
    /// @brief Remove (clear) output policy flags.
    /// @param[in] channel Channel name
    /// @param[in] flags policy flags to remove
    /// @return 0 on success, -1 otherwise.
    int removeOut( Str channel, LcmPolicy::OFLAGS flags );
    /// @fn int setOut( Str channel, LcmPolicy::OFLAGS flags )
    /// @brief Set output policy flags.
    /// @param[in] channel Channel name
    /// @param[in] flags policy flags to set
    /// @return 0 on success, -1 otherwise.
    int setOut( Str channel, LcmPolicy::OFLAGS flags );

    /// @fn int addIn( Str channel, LcmPolicy::IFLAGS flags )
    /// @brief Add input policy for channel.
    /// @param[in] channel Channel name
    /// @param[in] flags Input policy flags
    /// @return 0 on success, -1 otherwise.
    int addIn( Str channel, LcmPolicy::IFLAGS flags );
    /// @fn int removeIn( Str channel, LcmPolicy::IFLAGS flags )
    /// @brief Remove (clear) input policy flags.
    /// @param[in] channel Channel name
    /// @param[in] flags policy flags to remove
    /// @return 0 on success, -1 otherwise.
    int removeIn( Str channel, LcmPolicy::IFLAGS flags );
    /// @fn int setIn( Str channel, LcmPolicy::IFLAGS flags )
    /// @brief Set input policy flags.
    /// @param[in] channel Channel name
    /// @param[in] flags policy flags to set
    /// @return 0 on success, -1 otherwise.
    int setIn( Str channel, LcmPolicy::IFLAGS flags );

    /// @fn const Str& getSource()
    /// @brief Get source name string
    /// @return Source name string on success, NULL otherwise.
    const Str& getSource();
    /// @fn LcmAccess* access( Str channel )
    /// @brief Get LcmAccess structure for a channel
    /// @param[in] channel Channel name
    /// @return LcmAccess struct pointer on success, NULL otherwise.
    LcmAccess* access( Str channel );
    /// @fn int channelCount()
    /// @brief Get number of channels
    /// @return number of channels in policy.
    int channelCount();

    /// @fn bool subAllowed( const Str channel, LcmPolicy::IFLAGS flags )
    /// @brief Return subscription (input) policy for a channel
    /// @param[in] channel Channel name
    /// @param[in] flags input flags to check
    /// @return true if input from sources indicated by flags matches policy, false otherwise.
    bool subAllowed( const Str channel, LcmPolicy::IFLAGS flags );
    /// @fn bool pubAllowed( const Str channel, LcmPolicy::OFLAGS flags )
    /// @brief Return publication (output) policy for a channel
    /// @param[in] channel Channel name
    /// @param[in] flags output flags to check
    /// @return true if output to destinations indicated by flags matches policy, false otherwise.
    bool pubAllowed( const Str channel, LcmPolicy::OFLAGS flags );

protected:

    ///@var Str source_
    ///@brief Data source name string
    Str source_;
    ///@var AccessMap access_map_
    ///@brief FastMap instance maps channel names to policy values (LcmAccess)
    AccessMap access_map_;
    ///@var Logger logger_
    ///@brief Log instance
    Logger logger_;

};

#endif /*LCMPOLICY_H_*/
