#if !defined( _IOADEVICE_H )
#define _IOADEVICE_H

#include "SerialInterface.h"

class IoADevice
{
public:
    IoADevice( const char *Name, int Index = 0 ) : m_pName( Name ), m_Index( Index ),
                                                   m_Protocol( eInvalidProtocol ), m_Address( 0x0 ),
                                                   m_pSerialInterface( NULL ), m_bSerialInterface( FALSE ),
                                                   m_bOpen( FALSE ) { }

    // Virtual destructor ensures destructor in derived class is always invoked
    virtual ~IoADevice( ) { Detach( ); }  // terminate any device attachment before object is destroyed

    const char *Name( ) const { return m_pName; }

    int Index( ) const { return m_Index; }

    // Attach + detach
    int Attach( IoASerialInterface& SerialInterface );

    int IsAttached( ) const { return m_pSerialInterface != NULL; }

    IoASerialProtocolEnum Protocol( ) const { return m_Protocol; }

    int IsProtocol( IoASerialProtocolEnum Protocol ) const { return m_Protocol == Protocol; }

    int Address( ) const { return m_Address; }

    virtual void Detach( ) = 0  // pure virtual declaration makes this class abstract
    {
        if ( IsAttached( ) )
        {
            // If Detach( ) function call not made from serial interface, notify serial interface
            if ( ! m_bSerialInterface )
            {
                m_pSerialInterface->Detach( this );
            }

            m_pSerialInterface = NULL;
        }
    }

    // Open + close (base class functions provide notification calls for derived classes)
    virtual int Open( int = 0 ) { m_bOpen = TRUE; return TRUE; }

    int IsOpen( ) const { return m_bOpen; }

    virtual void Close( int = 0 ) { m_bOpen = FALSE; }

protected:
    // Called from derived classes
    const char *ConfigurationString( ) const { return IsAttached( ) ? m_pSerialInterface->ConfigurationString( ) : NULL; }

    int ReadBSP ( int PreSelect, int Bits[ ], int nBits, int PostSelect ) const;
    int WriteBSP( int PreSelect, const int Bits[ ], int nBits, int PostSelect ) const;

    // Later
//    int ReadSPI( ..... );
//    int WriteSPI( ..... );

//    int ReadI2C( ..... );
//    int WriteI2C( ..... );

private:
    // Notification function called only from IoASerialInterface
    friend class IoASerialInterface;

    void Detach( IoASerialInterface *pSerialInterface )
    {
        m_bSerialInterface = TRUE;

        if ( pSerialInterface == m_pSerialInterface ) Detach( );  // virtual function call

        m_bSerialInterface = FALSE;
    }

    const char *m_pName;
    int         m_Index;

    IoASerialInterface *m_pSerialInterface;

    int m_bSerialInterface;

    IoASerialProtocolEnum m_Protocol;
    int                   m_Address;

    int m_bOpen;
};

#endif
