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

/*
//   Purpose: Functions of Addition operation
//   Contents:
//       ippiAdd_16s_C1IRSfs_T
//       ippiAdd_16s_C3IRSfs_T
//       ippiAdd_16s_C4IRSfs_T
*/

#include "pisimplearithm_t.h"

static IppStatus ippiAdd_16s_C1IRSfs_T_Fun(int i, void *arg)
{
    ippiSimpleArithmetics_16s_T_Str *ts = (ippiSimpleArithmetics_16s_T_Str *)arg;

    const Ipp16s* pSrc    = (const Ipp16s*)ts->pSrc1;
    int srcStep           = ts->src1Step;
    Ipp16s* pSrcDst       = ts->pDst;
    int srcDstStep        = ts->dstStep;

    IppiSize roiSize;
    roiSize.width         = ts->roiSize.width;
    roiSize.height        = ts->roiSize.height;
    int scaleFactor       = ts->scaleFactor;
    IppiPoint  splitImage = ts->splitImage;
    IppiSize tileSize     = ts->tileSize;
    IppiSize tailSize     = ts->tailSize;

    const Ipp16s *pSrcRoi;
    Ipp16s       *pSrcDstRoi;
    IppiPoint     roiOffset;

    owniGetTileParamsByIndex_T(i, splitImage, tileSize, tailSize, &roiOffset, &roiSize);

    /* compute pointers to ROIs */
    pSrcRoi    = owniGetImagePointer_16s_C1 (pSrc, srcStep, roiOffset.x, roiOffset.y);
    pSrcDstRoi = owniGetImagePointer_16s_C1 (pSrcDst, srcDstStep, roiOffset.x, roiOffset.y);

    return ippiAdd_16s_C1IRSfs(pSrcRoi, srcStep, pSrcDstRoi, srcDstStep, roiSize, scaleFactor);
}

IPPFUN (IppStatus, ippiAdd_16s_C1IRSfs_T, (const Ipp16s* pSrc, int srcStep, Ipp16s* pSrcDst, int srcDstStep, IppiSize roiSize, int scaleFactor))
{
    IppStatus status = ippStsNoErr;

    if (pSrc == 0 || pSrcDst == 0)              return ippStsNullPtrErr;
    if (roiSize.width <= 0 || roiSize.height <= 0) return ippStsSizeErr;

    int numTiles = 0;
    int pixelSize = sizeof (Ipp16s);

    IppiPoint splitImage;
    IppiSize  tileSize, tailSize;
    int   minTileSize = IPP_MIN (IPP64_MIN_ADD_2D / pixelSize, IPP_MAX_32S / pixelSize);

    /* split the image to tiles */
    owniSplitUniform2D_T (roiSize, minTileSize, &splitImage, &tileSize, &tailSize);

    if (splitImage.x == 1 && splitImage.y == 1)
    {
        status = ippiAdd_16s_C1IRSfs(pSrc, srcStep, pSrcDst, srcDstStep, roiSize, scaleFactor);
    }
    else
    {
        numTiles = splitImage.x * splitImage.y;
        ippiSimpleArithmetics_16s_T_Str ts;
        simpleArithmeticsThreadingStructureEncode_16s ((Ipp16s*)pSrc, srcStep, (Ipp16s*)0, (int)0, pSrcDst, srcDstStep, roiSize, scaleFactor,
                                                       splitImage, tileSize, tailSize, &ts);
        status = ippParallelFor_T(numTiles, (void*)&ts, ippiAdd_16s_C1IRSfs_T_Fun);
    }

    return status;
}

IPPFUN (IppStatus, ippiAdd_16s_C3IRSfs_T, (const Ipp16s* pSrc, int srcStep, Ipp16s* pSrcDst, int srcDstStep, IppiSize roiSize, int scaleFactor))
{
    roiSize.width *= 3;
    return ippiAdd_16s_C1IRSfs_T(pSrc, srcStep, pSrcDst, srcDstStep, roiSize, scaleFactor);
}

IPPFUN (IppStatus, ippiAdd_16s_C4IRSfs_T, (const Ipp16s* pSrc, int srcStep, Ipp16s* pSrcDst, int srcDstStep, IppiSize roiSize, int scaleFactor))
{
    roiSize.width *= 4;
    return ippiAdd_16s_C1IRSfs_T(pSrc, srcStep, pSrcDst, srcDstStep, roiSize, scaleFactor);
}

static IppStatus ippiAdd_32s_C1IRSfs_T_Fun(int i, void *arg)
{
	IppStatus status = ippStsNoErr;
	ippiSimpleArithmetics_32s_T_Str *ts = (ippiSimpleArithmetics_32s_T_Str *)arg;

	const Ipp32s* pSrc = (const Ipp32s*)ts->pSrc1;
	int srcStep = ts->src1Step;
	Ipp32s* pSrcDst = ts->pDst;
	int srcDstStep = ts->dstStep;

	IppiSize roiSize;
	roiSize.width = ts->roiSize.width;
	roiSize.height = ts->roiSize.height;
	int scaleFactor = ts->scaleFactor;
	IppiPoint  splitImage = ts->splitImage;
	IppiSize tileSize = ts->tileSize;
	IppiSize tailSize = ts->tailSize;

	const Ipp32s *pSrcRoi;
	Ipp32s       *pSrcDstRoi;
	IppiPoint     roiOffset;

	owniGetTileParamsByIndex_T(i, splitImage, tileSize, tailSize, &roiOffset, &roiSize);

	/* compute pointers to ROIs */
	pSrcRoi = owniGetImagePointer_32s_C1(pSrc, srcStep, roiOffset.x, roiOffset.y);
	pSrcDstRoi = owniGetImagePointer_32s_C1(pSrcDst, srcDstStep, roiOffset.x, roiOffset.y);

	Ipp32s *pLineSrc = 0;
	Ipp32s *pLineSrcDst = 0;

	for (int i = 0; i < roiSize.height; ++i) {
		pLineSrc = (Ipp32s *)((Ipp8u *)pSrcRoi + i * srcStep);
		pLineSrcDst = (Ipp32s *)((Ipp8u *)pSrcDstRoi + i * srcDstStep);

		status = ippsAdd_32s_Sfs(pLineSrc, pLineSrcDst, pLineSrcDst, roiSize.width, scaleFactor);
		if (status != ippStsNoErr) return status;
	}

	return status;
}

IPPFUN(IppStatus, ippiAdd_32s_C1IRSfs_T, (const Ipp32s* pSrc, int srcStep, Ipp32s* pSrcDst, int srcDstStep, IppiSize roiSize, int scaleFactor))
{
	IppStatus status = ippStsNoErr;

	if (pSrc == 0 || pSrcDst == 0)                 return ippStsNullPtrErr;
	if (roiSize.width <= 0 || roiSize.height <= 0) return ippStsSizeErr;

	int numTiles = 0;
	int pixelSize = sizeof (Ipp32s);

	IppiPoint splitImage;
	IppiSize  tileSize, tailSize;
	int   minTileSize = IPP_MIN(IPP64_MIN_ADD_2D / pixelSize, IPP_MAX_32S / pixelSize);

	/* split the image to tiles */
	status = owniSplitUniform2D_T(roiSize, minTileSize, &splitImage, &tileSize, &tailSize);
	if (status != ippStsNoErr) return status;

	if (splitImage.x == 1 && splitImage.y == 1)
	{
		Ipp32s *pLineSrc = 0;
		Ipp32s *pLineSrcDst = 0;

		for (int i = 0; i < roiSize.height; ++i) {
			pLineSrc = (Ipp32s*)((Ipp8u *)pSrc + i * srcStep);
			pLineSrcDst = (Ipp32s*)((Ipp8u *)pSrcDst + i * srcDstStep);

			status = ippsAdd_32s_Sfs(pLineSrc, pLineSrcDst, pLineSrcDst, roiSize.width, scaleFactor);
			if (status != ippStsNoErr) return status;
		}
		return status;
	}
	else
	{
		numTiles = splitImage.x * splitImage.y;
		ippiSimpleArithmetics_32s_T_Str ts;
		simpleArithmeticsThreadingStructureEncode_32s((Ipp32s*)pSrc, srcStep, (Ipp32s*)0, (int)0, pSrcDst, srcDstStep, roiSize, scaleFactor,
			splitImage, tileSize, tailSize, &ts);
		status = ippParallelFor_T(numTiles, (void*)&ts, ippiAdd_32s_C1IRSfs_T_Fun);
	}

	return status;
}