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

#ifndef LINEARAPPROXLOGWRITER_H_
#define LINEARAPPROXLOGWRITER_H_

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

class DataEntry;
class DataValue;
class ElementURI;
class LogEntry;
class SyslogEntry;

/**
 *  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 LinearApproxLogWriter : public DecimationLogWriter
{
public:

    LinearApproxLogWriter( LogWriter& outputTo, const Str& varName, DataValue* approxErrorValue,
                           bool makeDirEntries, Logger& logger );

    virtual ~LinearApproxLogWriter();

    /// Write an entry to the text log
    virtual unsigned int write( const LogEntry *entry, const Unit* unit = NULL );

    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();

    virtual void setParameter( DataValue* approxError, Logger& logger );

    virtual unsigned int flush();

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

    friend class Supervisor;

    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_;
        }

        float getApproxError()
        {
            return approxError_;
        }

        void setApproxError( float approxError )
        {
            approxError_ = approxError;
        }

        bool flushed()
        {
            return startTime_ == endTime_ && endTime_ == nextTime_;
        }

    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_;
    };

    unsigned int sendOutput( DataEntry* dataEntry );

    const Str varName_;
    DataValue* approxErrorValue_;

    LinearApproxLogWriter::VarData* varData_;

    EventEntry cycleStartEntry_;
    Timestamp lastTime_;

};

#endif /*LINEARAPPROXLOGWRITER_H_*/
