#if !defined( _IOAAD7940_H )
#define _IOAAD7940_H

#include "Device.h"

class IoAAD7940 : public IoADevice
{
public:
    IoAAD7940( int Index = 0 ) : IoADevice( "AD7940", Index ), m_ReferenceVoltage( 0.0 ) { }
    IoAAD7940( double ReferenceVoltage, int Index = 0 ) : IoADevice( "AD7940", Index ),
                                                          m_ReferenceVoltage( ReferenceVoltage ) { }

    void Detach( ) { Close( ); IoADevice::Detach( ); }  // have to override IoADevice::Detach( )

    // Open + close
    int Open( int = 0 );  // have to override IoADevice::Open( )

//    void Close( int = 0 ) { IoADevice::Close( ) }  // no need to override IoADevice::Close( )

    // Voltage reference
    void SetReferenceVoltage( double ReferenceVoltage )
    {
        if ( ReferenceVoltage > 0.0 ) m_ReferenceVoltage = ReferenceVoltage;
    }

    double ReferenceVoltage( ) const { return m_ReferenceVoltage; }

    int IsReferenceVoltageDefined( ) const { return m_ReferenceVoltage > 0.0; }

    int VoltageLevels( ) const { return 16384; }

    double VoltageIncrement( ) const { return ReferenceVoltage( ) / (double) VoltageLevels( ); }

    static int MinimumVoltageLevel( ) { return     0; }
    static int MaximumVoltageLevel( ) { return 16384; }

    double MinimumVoltage( ) const { return (double) MinimumVoltageLevel( ) * VoltageIncrement( ); }
    double MaximumVoltage( ) const { return (double) MaximumVoltageLevel( ) * VoltageIncrement( ); }

    // Conversion between ADC level and voltage
    double Voltage( int Level ) const
    {
        if ( Level < MinimumVoltageLevel( ) ) Level = MinimumVoltageLevel( );
        if ( Level > MaximumVoltageLevel( ) ) Level = MaximumVoltageLevel( );

        return (double) Level * VoltageIncrement( );
    }

    int Level( double Voltage ) const
    {
        if ( Voltage < MinimumVoltage( ) ) Voltage = MinimumVoltage( );
        if ( Voltage > MaximumVoltage( ) ) Voltage = MaximumVoltage( );

        return (int) ( Voltage / VoltageIncrement( ) + 0.5 );
    }

    int Sample( int& Level ) const { return IsOpen( ) && Read( Level ); }  // raw ADC output

    int Sample( double& V ) const
    {
        int Level;

        if ( ! Sample( Level ) ) return FALSE;

        V = Voltage( Level );

        return TRUE;
    }

    int SampleRange( double& VoltsMinimum, double& VoltsMaximum, int NumberOfSamples ) const;

    int SampleMedian( double& VoltsMinimum, double& VoltsMedian, double& VoltsMaximum, int NumberOfSamples ) const;

    int SampleMedian( double& VoltsMedian, int NumberOfSamples ) const
    {
        double VoltsMinimum, VoltsMaximum;  // discard min + max

        return SampleMedian( VoltsMinimum, VoltsMedian, VoltsMaximum, NumberOfSamples );
    }

    int SampleStatistics( double& VoltsMean, double& VoltsVariance, int NumberOfSamples ) const;

    int SampleStatistics( double& VoltsMean, double& VoltsVariance, double& VoltsPerSecond, int NumberOfSamples ) const;

    int SampleRateOfChange( double& VoltsPerSecond, int NumberOfSamples ) const;

    int WaitUntilSettled( double VoltsPerSecondThreshold, int NumberOfSamples, double TimeLimit ) const;

    int SampleMedianWhenSettled( double& VoltsMinimum, double& VoltsMedian, double& VoltsMaximum, int NumberOfSamples,
                                 double VoltsPerSecondThreshold, double TimeLimit ) const;

    int SampleMedianWhenSettled( double& VoltsMedian, int NumberOfSamples, double VoltsPerSecondThreshold, double TimeLimit ) const
    {
        double VoltsMinimum, VoltsMaximum;  // discard min + max

        return SampleMedianWhenSettled( VoltsMinimum, VoltsMedian, VoltsMaximum, NumberOfSamples,
                                        VoltsPerSecondThreshold, TimeLimit );
    }

private:
    int Read( int& DataBits ) const;  // device is read-only

    double m_ReferenceVoltage;
};

#endif
