/*******************************************************************************
* Copyright 2016-2020 Intel Corporation.
*
* This software and the related documents are Intel copyrighted  materials,  and
* your use of  them is  governed by the  express license  under which  they were
* provided to you (License).  Unless the License provides otherwise, you may not
* use, modify, copy, publish, distribute,  disclose or transmit this software or
* the related documents without Intel's prior written permission.
*
* This software and the related documents  are provided as  is,  with no express
* or implied  warranties,  other  than those  that are  expressly stated  in the
* License.
*******************************************************************************/

#if !defined( __IW_TILING_NO_PIPE__ )
#define __IW_TILING_NO_PIPE__

#include "iw_tiling_base.h"


class TilingNoPipeSharpAndScale: public TilingBase
{
public:
    TilingNoPipeSharpAndScale(){}
    virtual ~TilingNoPipeSharpAndScale(){}

    Status Init(Image &inter)
    {
        m_inter = inter;

        return STS_OK;
    }

    virtual Status Run(Image &src, Image &dst, Rect tile)
    {
        ipp::IwiImage iwSrc   = ImageToIwImage(src);
        ipp::IwiImage iwInter = ImageToIwImage(m_inter);
        ipp::IwiImage iwDst   = ImageToIwImage(dst);

        ipp::IwiRoi roi(ImageRectToIpp(tile));
        {
            IppStatus          ippStatus;
            ipp::IwiBorderType sharpBorder;
            IppiSize           sharpSize;
            ipp::IwiBorderSize borderSize = ipp::iwiSizeToBorderSize(ipp::iwiMaskToSize(m_sharpMask));
            AutoBuffer<Ipp8u>  sharpBuffer;

            ipp::IwiImage sharpSrc = iwSrc.GetRoiImage(roi);
            ipp::IwiImage sharpDst = iwInter.GetRoiImage(roi);

            ipp::IwiTile::CorrectBordersOverlap(roi, m_border, borderSize, iwSrc.m_size);
            sharpBorder = ipp::IwiTile::GetTileBorder(roi, m_border, ipp::iwiSizeToBorderSize(ipp::iwiMaskToSize(m_sharpMask)), iwSrc.m_size);

            sharpSize.width  = (int)IPP_MIN(sharpSrc.m_size.width,  sharpDst.m_size.width);
            sharpSize.height = (int)IPP_MIN(sharpSrc.m_size.height, sharpDst.m_size.height);

            {
                int bufferSize;

                ippStatus = ippiFilterSharpenBorderGetBufferSize(sharpSize, m_sharpMask, sharpSrc.m_dataType, sharpDst.m_dataType, sharpSrc.m_channels, &bufferSize);
                CHECK_STATUS_PRINT_AC(ippStatus, "ippiFilterSharpenBorderGetBufferSize()", ippGetStatusString(ippStatus), return STS_ERR_FAILED);

                if(bufferSize && bufferSize > (int)sharpBuffer.GetSize())
                {
                    sharpBuffer.Alloc(bufferSize);
                    if(!sharpBuffer)
                    {
                        PRINT_MESSAGE("Cannot allocate memory for ippiFilterSharpenBorder_32f_C1R");
                        return STS_ERR_ALLOC;
                    }
                }
            }

            ippStatus = ippiFilterSharpenBorder_32f_C1R((Ipp32f*)sharpSrc.ptr(), (int)sharpSrc.m_step, (Ipp32f*)sharpDst.ptr(), (int)sharpDst.m_step, sharpSize, m_sharpMask, sharpBorder, 0, sharpBuffer);
            CHECK_STATUS_PRINT_AC(ippStatus, "ippiFilterSharpenBorder_32f_C1R()", ippGetStatusString(ippStatus), return STS_ERR_FAILED);
        }

        double mul, add;
        ipp::iwiScale_GetScaleVals(iwInter.m_dataType, iwDst.m_dataType, mul, add);
        ipp::iwiScale(iwInter, iwDst, mul, add, ipp::IwDefault(), ipp::IwiRoi(ImageRectToIpp(tile)));

        return STS_OK;
    }

public:
    Image m_inter;
};

class TilingNoPipeGauss: public TilingBase
{
public:
    TilingNoPipeGauss(){}
    virtual ~TilingNoPipeGauss(){}

    virtual Status Run(Image &src, Image &dst, Rect tile)
    {
        try
        {
            ipp::IwiImage iwSrc = ImageToIwImage(src);
            ipp::IwiImage iwDst = ImageToIwImage(dst);

            ipp::iwiFilterGaussian(iwSrc, iwDst, m_gaussMask, 1, ipp::IwDefault(), m_border, ipp::IwiRoi(ImageRectToIpp(tile)));
        }
        catch(ipp::IwException ex)
        {
            CHECK_STATUS_PRINT_AC(ex.m_status, "catch(IwException)", iwGetStatusString(ex), return STS_ERR_FAILED);
        }

        return STS_OK;
    }
};

class TilingNoPipeColorAndScale: public TilingBase
{
public:
    TilingNoPipeColorAndScale(){}
    virtual ~TilingNoPipeColorAndScale(){}

    Status Init(Image &inter)
    {
        m_inter = inter;

        return STS_OK;
    }

    virtual Status Run(Image &src, Image &dst, Rect tile)
    {
        try
        {
            ipp::IwiImage iwSrc   = ImageToIwImage(src);
            ipp::IwiImage iwInter = ImageToIwImage(m_inter);
            ipp::IwiImage iwDst   = ImageToIwImage(dst);

            ipp::iwiColorConvert(iwSrc, ImageColorToIpp(src.m_color), iwInter, ImageColorToIpp(m_inter.m_color), IwValueMax, NULL, ipp::IwiRoi(ImageRectToIpp(tile)));

            double mul, add;
            ipp::iwiScale_GetScaleVals(iwInter.m_dataType, iwDst.m_dataType, mul, add);
            ipp::iwiScale(iwInter, iwDst, mul, add, ipp::IwDefault(), ipp::IwiRoi(ImageRectToIpp(tile)));
        }
        catch(ipp::IwException ex)
        {
            CHECK_STATUS_PRINT_AC(ex.m_status, "catch(IwException)", iwGetStatusString(ex), return STS_ERR_FAILED);
        }

        return STS_OK;
    }

public:
    Image m_inter;
};

class TilingNoPipeSobel: public TilingBase
{
public:
    TilingNoPipeSobel(){}
    virtual ~TilingNoPipeSobel(){}

    virtual Status Run(Image &src, Image &dst, Rect tile)
    {
        try
        {
            ipp::IwiImage iwSrc = ImageToIwImage(src);
            ipp::IwiImage iwDst = ImageToIwImage(dst);

            ipp::iwiFilterSobel(iwSrc, iwDst, m_sobelType, m_sobelMask, NULL, ippBorderRepl, ipp::IwiRoi(ImageRectToIpp(tile)));
        }
        catch(ipp::IwException ex)
        {
            CHECK_STATUS_PRINT_AC(ex.m_status, "catch(IwException)", iwGetStatusString(ex), return STS_ERR_FAILED);
        }

        return STS_OK;
    }
};

class TilingNoPipe: public TilingBase
{
public:
    TilingNoPipe(ParallelInterface parallel = PARALLEL_NONE)
    {
        SetParallelInterface(parallel);
        m_sharpScale.SetParallelInterface(parallel);
        m_colorScale.SetParallelInterface(parallel);
        m_sobel.SetParallelInterface(parallel);
        m_gauss.SetParallelInterface(parallel);
    }
    virtual ~TilingNoPipe(){}
    virtual void Release()
    {
        m_inter_32f[0].Release();
        m_inter_32f[1].Release();
        m_inter_8u.Release();
    }

    virtual Status Init(Image &src, Image &dst)
    {
        Release();

        InitExternal(src, dst);

        // Allocate intermediate buffers
        m_inter_32f[0].Alloc(src.m_size, m_dstColor, m_interType);
        m_inter_32f[1].Alloc(src.m_size, m_dstColor, m_interType);
        m_inter_8u.AttachBuffer(src.m_size, m_dstColor, m_srcType, m_inter_32f[0].ptr(), m_inter_32f[0].m_step);

        m_colorScale.Init(m_inter_8u);
        m_sharpScale.Init(m_inter_32f[0]);

        return STS_OK;
    }

    virtual Status Run(Image &, Image &, Rect)
    {
        return STS_ERR_UNSUPPORTED;
    }

    virtual Status RunParallel(Image &src, Image &dst, Size tile)
    {
        Status status;

        status = m_colorScale.RunParallel(src, m_inter_32f[1], tile);
        CHECK_STATUS_PRINT_AC(status, "TilingNoPipeColorAndScale::Init()", GetBaseStatusString(status), return status);

        status = m_gauss.RunParallel(m_inter_32f[1], m_inter_32f[0], tile);
        CHECK_STATUS_PRINT_AC(status, "TilingNoPipeGauss::Init()", GetBaseStatusString(status), return status);

        status = m_sobel.RunParallel(m_inter_32f[0], m_inter_32f[1], tile);
        CHECK_STATUS_PRINT_AC(status, "TilingNoPipeSobel::Init()", GetBaseStatusString(status), return status);

        status = m_sharpScale.RunParallel(m_inter_32f[1], dst, tile);
        CHECK_STATUS_PRINT_AC(status, "TilingNoPipeSharpAndScale::Init()", GetBaseStatusString(status), return status);

        return STS_OK;
    }

public:
    Image m_inter_8u;
    Image m_inter_32f[2];

    TilingNoPipeSharpAndScale m_sharpScale;
    TilingNoPipeSobel         m_sobel;
    TilingNoPipeGauss         m_gauss;
    TilingNoPipeColorAndScale m_colorScale;
};

#endif
