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

#ifndef DATAENTRY_H_
#define DATAENTRY_H_

#include "data/DataElement.h"

#include "LogEntry.h"
#include "utils/Mutex.h"

class RingBufferVoid;

/**
 *  Code unit that represents an atomic unit of data destined for writing
 *  in the log file.
 *
 * A DataEntry is serialized as:
 * - a 16-bit header (serialized using OutStream::writeUShortCompact) including:
 *   - 13 high bits: DataAccessor code (which can be used to look up
 *     metadata about the entry that follows)
 *   - 1 bit: "Best" flag, set if this is a member of a "Universal" set
 *     of variables, and this one is the "best" one (see UniversalDataElement)
 *   - 2 bits: the code 01, indicating this is a DataEntry
 * - ** if LogEntry::TYPE_MASK <= 0x0003:
 *   64-bit Timespan as integer microseconds since the previous LogEntry,
 *   serialized using OutStream::writeLongLongCompact.
 * - ** if LogEntry::TYPE_MASK > 0x0003:
 *   63-bit Timespan as integer milliseconds*2 since the previous LogEntry
 *   or as integer microseconds*2 since the previous LogEntry( depending on
 *   setting in DataAccess). Lowest bit is set if the value is a repeat of
 *   the previous value. 64 bits serialized using OutStream::writeLongLongCompact.
 * - the data, length determined by the DataAccessor or omitted if a repeat is
 *   encoded in the Timespan.
 *
 *  \ingroup logging
 */
class DataEntry : public LogEntry
{
public:

    /// Type of event
    typedef enum
    {
        NOT_BEST = 0x0000,    // 0 Timestamp -- start of cycle
        IS_BEST = 0x0004      // 1 action(2b)&actor(12b), Timespan, Element, Accuracy
    } Best;

    /// Mask for Best values
    static const int BEST_MASK = 0x0004;

    /// Constructor
    DataEntry( DataAccessor* dataAccessor, const bool best, const bool changed );

    /// Copy Constructor
    DataEntry( const DataEntry* dataEntry );

    /// DataAccess Constructor
    DataEntry( DataAccess* access, DataValue* dataValue, const Timestamp& timestamp, const bool best, const bool changed );

    /// Destructor
    virtual ~DataEntry();

    /// Override new
    void* operator new( size_t size );

    /// Override delete
    void operator delete( void* p );

    DataAccess* getDataAccess( void ) const
    {
        return dataAccess_;
    }

    void setDataAccess( DataAccess* dataAccess )
    {
        dataAccess_ = dataAccess;
    }

    DataValue* getDataValue( void ) const
    {
        return dataValue_;
    }

    bool isBest() const
    {
        return best_;
    }

    bool isDataWrite() const;

    /** Read new DataEntry from a stream.
     *
     *  Implements requirement: \ref req_timing_accurateStorage
     *
     */
    static DataEntry* Read( Timestamp& timeBase, InStream &inStream, unsigned short firstWord, Logger& logger, bool& error );

    /** Send payload to a stream
     *
     *  Implements requirement: \ref req_timing_accurateStorage
     *
     */
    virtual unsigned int write( Timestamp& timeBase, OutStream& logStream ) const;

    virtual Str toString( const Unit* unit = NULL ) const;

    virtual const Str getDataValueString( const Unit* unit = NULL, bool hideUnits = false ) const;

protected:

    DataAccess* dataAccess_;
    DataValue* dataValue_;
    bool best_;
    bool changed_;

    /// Declared as a pointer to avoid including RingBuffer.h header here.
    static RingBufferVoid* MallocRing_;

    /// Makes sure that mallocRing_s is deleted on shutdown
    class StaticDestructor
    {
    public:
        ~StaticDestructor();
    };

    /// Static instance of StaticDestructor
    static DataEntry::StaticDestructor StaticDestructor_;

    /// Used for free/delete operations
    static Mutex Mutex_;

private:
    // Note that the copy constructor below is private and not given a body.
    // Any attempt to call it will return a compiler error.
    DataEntry( const DataEntry& old ); // disallow copy constructor

};

#endif /*DATAENTRY_H_*/
