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

#include "ippi.h"
#include "ippcore_tl.h"
#include "ippi_tl.h"
#include "ipps.h"
#include "owndefs_tl.h"

#ifdef _OPENMP
#include <omp.h>
#endif

#if ( _IPP >= _IPP_A6 )||( _IPP32E >= _IPP32E_M7 )
#define _CORRFULL_BLOCK_ALG      12
#define _CORRFULL_N_BLOCK_ALG     2
#define _CORRSAME_BLOCK_ALG       1
#define _CORRVALID_BLOCK_ALG      8
#define _CORRVALID_N_BLOCK_ALG    8
#else
#define _CORRFULL_BLOCK_ALG      12
#define _CORRFULL_N_BLOCK_ALG     2
#define _CORRSAME_BLOCK_ALG       1
#define _CORRVALID_BLOCK_ALG      4
#define _CORRVALID_N_BLOCK_ALG   12
#endif

/* below this order the double FFT size is more effective */
#if ( _IPP >= _IPP_H9 )||( _IPP32E >= _IPP32E_L9 )
#define _DOUBLE_SIZE 10 // this size was chosen base on perf measurements
#else
#define _DOUBLE_SIZE 7
#endif

/* predefined precision for all correlation functions - if the
   autocorrelation function of the image part under template
   is less then ( eps = THRESH_32F * L2norm from template ), it's
   assumes to be zero and is substituted by eps */
#define THRESH_32F (IPP_EPS23)

#define MAX_DIRECT_DIMENSION_SIZE 64
#define CROSSCORRVALID_FFT_CRITERION_OUTSIZE 27
#define CROSSCORRVALID_FFT_CRITERION_TPLSIZE 10
#define CROSSCORRVALID_FFT_CRITERION_SRCSIZE 44
#define CROSSCORRVALID_MAX_DIRECT_TPL_SIZE 256 * 127


   /* ////// One usefull inline function to get mpy from scale factor ////// */
__INLINE Ipp32f get_mpy(int scaleFactor)
{
    union { Ipp32s i; Ipp32f f; } tmp;

    tmp.f = 1.0;
    if (scaleFactor < 0) tmp.i = tmp.i + (((-scaleFactor) & 0x7f) << 23);
    else tmp.i = tmp.i - ((scaleFactor & 0x7f) << 23);
    return tmp.f;
}


//   Purpose: IPPi Fast Fourier Transform with 2D buffer of float data

typedef enum {
    idCtxFFT2D_R_32f
} IppCtxId;

typedef struct FFTContext_32f IppsFFTContext_32f;

typedef struct FFT2DContext_32f {
    IppCtxId            idCtx;
    int                 orderX;
    int                 orderY;
    IppHintAlgorithm    hint;
    int                 bufSize;
    int                 nThreads;
    IppsFFTContext_32f *ctxFFT_C_X;
    IppsFFTContext_32f *ctxFFT_C_Y;
    IppsFFTContext_32f *ctxFFT_R_X;
    IppsFFTContext_32f *ctxFFT_R_Y;
    Ipp8u              *ctxMemFFT_C_X;
    Ipp8u              *ctxMemFFT_C_Y;
    Ipp8u              *ctxMemFFT_R_X;
    Ipp8u              *ctxMemFFT_R_Y;
} IppiFFTContext_32f;

typedef struct {
    IppEnum algType;//in
    IppDataType srcDataType, dstDataType;
    IppiSize srcRoiSize, tplRoiSize;//in
    IppiSize fftRoiSize, dstRoiSize, frameRoiSize;//out
    int orderX, orderY;//out
    int sizeFftSpec, sizeFftSpecBuf, sizeFftBuf, sizeA, sizeWrkBuf;//out: buf sizes
} OwniCrossCorrConfig;

typedef struct {
    IppStatus *stsBuf;
    int nThreads, nFrames, w, onceW, onceH, shftW, shftH;
    Ipp32f *pMemBuf, *tplFft;
    int sizeWrkBuf, sizeA, stsBufSize, thrMemSize;
    IppDataType srcDataType, dstDataType;
    IppiSize dstSize, srcRoiSize, tplRoiSize, fftS;
    int srcDataSize, dstDataSize;
    void* pSrc, *pDst;
    Ipp32f tplNorm, sqrNorm, thresh;
    int srcStep, aStep, fStep, dstStep, scaleFactor;
    IppiFFTSpec_R_32f *ctxFft;
    void(*pAuto)(const Ipp32f*, int, IppiSize, Ipp32f*, int, IppiSize, Ipp64f*, Ipp32f*, Ipp32f*);
    void(*pDeno)(const Ipp32f*, int, IppiSize, Ipp32f*, int, IppiSize, Ipp64f*, int, Ipp32f*, Ipp32f*);
    IppiNormOp normOp;
} ippiCrossCorrNorm_T_Str;