/*******************************************************
 * Copyright (c) 2015, ArrayFire
 * All rights reserved.
 *
 * This file is distributed under 3-clause BSD license.
 * The complete license agreement can be obtained at:
 * http://arrayfire.com/licenses/BSD-3-Clause
 ********************************************************/

#pragma once
#include <af/defines.h>
#include <af/constants.h>
#include <cmath>
#include <algorithm>
#include "backend.hpp"

namespace cpu
{

static inline
dim_t trimIndex(int const & idx, dim_t const & len)
{
    int ret_val = idx;
    int offset  = abs(ret_val)%len;
    if (ret_val<0) {
        ret_val = offset-1;
    } else if (ret_val>=(int)len) {
        ret_val = len-offset-1;
    }
    return ret_val;
}

static inline
dim_t clamp(dim_t a, dim_t mn, dim_t mx)
{
    return (a<mn ? mn : (a>mx ? mx : a));
}

static inline
unsigned getIdx(af::dim4 const & strides, int i, int j = 0, int k = 0, int l = 0)
{
    return (l * strides[3] + k * strides[2] + j * strides[1] + i * strides[0]);
}

template<typename T>
void gaussian1D(T* out, int const dim, double sigma=0.0)
{
    if(!(sigma>0)) sigma = 0.25*dim;

    T sum = (T)0;
    for(int i=0;i<dim;i++)
    {
        int x = i-(dim-1)/2;
        T el = 1. / std::sqrt(2 * af::Pi * sigma*sigma) * std::exp(-((x*x)/(2*(sigma*sigma))));
        out[i] = el;
        sum   += el;
    }

    for(int k=0;k<dim;k++)
        out[k] /= sum;
}

}
