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

#ifndef LINEARAPPROXIMATIONLOGWRITER_H_
#define LINEARAPPROXIMATIONLOGWRITER_H_

#include "logger/TableLogWriter.h"

#include "logger/EventEntry.h"
#include "logger/Logger.h"
#include "utils/FlexArray.h"

class DataAccess;
class DataEntry;
class DataValue;
class ElementURI;
class LogEntry;

/**
 *  Defines a LogWriter that can perform lossy decimation on a stream of
 *  DataEntries, by outputting values that can be reconstructed via linear
 *  interpolation.  The resulting output will have no more error than the
 *  specified error limits (using the DataValue's absDiff() function to
 *  calculate differences -- important in the case of Location values).
 *  See:
 *  \n K. Konstantinides and B. K. Natarajan, “An architecture for lossy
 *  compression of waveforms using piecewise linear approximation,”
 *  <em>IEEE Trans. Signal Processing</em>, vol. 42, no. 9, pp. 2449-2454,
 *  Sept. 1994. (http://ieeexplore.ieee.org/xpls/abs_all.jsp?arnumber=317866)
 *
 *  See TextLogWriter for conversion to text
 *  See FileLogWriter for output to the filesystem.
 *
 *  \ingroup logging
 */
class LinearApproximationLogWriter : public TableLogWriter
{
public:

    LinearApproximationLogWriter( LogWriter* outputTo, int varCount, char** varList, char** unitList, float* approxErrors, bool sendAtStartCycle, bool makeDirEntries = false );

    virtual ~LinearApproximationLogWriter();

    virtual unsigned int writeHeader();

    /// Do what needs to be done at the end of the cycle.
    virtual void endCycle()
    {
        outputTo_->endCycle();
    }

    /// Configure from a config file
    virtual void config( Logger& logger )
    {
        outputTo_->config( logger );
    }

    virtual unsigned int writeFooter();

    void resetDirectoryEntries();

    unsigned int forceWrite( DataEntry* dataEntry );

    unsigned int forceWriteRow();


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

    friend class Supervisor;

    // An instance of VarData is created for each variable being filtered.
    class VarData
    {
    public:
        VarData( const DataEntry* startEntry, float approxError );
        ~VarData();

        DataEntry* getDataEntry()
        {
            return dataEntry_;
        }

        float getDeltaT( const Timestamp timestamp );

        void advance();

        // Returns whether due to deliver next output
        bool checkNextEntry( const DataEntry* nextEntry );

        bool isReady()
        {
            return ready_;
        }

        bool wasNaN()
        {
            return wasNaN_;
        }

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

        DataEntry* dataEntry_;
        DataValue* dataValue_;
        const Unit& unit_;
        float approxError_;
        float minUpperSlope_;
        float maxLowerSlope_;
        double startValue_;
        double endValue_;
        double nextValue_;
        Timestamp startTime_;
        Timestamp endTime_;
        Timestamp nextTime_;
        bool ready_;
        bool wasNaN_;
    };


    void preInitialize();

    virtual unsigned int writeToColumn( const DataEntry *dataEntry, const int column );
    virtual unsigned int writeRow();
    virtual unsigned int writeSyslog( const SyslogEntry* syslogEntry );

    unsigned int sendOutput( DataEntry* dataEntry, int varIndex );

    float* approxErrors_;
    bool sendAtStartCycle_;
    bool makeDirEntries_;

    LinearApproximationLogWriter::VarData** varData_;

    FlexArray< int* > nameWrites_;
    FlexArray< int* > forceWrites_;
    DataAccess** dataAccesses_;
    bool* dataAccessHidden_;
    bool recentOutput_;
    EventEntry cycleStartEntry_;

};

#endif /*LINEARAPPROXIMATIONLOGWRITER_H_*/
