#if !defined( _IOAIMAGEFILESEQUENCE_H )
#define _IOAIMAGEFILESEQUENCE_H

#include "FrameBuffer.h"
#include "FileBuffer.h"
#include "ImageFileFormat.h"

class IoAImageFileSequence
{
public:
    IoAImageFileSequence( );
    ~IoAImageFileSequence( ) { Free( ); }

    void Free( );
    void Clear( );

    // Parse data files
    int ParseIndexFiles( const char *RootFolder, const char *FileName = NULL );

    int VerifyFolders( )
    {
        for ( int CameraIndex = 0; CameraIndex < CameraCount( ); CameraIndex++ )
        {
            if ( ! VerifyFolders( CameraIndex ) ) return FALSE;
        }

        return TRUE;
    }

    int VerifyFolders( int CameraIndex );

    int VerifyFiles( )
    {
        for ( int CameraIndex = 0; CameraIndex < CameraCount( ); CameraIndex++ )
        {
            if ( ! VerifyFiles( CameraIndex ) ) return FALSE;
        }

        return TRUE;
    }

    int VerifyFiles( int CameraIndex );

    // Counts
    int CameraCount( ) const { return m_CameraCount; }

    int CameraNumber( int CameraIndex ) const
    {
        if ( CameraIndex < 0 || CameraIndex >= CameraCount( ) ) return -1;

        return m_CameraNumber[ CameraIndex ];
    }

    int FolderCount( int CameraIndex ) const
    {
        if ( CameraIndex < 0 || CameraIndex >= CameraCount( ) ) return 0;

        return m_FolderCount[ CameraIndex ];
    }

    int FileCount( int CameraIndex ) const
    {
        if ( CameraIndex < 0 || CameraIndex >= CameraCount( ) ) return 0;

        return m_FileCount[ CameraIndex ];
    }

    int FrameCount( int CameraIndex ) const
    {
        if ( CameraIndex < 0 || CameraIndex >= CameraCount( ) ) return 0;

        return m_FrameCount[ CameraIndex ];
    }

    // Frame access
    int FrameExists( int FrameIndex, int CameraIndex = 0 ) const
    {
        return FrameFileSize( FrameIndex, CameraIndex ) > 0;
    }

    int GetFrame( IoAFrameBuffer& FrameBuffer, int FrameIndex, int CameraIndex = 0 ) const
    {
        char FilePath[ 1000 ];

        if ( ! GetFrameFilePath( FilePath, FrameIndex, CameraIndex ) ) return FALSE;

        int FileOffset = m_Data[ eFileOffset ][ CameraIndex ][ FrameIndex ];
        int FileSize   = m_Data[ eFileSize   ][ CameraIndex ][ FrameIndex ];

        IoAFileBuffer& FileBuffer = ( (IoAImageFileSequence *) this )->m_FileBuffer;  // cast away const

        if ( ! FileBuffer.SynchronousRead( FilePath, FileOffset, FileSize ) ) return FALSE;

        if ( ! IoAImageFileFormat::LuckyFileFormat( FileBuffer, FrameBuffer ) ) return FALSE;

        if ( ! FrameBuffer.SetFrameIndex( FrameIndex ) ) return FALSE;

        return TRUE;
    }

    // Playback
    int SetPlaybackMode( int Mode, int Reverse = FALSE );

    int SetFrameRate( double FramesPerSecond );

    int PlaybackMode( ) const;
    int PlayForward ( ) const;
    int PlayBackward( ) const;

    double FramesPerSecond( ) const;

    int StartPlayback( double FramesPerSecond = 0.0 );

    int GetFrame( IoAFrameBuffer& FrameBuffer, int CameraIndex = 0 ) const
    {
        if ( CameraIndex < 0 || CameraIndex >= CameraCount( ) ) return FALSE;

        return TRUE;
    }

private:
    enum
    {
        eFolderIndex, eFileIndex, eFileOffset, eFileSize, eFrameNumber, eTimeStamp, eFolderFlag, eFileFlag,
        eParameterCount, maxCameras = 16
    };

    const char *RootFolder   ( ) const { return m_RootFolder; }
    const char *CameraName   ( ) const { return "Camera";     }
    const char *FolderName   ( ) const { return "Folder";     }
    const char *FileName     ( ) const { return m_FileName;   }
    const char *FileExtension( ) const { return "lcz";        }

    // Frame location
    int GetFrameFilePath( char *FilePath, int FrameIndex, int CameraIndex = 0 ) const
    {
        if ( FrameIndex < 0 || FrameIndex >= FrameCount( CameraIndex ) ) return FALSE;

        if ( m_Data[ eFileSize ][ CameraIndex ][ FrameIndex ] == 0 ) return FALSE;

        int CameraNumber = m_CameraNumber[ CameraIndex ];

        int FolderIndex = m_Data[ eFolderIndex ][ CameraIndex ][ FrameIndex ];
        int FileIndex   = m_Data[ eFileIndex   ][ CameraIndex ][ FrameIndex ];

        ::sprintf( FilePath, "%s\\%s_%d\\%s_%d\\%s_%d_%d.%s", RootFolder( ), CameraName( ), CameraNumber,
                   FolderName( ), FolderIndex, FileName( ), CameraNumber, FileIndex, FileExtension( ) );

        return TRUE;
    }

    const char *FrameFilePath( int FrameIndex, int CameraIndex = 0 )
    {
        return GetFrameFilePath( m_FilePath, FrameIndex, CameraIndex ) ? m_FilePath : NULL;
    }

    int FrameFileOffset( int FrameIndex, int CameraIndex = 0 ) const
    {
        if ( FrameIndex < 0 || FrameIndex >= FrameCount( CameraIndex ) ) return NULL;

        return m_Data[ eFileOffset ][ CameraIndex ][ FrameIndex ];
    }

    int FrameFileSize( int FrameIndex, int CameraIndex = 0 ) const
    {
        if ( FrameIndex < 0 || FrameIndex >= FrameCount( CameraIndex ) ) return NULL;

        return m_Data[ eFileSize ][ CameraIndex ][ FrameIndex ];
    }

    char *m_RootFolder;
    char *m_FileName;

    int m_CameraCount;

    int m_CameraNumber[ maxCameras ];

    int m_FolderCount[ maxCameras ];
    int m_FileCount  [ maxCameras ];
    int m_FrameCount [ maxCameras ];

    int *m_Data[ eParameterCount ][ maxCameras ];

    char m_FilePath[ 1000 ];  // temporary buffer for returning file path string

    IoAFileBuffer m_FileBuffer;
};

#endif
