/*******************************************************************************
* Copyright 2011-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.
*******************************************************************************/

#ifndef __BASE_IPP_H__
#define __BASE_IPP_H__

#include "base_image.h"

#if defined(__MIC__)
    #pragma offload_attribute(push, target(mic))
    #include "ippcore.h"
    #include "ippi.h"
    #pragma offload_attribute(pop)
#else
    #include "ippcore.h"
    #include "ippi.h"
#endif
#include "ippversion.h"

#ifndef IPP_VERSION_COMPLEX
#define IPP_VERSION_COMPLEX           (IPP_VERSION_MAJOR*10000 + IPP_VERSION_MINOR*100 + IPP_VERSION_UPDATE)
#endif

#define PRINT_LIB_VERSION(LIB, VER) \
    VER = ipp##LIB##GetLibVersion(); \
    printf("  %s %s %s \n", VER->Name, VER->Version, VER->BuildDate);

static IppStatus InitPreferredCpu(const char *sCpu)
{
    if(sCpu && vm_string_strlen(sCpu, 0xFFFF))
    {
        if (!vm_string_stricmp(sCpu, "SSE3"))
            return ippSetCpuFeatures(ippCPUID_SSE3);
        else if(!vm_string_stricmp(sCpu, "SSSE3"))
            return ippSetCpuFeatures(ippCPUID_SSSE3);
        else if(!vm_string_stricmp(sCpu, "SSE41"))
            return ippSetCpuFeatures(ippCPUID_SSE41);
        else if(!vm_string_stricmp(sCpu, "SSE42"))
            return ippSetCpuFeatures(ippCPUID_SSE42);
        else if(!vm_string_stricmp(sCpu, "AVX"))
            return ippSetCpuFeatures(ippCPUID_AVX);
        else if(!vm_string_stricmp(sCpu, "AVX2"))
            return ippSetCpuFeatures(ippCPUID_AVX2);
        else if(!vm_string_stricmp(sCpu, "AVX512"))
            return ippSetCpuFeatures(ippCPUID_AVX512F);
    }
    return ippInit();
}
#define IPP_OPT_LIST "SSE3, SSSE3, SSE41, SSE42, AVX, AVX2, AVX512"

static const char* InterToString(IppiInterpolationType inter)
{
    if(inter == ippNearest)
        return "ippNearest";
    else if(inter == ippLinear)
        return "ippLinear";
    else if(inter == ippCubic)
        return "ippCubic";
    else if(inter == ippLanczos)
        return "ippLanczos";
    else if(inter == ippHahn)
        return "ippHahn";
    else if(inter == ippSuper)
        return "ippSuper";
    else
        return NULL;
}

static const char* AxisToString(IppiAxis inter)
{
    if(inter == ippAxsHorizontal)
        return "ippAxsHorizontal";
    else if(inter == ippAxsVertical)
        return "ippAxsVertical";
    else if(inter == ippAxsBoth)
        return "ippAxsBoth";
    else if(inter == ippAxs45)
        return "ippAxs45";
    else if(inter == ippAxs135)
        return "ippAxs135";
    else
        return NULL;
}

static const char* BorderToString(IppiBorderType border)
{
    IppiBorderType pureBorder = (IppiBorderType)(border&0xF);

    if((border&ippBorderInMem) == ippBorderInMem)
        return "ippBorderInMem";
    else
    {
#if IPP_VERSION_COMPLEX >= 20170002
        if((border&ippBorderFirstStageInMem) == ippBorderFirstStageInMem)
        {
            if(pureBorder == ippBorderConst)
                return "FSIM-ippBorderConst";
            else if(pureBorder == ippBorderRepl)
                return "FSIM-ippBorderRepl";
            else if(pureBorder == ippBorderWrap)
                return "FSIM-ippBorderWrap";
            else if(pureBorder == ippBorderMirror)
                return "FSIM-ippBorderMirror";
            else if(pureBorder == ippBorderMirrorR)
                return "FSIM-ippBorderMirrorR";
            else if(pureBorder == ippBorderTransp)
                return "FSIM-ippBorderTransp";
            else
                return "FSIM-ippBorderDefault";
        }
        else
#endif
        {
            if(pureBorder == ippBorderConst)
                return "ippBorderConst";
            else if(pureBorder == ippBorderRepl)
                return "ippBorderRepl";
            else if(pureBorder == ippBorderWrap)
                return "ippBorderWrap";
            else if(pureBorder == ippBorderMirror)
                return "ippBorderMirror";
            else if(pureBorder == ippBorderMirrorR)
                return "ippBorderMirrorR";
            else if(pureBorder == ippBorderDefault)
                return "ippBorderDefault";
            else if(pureBorder == ippBorderTransp)
                return "ippBorderTransp";
            else
                return NULL;
        }
    }
}

static IppDataType ImageFormatToIpp(SampleFormat format)
{
    if(format == ST_8U)
        return ipp8u;
    else if(format == ST_8S)
        return ipp8s;
    else if(format == ST_16U)
        return ipp16u;
    else if(format == ST_16S)
        return ipp16s;
    else if(format == ST_32U)
        return ipp32u;
    else if(format == ST_32S)
        return ipp32s;
    else if(format == ST_32F)
        return ipp32f;
    else if(format == ST_64F)
        return ipp64f;
    else
        return ippUndef;
}

static SampleFormat IppFormatToImage(IppDataType format)
{
    if(format == ipp8u)
        return ST_8U;
    else if(format == ipp8s)
        return ST_8S;
    else if(format == ipp16u)
        return ST_16U;
    else if(format == ipp16s)
        return ST_16S;
    else if(format == ipp32u)
        return ST_32U;
    else if(format == ipp32s)
        return ST_32S;
    else if(format == ipp32f)
        return ST_32F;
    else if(format == ipp64f)
        return ST_64F;
    else
        return ST_UNKNOWN;
}

static IppiSize ImageSizeToIppOld(Size size)
{
    IppiSize ippSize = {(int)size.width, (int)size.height};
    return ippSize;
}

static IppiSizeL ImageSizeToIpp(Size size)
{
    IppiSizeL ippSize = {(IppSizeL)size.width, (IppSizeL)size.height};
    return ippSize;
}

static IppSizeL ImageSizeToLen(Size size)
{
    return (IppSizeL)(size.width);
}

static Size IppSizeToImage(IppiSizeL size)
{
    return Size(size.width, size.height);
}

static IppiRectL ImageRectToIpp(Rect rect)
{
    IppiRectL ippRect = {(IppSizeL)rect.x, (IppSizeL)rect.y, (IppSizeL)rect.width, (IppSizeL)rect.height};
    return ippRect;
}

static Rect IppRectToImage(IppiRectL rect)
{
    return Rect(rect.x, rect.y, rect.width, rect.height);
}

static IppiBorderSize ImageBorderSizeToIpp(BorderSize borderSize)
{
    IppiBorderSize ippBorder = {(Ipp32u)borderSize.left, (Ipp32u)borderSize.top, (Ipp32u)borderSize.right, (Ipp32u)borderSize.bottom};
    return ippBorder;
}

static BorderSize IppBorderSizeToImage(IppiBorderSize borderSize)
{
    return BorderSize(borderSize.borderLeft, borderSize.borderTop, borderSize.borderRight, borderSize.borderBottom);
}


#endif
