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

#ifndef JOB_UTIL_IMAGE_PROCESSOR_H
#define JOB_UTIL_IMAGE_PROCESSOR_H

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

#include "job_util/image_desc.h"

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

namespace EA {
    namespace Jobs {

class ImageProcessor
{
public:
    ImageProcessor(ImageDesc * imageDesc, char * buffer, uint32_t bufferSize);
    ImageProcessor(ImageDesc * imageDesc, uint32_t jobIndex, char * buffer, uint32_t bufferSize);
    ImageProcessor(uintptr_t imageDescEa, char * buffer, uint32_t bufferSize);
    ImageProcessor(uintptr_t imageDescEa, uint32_t jobIndex, char * buffer, uint32_t bufferSize);
    ~ImageProcessor();

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

    template <class T> T * GetRegionLine(size_t index, size_t line);

    size_t GetXOffset(size_t index) const;
    size_t GetYOffset(size_t index) const;

    size_t GetWidth() const;
    size_t GetHeight() const;
    size_t GetRegionWidth() const;
    size_t GetRegionHeight() const;

    size_t GetNextXOffset(size_t index) const;
    size_t GetNextYOffset(size_t index) const;

private:
    void Initialize();
    void GetNextReadOffset();
    void NextBuffer(size_t & buffer);
    void Read();
    void Write();
    void Wait(size_t dmaTag);

    ImageProcessor & operator= (ImageProcessor const&);
    ImageProcessor(ImageProcessor const&);

private:

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

private:
    uintptr_t mDescEa;
    int mReadOffset;
    int mCurrentOffset;

    size_t mWriteBufferIndex;
    size_t mReadBufferIndex;
    size_t mCurrentBufferIndex;

    int mLastOffset;

    int mBufferOffset[sBufferingCount];
    int mWritesPending;

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

    static size_t const sImageRegionCount = ImageDesc::sMaxImageRegionDescs * sBufferingCount;
    char * mImageRegionOffsetInBuffer[sImageRegionCount];
    char * mBuffer;
    size_t mBufferSize;

    bool mDone;

    int mJobIndex;

    EA_PREFIX_ALIGN(PLATFORM_PREFERRED_ALIGNMENT) ImageDesc mDesc EA_POSTFIX_ALIGN(PLATFORM_PREFERRED_ALIGNMENT);

};

//----------------------------------------------------------------------
template <class T> T * ImageProcessor::GetRegionLine(size_t index, size_t line)
{
    EA_ASSERT(index < ImageDesc::sMaxImageRegionDescs);
    ImageDesc::ImageRegionDesc const & imageRegionDesc = mDesc.GetImageRegionDesc(index);

    if (mBuffer)
    {
        size_t regionLineSize = imageRegionDesc.mBytesPerPixel * mDesc.GetRegionWidth();
        return reinterpret_cast<T *>(mImageRegionOffsetInBuffer[index * sBufferingCount + mCurrentBufferIndex] + line * regionLineSize);
    }

    return reinterpret_cast<T *>(mImageRegionOffsetInBuffer[index * sBufferingCount + mCurrentBufferIndex] + line * imageRegionDesc.mBytesPerLine);
}

}}

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

#endif
