//----------------------------------------------------------------------
// Copyright (C) 2006-2007 Electronic Arts
//----------------------------------------------------------------------

#ifndef JOB_UTIL_BATCH_PROCESSOR_H
#define JOB_UTIL_BATCH_PROCESSOR_H

#include "EAAssert/eaassert.h"
#include "EABase/eabase.h"

#include "job_util/batch_desc.h"
#include "job_manager/config.h"

#if defined EA_PLATFORM_WINDOWS || defined EA_PLATFORM_XENON
#pragma warning (disable: 4347)
#endif

#if defined(EA_PLATFORM_PS3) && defined(EA_COMPILER_SN)
#pragma diag_push
#pragma diag_suppress=1788
#endif

namespace EA {
    namespace Jobs {

//----------------------------------------------------------------------
class BatchProcessor
{
public:
    BatchProcessor(BatchDesc * batchDesc, char * buffer, size_t bufferSize);
    BatchProcessor(BatchDesc * batchDesc, size_t jobIndex, char * buffer, size_t bufferSize);
    BatchProcessor(uintptr_t batchDescEa, char * buffer, size_t bufferSize);
    BatchProcessor(uintptr_t batchDescEa, size_t jobIndex, char * buffer, size_t bufferSize);
    ~BatchProcessor();

    void First();
    void Next();
    bool Done() const;

    template <typename T> inline T * GetArray(int index);
    char * GetArrayTypeless(int index);

    int GetNumElements() const;
    int GetElementOffset() const;

private:
    void Intialize();

    void GetNextReadCount();
    void NextBuffer(int & buffer);
    void Read();
    void Write();
    void Wait(int dmaTag);

    BatchProcessor & operator= (BatchProcessor const&);
    BatchProcessor(BatchProcessor const&);

private:

    static int const sBufferingCount = 2;
    static int const sDmaWaitAllMask = (1<<0) | (1<<1);

private:
    uintptr_t mBatchDescEa;

    int mReadBufferIndex;
    int mWriteBufferIndex;
    int mCurrentBufferIndex;

    int mLastBatchNumber;
    int mCurrentBatchNumber;
    int mReadBatchNumber;

    int mBufferBatchNumber[sBufferingCount];
    int mBufferBatchWritesPending;

    int mElementsPerBatch;
    int mElementsInLastBatch;

    uint32_t * mDynamicCounterEa;   // Pointer to an integer which can participate in atomic operations.
    uint32_t * mRefCounterEa;

    static int const sArrayCount = BatchDesc::sMaxArrays * sBufferingCount;
    char * mArrayOffsetInBuffer[sArrayCount];
    char * mBuffer;
    int mBufferSize;

    bool mDone;

    int mJobIndex;

public:
    EA_PREFIX_ALIGN(PLATFORM_PREFERRED_ALIGNMENT) BatchDesc mBatchDesc EA_POSTFIX_ALIGN(PLATFORM_PREFERRED_ALIGNMENT) ;
};

template <typename T>
inline T * BatchProcessor::GetArray(int index)
{
    EA_ASSERT(index >= 0 && index < BatchDesc::sMaxArrays);
    #ifndef EA_PLATFORM_REVOLUTION
        /* produces a weird compiler error on REV */
        EA_ASSERT(sizeof(T) == mBatchDesc.GetArrayDesc(index).mElementSize);
    #endif
    return static_cast<T*>(static_cast<void*>(mArrayOffsetInBuffer[index * sBufferingCount + mCurrentBufferIndex]));
}

#if defined(EA_PLATFORM_PS3) && defined(EA_COMPILER_SN)
#pragma diag_pop
#endif

}}

#endif
