/*******************************************************************************
* 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_BASE__ )
#define __IW_TILING_BASE__

#include "base_proc.h"
#include "base_iw.h"

#include "iw++/iw.hpp"

class TilingBase: public BaseProc
{
public:
    TilingBase()
    {
    }

    static Status InitExternal(Image &src, Image &dst)
    {
        src.ConvertColor(m_srcColor);
        src.ConvertSamples(m_srcType);

        dst.Alloc(src.m_size, m_dstColor, m_dstType);

        return STS_OK;
    }

    // Estimates memory required to process single tile through the pipeline
    // Note: this function is hand-tuned to match the processing pipeline
    static int GetTileFootprint(Size tileSize, Size dstSize)
    {
        int footprint = 0;

        ipp::IwiBorderSize m_swapBorderSize = ipp::iwiSizeToBorderSize(ipp::iwiMaskToSize(m_sobelMask))*2 +
            ipp::iwiSizeToBorderSize(m_gaussMask) +
            ipp::iwiSizeToBorderSize(ipp::iwiMaskToSize(m_sharpMask))*3;
        Size swapSize(tileSize.width + (m_swapBorderSize.left + m_swapBorderSize.right)/3, tileSize.height + (m_swapBorderSize.top + m_swapBorderSize.bottom)/3);
        if(swapSize.width > dstSize.width)
            swapSize.width = dstSize.width;
        if(swapSize.height > dstSize.height)
            swapSize.height = dstSize.height;

        ipp::IwiBorderSize m_srcBorderSize = ipp::iwiSizeToBorderSize(ipp::iwiMaskToSize(m_sobelMask)) +
            ipp::iwiSizeToBorderSize(m_gaussMask) +
            ipp::iwiSizeToBorderSize(ipp::iwiMaskToSize(m_sharpMask));
        Size srcSize(tileSize.width + (m_srcBorderSize.left + m_srcBorderSize.right), tileSize.height + (m_srcBorderSize.top + m_srcBorderSize.bottom));
        if(srcSize.width > dstSize.width)
            srcSize.width = dstSize.width;
        if(srcSize.height > dstSize.height)
            srcSize.height = dstSize.height;

        footprint += (int)(tileSize.width*tileSize.height*GetSampleSize(m_dstType)*GetSamplesNum(m_dstColor));     // dst
        footprint += (int)(swapSize.width*swapSize.height*GetSampleSize(m_interType)*GetSamplesNum(m_dstColor));   // Scale, Gauss, Sobel, Sharp dst
        footprint += (int)(swapSize.width*swapSize.height*GetSampleSize(m_interType)*GetSamplesNum(m_dstColor));   // - swap buffers
        footprint += (int)(srcSize.width*srcSize.height*GetSampleSize(m_srcType)*GetSamplesNum(m_dstColor));       // CC 8u dst
        footprint += (int)(srcSize.width*srcSize.height*GetSampleSize(m_srcType)*GetSamplesNum(m_srcColor));       // Src

        return footprint/1024;
    }

    // Returns ratio of number of border pixels which each tile must process, to size of the image.
    // E.g. if overhead is 1 then function actually process twice the size of the image.
    // Note: this function is hand-tuned to match the processing pipeline
    static double GetTileOverhead(Size tileSize, Size dstSize)
    {
        double tilesX = ((double)dstSize.width/tileSize.width);
        double tilesY = ((double)dstSize.height/tileSize.height);
        ipp::IwiBorderSize m_sobelBorderSize = ipp::iwiSizeToBorderSize(ipp::iwiMaskToSize(m_sobelMask));
        ipp::IwiBorderSize m_gaussBorderSize = ipp::iwiSizeToBorderSize(m_gaussMask);
        ipp::IwiBorderSize m_sharpBorderSize = ipp::iwiSizeToBorderSize(ipp::iwiMaskToSize(m_sharpMask));

        int pixOverLR = (int)((m_sharpBorderSize.left + m_sharpBorderSize.right)*5 + (m_sobelBorderSize.left + m_sobelBorderSize.right)*4
            + (m_gaussBorderSize.left + m_gaussBorderSize.right)*3);
        int pixOverTB = (int)((m_sharpBorderSize.top + m_sharpBorderSize.bottom)*5 + (m_sobelBorderSize.top + m_sobelBorderSize.bottom)*4
            + (m_gaussBorderSize.top + m_gaussBorderSize.bottom)*3);

        return ((pixOverLR*tilesX*tilesY*tileSize.height + pixOverTB*tilesX*tilesY*tileSize.width)/6)/(dstSize.width*dstSize.height);
    }

public:
    static IwiDerivativeType   m_sobelType;
    static IppiMaskSize        m_sobelMask;
    static IppiMaskSize        m_sharpMask;
    static int                 m_gaussMask;
    static ipp::IwiBorderType  m_border;

    static SampleFormat        m_srcType;
    static SampleFormat        m_dstType;
    static SampleFormat        m_interType;
    static ColorFormat         m_srcColor;
    static ColorFormat         m_dstColor;
};

IwiDerivativeType   TilingBase::m_sobelType = iwiDerivHorFirst;
IppiMaskSize        TilingBase::m_sobelMask = ippMskSize5x5;
IppiMaskSize        TilingBase::m_sharpMask = ippMskSize3x3;
int                 TilingBase::m_gaussMask = 3;
ipp::IwiBorderType  TilingBase::m_border    = ippBorderRepl;

SampleFormat        TilingBase::m_srcType   = ST_8U;
SampleFormat        TilingBase::m_dstType   = ST_8U;
SampleFormat        TilingBase::m_interType = ST_32F;
ColorFormat         TilingBase::m_srcColor  = CF_RGB;
ColorFormat         TilingBase::m_dstColor  = CF_GRAY;

#endif
