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

#ifndef DIRECTORYENTRY_H_
#define DIRECTORYENTRY_H_

#include "LogEntry.h"

#include "component/FailureMode.h"
#include "data/DataElement.h"
#include "data/Slate.h"
#include "utils/Mutex.h"

class RingBufferVoid;

/**
 *  Code unit that represents an event to be stored in the log file.
 *  The kinds of events include:
 *  \li Starting a computation cycle
 *  \li Setting the accuracy of a variable
 *  \li Setting the state of a variable
 *  \li Setting the "Best" value of a UniversalDataElement
 *
 * An DirectoryEntry is serialized as:
 * - a 16-bit header (serialized using OutStream::writeUShortCompact) including:
 * 	 \li 8 high bits: character "<"
 *   \li 3 bits: Zero.
 *   \li 3 bits: DirectoryEntry::DirectoryType code, indicating the type of action being
 *       logged; e.g., the start of a cycle, the setting of accuracy, the setting
 *       of the state of a variable, or the setting of a variable to the "best"
 *       for its associated Universal variable
 *   \li 2 bits: the code 01, indicating this is a DirectoryEntry
 * - contents, depending on the type of Directory Entry, ending in a ">"
 *
 *  \ingroup logging
 */
class DirectoryEntry : public LogEntry
{
public:

    /// Type of directory entry
    typedef enum
    {
        ACCESSOR = 'a', /// Defines an Accessor. Appears as "<a"
        ELEMENT =  'e', /// Defines an ElementUri. Appears as "<e"
        NAME =     'n', /// Defines an Name. Appears as "<n"
        VERSION =  'v', /// Indicates the Version. Appears as "<v"

    } DirectoryType;
    static const int DIRECTORY_TYPE_MASK = 7 << 2;

    static unsigned short GetCurrentLogVersion()
    {
        return CurrentLogVersion_;
    }

    static unsigned short GetMinimumLogVersion()
    {
        return MinimumLogVersion_;
    }

    /// Version Construnctor
    DirectoryEntry( const short version = 0 );

    /// Accessor Constructor
    DirectoryEntry( DataAccess* dataAccess );

    /// Name Constructor
    DirectoryEntry( const CodedStr* name );

    /// ElementURI Constructor
    DirectoryEntry( ElementURI* elementURI );

    /// Destructor
    virtual ~DirectoryEntry();

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

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

    /** Read new DirectoryEntry from a stream.
     *
     *  Implements requirement: \ref req_timing_accurateStorage
     *
     */
    static DirectoryEntry* 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;

    /// Convert actions to Strs
    static const char* DirectoryTypeToString( DirectoryType directoryType );

    DirectoryType getDirectoryType( void ) const
    {
        return directoryType_;
    }

protected:

    static unsigned short MinimumLogVersion_;

    static unsigned short CurrentLogVersion_;

    DirectoryType directoryType_;

    union
    {
        unsigned short version_;
        DataAccess* dataAccess_;
        ElementURI* elementURI_;
        const CodedStr* name_;
    };

    /// Indicates whether the value was read in, and therefore can be deleted
    bool wasRead_;

    /// 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 DirectoryEntry::StaticDestructor StaticDestructor_;

    /// Static storage of ElementURIs to delete at cleanup
    static FlexArray<ElementURI*> ElementStore_;

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

#endif /*DIRECTORYENTRY_H_*/
