/*******************************************************************************
* 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_REF__ )
#define __IW_TILING_REF__

#include "iw++/iw.hpp"
#include "iw_tiling_base.h"

class TilingRef: public TilingBase
{
public:
    TilingRef()
    {
        SetParallelInterface(PARALLEL_NONE);
    }
    virtual ~TilingRef() {}
    virtual void Release()
    {
        m_inter_32f[0].Release();
        m_inter_32f[1].Release();
        m_inter_8u.Release();

        m_sharpBuffer.Release();
    }

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

        InitExternal(src, dst);

        // Allocate intermediate buffers.
        // Use only two swap 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);
        // Dummy 8u buffer, since it will always fit in 32f one.
        m_inter_8u.AttachBuffer(src.m_size, m_dstColor, m_srcType, m_inter_32f[0].ptr(), m_inter_32f[0].m_step);

        return STS_OK;
    }

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

    virtual Status Run(Image &src, Image &dst)
    {
        try
        {
            ipp::IwiColorFmt ippSrcColor  = ImageColorToIpp(m_srcColor);
            ipp::IwiColorFmt ippDstColor  = ImageColorToIpp(m_dstColor);

            ipp::IwiImage iwSrc = ImageToIwImage(src);
            ipp::IwiImage iwDst = ImageToIwImage(dst);
            ipp::IwiImage iwInter_8u = ImageToIwImage(m_inter_8u);
            ipp::IwiImage iwInter[2] = {
                ImageToIwImage(m_inter_32f[0]),
                ImageToIwImage(m_inter_32f[1]),
            };

            ipp::iwiColorConvert(iwSrc, ippSrcColor, iwInter_8u, ippDstColor);

            double mul, add;
            ipp::iwiScale_GetScaleVals(iwInter_8u.m_dataType, iwInter[1].m_dataType, mul, add);
            ipp::iwiScale(iwInter_8u, iwInter[1], mul, add);

            ipp::iwiFilterGaussian(iwInter[1], iwInter[0], m_gaussMask, 1, ipp::IwDefault(), m_border);
            ipp::iwiFilterSobel(iwInter[0], iwInter[1], m_sobelType, m_sobelMask, ipp::IwDefault(), m_border);

            {
                IppStatus   ippStatus;
                IppiSize    sharpSize = {(int)iwInter[0].m_size.width, (int)iwInter[0].m_size.height};

                // Allocate buffer for the function.
                {
                    int bufferSize;

                    ippStatus = ippiFilterSharpenBorderGetBufferSize(sharpSize, m_sharpMask, iwInter[1].m_dataType, iwInter[0].m_dataType, iwInter[1].m_channels, &bufferSize);
                    CHECK_STATUS_PRINT_AC(ippStatus, "ippiFilterSharpenBorderGetBufferSize()", ippGetStatusString(ippStatus), return STS_ERR_FAILED);

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

                ippStatus = ippiFilterSharpenBorder_32f_C1R((Ipp32f*)iwInter[1].ptr(), (int)iwInter[1].m_step, (Ipp32f*)iwInter[0].ptr(), (int)iwInter[0].m_step, sharpSize, m_sharpMask, m_border, 0, m_sharpBuffer);
                CHECK_STATUS_PRINT_AC(ippStatus, "ippiFilterSharpenBorder_32f_C1R()", ippGetStatusString(ippStatus), return STS_ERR_FAILED);
            }

            // Stage 6. Scaling 32f->8u
            ipp::iwiScale_GetScaleVals(iwInter[0].m_dataType, iwDst.m_dataType, mul, add);
            ipp::iwiScale(iwInter[0], iwDst, mul, add);
        }
        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_8u;
    Image               m_inter_32f[2];
    AutoBuffer<Ipp8u>   m_sharpBuffer;
};

#endif
