/////////////////////////////////////////////////////////////////////////////
//
// Tools_PS2_DMAChainWriter.h
//
// Copyright (c) 2002-2004 Rebellion. All rights reserved.
//
// Description:
//
//     Functionality for writing out PS2 DMA chains, optionally limiting the
//     size of each piece.
//
//////////////////////////////////////////////////////////////////////////////

// B E G I N   F I L E   W R A P P E R ///////////////////////////////////////

#ifdef ASURA_USE_PRAGMA_ONCE
    #pragma once
#endif

#ifndef ___TOOLS_PS2_DMACHAINWRITER_H___
#define ___TOOLS_PS2_DMACHAINWRITER_H___ 1

// I N C L U D E S ///////////////////////////////////////////////////////////

// Stdlib platform-specific.
#include <windows.h>

// C L A S S E S /////////////////////////////////////////////////////////////

class Tools_PS2_DMAChainWriter
{

    public:

        // T Y P E S /////////////////////////////////////////////////////////

        struct EndChainInfo
        {
            u_int uNumPiecesUsed;
            u_int uQWsInFirstPiece;
            u_int uQWsInLastPiece;
            u_int uIdxOfPostSplitTagInFirstPiece;
        };

        typedef bool(*EndChainCallback)( const EndChainInfo&, // xEndChainInfo
                                         void**,              // ppvDataToBeWritten
                                         u_int* );            // puNumBytesToBeWritten

        // C O N S T R U C T O R S   /   D E S T R U C T O R S ///////////////

        Tools_PS2_DMAChainWriter( void );
        ~Tools_PS2_DMAChainWriter( void );

        // M E T H O D S /////////////////////////////////////////////////////

        // Initialisation.
        bool Init( HANDLE hFile );

        // Setup.
        void SetMaxQWCPerTag( u_int uMaxQWC );
        void SetTagTypeForNonFinalPieces( u_int uTagType );
        void SetEndChainCallback( EndChainCallback pfnCallback );
        void EnablePaddingOfLastPiece( bool bPad );
        bool EnsureMinimumCapacity( u_int uMinBytes );

        // Chain construction methods.
        bool BeginChain( void );
        bool AddVifCode( u_int uVifCode );
        bool AddData( const void* pvData, u_int uNumBytesOfData );
        bool AddDataWord( u_int uDataWord );
        bool AddDataWord( float fDataWord ) { return AddDataWord( reinterpret_cast<const u_int&>(fDataWord) ); }
        bool AddDataWord( int   iDataWord ) { return AddDataWord( reinterpret_cast<const u_int&>(iDataWord) ); }
        bool EndChain( void );

        // For adding a gap in the chain, for use at runtime. Basically you
        // end up with two subchains to CALL.
        void MarkPointForChainSplit( void );

        // These methods are only valid between EndChain() and the next
        // BeginChain().
        inline u_int GetNumPiecesForLastChain( void ) const { return m_uNumPiecesUsed; }
        inline u_int GetTotalBytesWrittenForLastChain( void ) const { return m_uTotalBytesWrittenForChain; }

    private:

        // M E T H O D S /////////////////////////////////////////////////////

        bool WriteData( const void* pvData, u_int uNumBytes, bool bUpdateTotalBytesWritten = true );
        bool SkipBytes( u_int uNumBytes );

        bool GrowBuffer( u_int uMinAdditionalWordsReqd );

        // S T A T E /////////////////////////////////////////////////////////

        // Externally specified state.
        HANDLE           m_hFile;
        u_int            m_uMaxQWsPerPiece;       // Including tag.
        u_int            m_uMaxDataWordsPerPiece;
        bool             m_bPadLastPiece;
        u_int            m_uTagTypeExceptFinal;   // Value will be a member of the PS2STRIP_DMA_TAG_TYPE enum.
        EndChainCallback m_pfnEndChainCallback;

        // Internal buffer state.
        u_int* m_puInternalBfr;
        u_int  m_uCapacity;                       // In words.
        u_int  m_uWordsUsed;
        u_int  m_uPointForChainSplit;             // In words.

        // Stats.
        u_int  m_uTotalBytesWrittenForChain;
        u_int  m_uNumPiecesUsed;                  // Only valid between EndChain() and next BeginChain().

};

// E N D   F I L E   W R A P P E R ///////////////////////////////////////////

#endif // #ifndef ___TOOLS_PS2_DMACHAINWRITER_H___
