// Copyright 2024-2025 RnD Center "ELVEES", JSC

/*! \file
 *  \brief Заголовочный файл c функциями создания DMA-цепочек
 *  \author Фролов Андрей
 */

#ifndef DMA_CHAIN_CREATORS
#define DMA_CHAIN_CREATORS

#include <iostream>

#include "elcore50-dsplib/tile_length_setters.hpp"
#include "elcore50-dsplib/tile_segmentation.hpp"

/*!
 *  \fn int CreateTileSegConfigNeg(const T* src, T* dst, const int32_t size,
                                   TileSegConfig* config, void* local_mem_ptr,
                                   size_t manual_tile_length = 0)
 *  \brief Создание цепочек для функции отрицания элементов вектора
 *  \param[in] src входные данные
 *  \param[in] dst выходные данные
 *  \param[in] size размер входных данных
 *  \param[out] config указатель на структуру цепочки
 *  \param[in] local_mem_ptr указатель на локальную память
 *  \param[in] manual_tile_length пользовательский размер тайла
 */
template <typename T>
int CreateTileSegConfigNeg(const T* src, T* dst, const int32_t size, TileSegConfig* config, void* local_mem_ptr,
                           size_t manual_tile_length = 0) {
  if (!src || !dst) {
    std::cout << "WARNING! CreateTileSegConfigNeg: NULL ptr" << std::endl;
    return 1;
  }

  SetNegTileLength(src[0], manual_tile_length, config);

  void* src_arrays[] = {const_cast<void*>(static_cast<const void*>(src))};
  void* dst_arrays[] = {dst};

  CreateChains1D(src_arrays, 1, dst_arrays, 1, size, sizeof(src[0]), config, static_cast<uint16_t*>(local_mem_ptr));

  return 0;
}

/*!
 *  \fn int CreateTileSegConfigAdd(const T* src0, const T* src1, T* dst,
                                   const int32_t size, TileSegConfig* config,
                                   void* local_mem_ptr,
                                   size_t manual_tile_length = 0)
 *  \brief Создание цепочек для функции суммы элементов
 *  \param[in] src0 входные данные
 *  \param[in] src1 входные данные
 *  \param[in] dst выходные данные
 *  \param[in] size размер входных данных
 *  \param[out] config указатель на структуру цепочки
 *  \param[in] local_mem_ptr указатель на локальную память
 *  \param[in] manual_tile_length пользовательский размер тайла
 */
template <typename T>
int CreateTileSegConfigAdd(const T* src0, const T* src1, T* dst, const int32_t size, TileSegConfig* config,
                           void* local_mem_ptr, size_t manual_tile_length = 0) {
  if (!src0 || !src1 || !dst) {
    std::cout << "WARNING! CreateTileSegConfigAdd: NULL ptr" << std::endl;
    return 1;
  }

  SetAddTileLength(src0[0], manual_tile_length, config);

  void* src_arrays[] = {const_cast<void*>(static_cast<const void*>(src0)),
                        const_cast<void*>(static_cast<const void*>(src1))};
  void* dst_arrays[] = {dst};

  CreateChains1D(src_arrays, 2, dst_arrays, 1, size, sizeof(src0[0]), config, static_cast<uint16_t*>(local_mem_ptr));

  return 0;
}

/*!
 *  \fn CreateTileSegConfigMinVal(const T* src, const int32_t size,
                                  TileSegConfig* config, void* local_mem_ptr,
                                  size_t manual_tile_length = 0)
 *  \brief Создание цепочек для функции поиска значения минимального элемента в
           векторе
 *  \param[in] src входные данные
 *  \param[in] size размер входных данных
 *  \param[out] config указатель на структуру цепочки
 *  \param[in] local_mem_ptr указатель на локальную память
 *  \param[in] manual_tile_length пользовательский размер тайла
 */
template <typename T>
int CreateTileSegConfigMinVal(const T* src, const int32_t size, TileSegConfig* config, void* local_mem_ptr,
                              size_t manual_tile_length = 0) {
  if (!src) {
    std::cout << "WARNING! CreateTileSegConfigMinVal: NULL ptr" << std::endl;
    return 1;
  }

  SetMinValTileLength(src[0], manual_tile_length, config);

  void* src_arrays[] = {const_cast<void*>(static_cast<const void*>(src))};
  void* dst_arrays[] = {};

  CreateChains1D(src_arrays, 1, dst_arrays, 0, size, sizeof(src[0]), config, static_cast<uint16_t*>(local_mem_ptr));

  return 0;
}

/*!
 *  \fn int CreateTileSegConfigMaxVal(const T* src, const int32_t size,
                                      TileSegConfig* config, void* local_mem_ptr,
                                      size_t manual_tile_length = 0)
 *  \brief Создание цепочек для функции поиска значения максимального элемента в
           векторе
 *  \param[in] src входные данные
 *  \param[in] size размер входных данных
 *  \param[out] config указатель на структуру цепочки
 *  \param[in] local_mem_ptr указатель на локальную память
 *  \param[in] manual_tile_length пользовательский размер тайла
 */
template <typename T>
int CreateTileSegConfigMaxVal(const T* src, const int32_t size, TileSegConfig* config, void* local_mem_ptr,
                              size_t manual_tile_length = 0) {
  if (!src) {
    std::cout << "WARNING! CreateTileSegConfigMaxVal: NULL ptr" << std::endl;
    return 1;
  }

  SetMaxValTileLength(src[0], manual_tile_length, config);

  void* src_arrays[] = {const_cast<void*>(static_cast<const void*>(src))};
  void* dst_arrays[] = {};

  CreateChains1D(src_arrays, 1, dst_arrays, 0, size, sizeof(src[0]), config, static_cast<uint16_t*>(local_mem_ptr));

  return 0;
}

/*!
 *  \fn int CreateTileSegConfigDotprod(const T* src0, const T* src1,
                                       const int32_t size, TileSegConfig* config,
                                       void* local_mem_ptr,
                                       size_t manual_tile_length = 0)
 *  \brief Создание цепочек для функции cкалярного произведения векторов
 *  \param[in] src0 входные данные
 *  \param[in] src1 входные данные
 *  \param[in] size размер входных данных
 *  \param[out] config указатель на структуру цепочки
 *  \param[in] local_mem_ptr указатель на локальную память
 *  \param[in] manual_tile_length пользовательский размер тайла
 */
template <typename T>
int CreateTileSegConfigDotprod(const T* src0, const T* src1, const int32_t size, TileSegConfig* config,
                               void* local_mem_ptr, size_t manual_tile_length = 0) {
  if (!src0 || !src1) {
    std::cout << "WARNING! CreateTileSegConfigDotprod: NULL ptr" << std::endl;
    return 1;
  }

  SetDotprodTileLength(src0[0], manual_tile_length, config);

  void* src_arrays[] = {const_cast<void*>(static_cast<const void*>(src0)),
                        const_cast<void*>(static_cast<const void*>(src1))};
  void* dst_arrays[] = {};

  CreateChains1D(src_arrays, 2, dst_arrays, 0, size, sizeof(src0[0]), config, static_cast<uint16_t*>(local_mem_ptr));

  return 0;
}

/*!
 *  \fn int CreateTileSegConfigVecSumSq(const T* src, const int32_t size,
                                        TileSegConfig* config,
                                        void* local_mem_ptr,
                                        size_t manual_tile_length = 0)
 *  \brief Создание цепочек для функции вычисления корня из суммы элементов
    вектора
 *  \param[in] src0 входные данные
 *  \param[in] size размер входных данных
 *  \param[out] config указатель на структуру цепочки
 *  \param[in] local_mem_ptr указатель на локальную память
 *  \param[in] manual_tile_length пользовательский размер тайла
 */
template <typename T>
int CreateTileSegConfigVecSumSq(const T* src, const int32_t size, TileSegConfig* config, void* local_mem_ptr,
                                size_t manual_tile_length = 0) {
  if (!src) {
    std::cout << "WARNING! CreateTileSegConfigVecSumSq: NULL ptr" << std::endl;
    return 1;
  }

  SetVecSumSqTileLength(src[0], manual_tile_length, config);

  void* src_arrays[] = {const_cast<void*>(static_cast<const void*>(src))};
  void* dst_arrays[] = {};

  CreateChains1D(src_arrays, 1, dst_arrays, 0, size, sizeof(src[0]), config, static_cast<uint16_t*>(local_mem_ptr));

  return 0;
}

/*!
 *  \fn int CreateTileSegConfigWVec(
                const T* src0, const T* src1, const T w, T* dst,
                const int32_t size, TileSegConfig* config, void* local_mem_ptr,
                size_t manual_tile_length = 0)
 *  \brief Создание цепочек для функции сложения элементов вектора с взвешенными
           элементами другого вектора
 *  \param[in] src0 входные данные
 *  \param[in] src1 входные данные
 *  \param[in] w весовой коэффициент
 *  \param[in] dst выходные данные
 *  \param[in] size размер входных данных
 *  \param[out] config указатель на структуру цепочки
 *  \param[in] local_mem_ptr указатель на локальную память
 *  \param[in] manual_tile_length пользовательский размер тайла
 */
template <typename T>
int CreateTileSegConfigWVec(const T* src0, const T* src1, const T w, T* dst, const int32_t size, TileSegConfig* config,
                            void* local_mem_ptr, size_t manual_tile_length = 0) {
  if (!src0 || !src1 || !dst) {
    std::cout << "WARNING! CreateTileSegConfigWVec: NULL ptr" << std::endl;
    return 1;
  }

  SetWVecTileLength(src0[0], manual_tile_length, config);

  void* src_arrays[] = {const_cast<void*>(static_cast<const void*>(src0)),
                        const_cast<void*>(static_cast<const void*>(src1))};
  void* dst_arrays[] = {dst};

  CreateChains1D(src_arrays, 2, dst_arrays, 1, size, sizeof(src0[0]), config, static_cast<uint16_t*>(local_mem_ptr));

  *(reinterpret_cast<T*>(config->param0)) = w;

  return 0;
}

/*!
 *  \fn int CreateTileSegConfigDotprodSqr(const Ret_type G, const T* src0,
                                          const T* src1, Ret_type* r,
                                          const int32_t size,
                                          TileSegConfig* config,
                                          void* local_mem_ptr,
                                          size_t manual_tile_length = 0)
 *  \brief Создание цепочек для функции подсчета суммы квадратов элементов
           второго вектора, вычисление скалярного произведения векторов
 *  \param[in] G коэффициент, который суммируется с результатом суммы квадратов
 *  \param[in] src0 входные данные
 *  \param[in] src1 входные данные
 *  \param[in] r скалярное произведение векторов
 *  \param[in] size размер входных данных
 *  \param[out] config указатель на структуру цепочки
 *  \param[in] local_mem_ptr указатель на локальную память
 *  \param[in] manual_tile_length пользовательский размер тайла
 */
template <typename T, typename Ret_type>
int CreateTileSegConfigDotprodSqr(const Ret_type G, const T* src0, const T* src1, Ret_type* r, const int32_t size,
                                  TileSegConfig* config, void* local_mem_ptr, size_t manual_tile_length = 0) {
  if (!src0 || !src1 || !r) {
    std::cout << "WARNING! CreateTileSegConfigDotprodSqr: NULL ptr" << std::endl;
    return 1;
  }

  SetDotprodSqrTileLength(src0[0], manual_tile_length, config);

  void* src_arrays[] = {const_cast<void*>(static_cast<const void*>(src0)),
                        const_cast<void*>(static_cast<const void*>(src1))};
  void* dst_arrays[] = {};

  CreateChains1D(src_arrays, 2, dst_arrays, 0, size, sizeof(src0[0]), config, static_cast<uint16_t*>(local_mem_ptr));

  *(reinterpret_cast<Ret_type*>(config->param0)) = G;
  *(reinterpret_cast<Ret_type**>(config->return_value1)) = r;

  return 0;
}

/*!
 *  \fn int CreateTileSegConfigRecip16(const int16_t* x, int16_t* rfrac,
                                       int16_t* rexp, const int32_t size,
                                       TileSegConfig* config,
                                       void* local_mem_ptr,
                                       size_t manual_tile_length = 0)
 *  \brief Создание цепочек для функции вычисления обратной величины для чисел с
           фиксированной точкой типа int16
 *  \param[in] x входные данные типа int16
 *  \param[in] rfrac выходные данные типа int16, нормализованное значение
 *  \param[in] rexp выходные данные типа int16, значение степени экспоненты
 *  \param[in] size размер входных массивов
 *  \param[out] config указатель на структуру цепочки
 *  \param[in] local_mem_ptr указатель на локальную память
 *  \param[in] manual_tile_length пользовательский размер тайла
 */
int CreateTileSegConfigRecip16(const int16_t* x, int16_t* rfrac, int16_t* rexp, const int32_t size,
                               TileSegConfig* config, void* local_mem_ptr, size_t manual_tile_length = 0) {
  if (!x || !rfrac || !rexp) {
    std::cout << "WARNING! CreateTileSegConfigRecip16: NULL ptr" << std::endl;
    return 1;
  }

  SetRecip16TileLength(x[0], manual_tile_length, config);

  void* src_arrays[] = {const_cast<void*>(static_cast<const void*>(x))};
  void* dst_arrays[] = {rfrac, rexp};

  CreateChains1D(src_arrays, 1, dst_arrays, 2, size, sizeof(x[0]), config, static_cast<uint16_t*>(local_mem_ptr));

  return 0;
}

/// Создание цепочек для функции умножения чисел с фиксированной точкой
/// @return 0=success, 1=error
int CreateTileSegConfigMul16I16F(const int32_t* src0,           ///< [in]  входные данные первого массива
                                 const int32_t* src1,           ///< [in]  входные данные второго массива
                                 int32_t* dst,                  ///< [in]  выходные данные типа int32
                                 const int32_t size,            ///< [in]  количество элементов входных массивов
                                 TileSegConfig* config,         ///< [out] указатель на структуру цепочки
                                 void* local_mem_ptr,           ///< [in]  указатель на локальную память
                                 size_t manual_tile_length = 0  ///< [in]  пользовательский размер тайла
) {
  if (!src0 || !src1 || !dst) {
    std::cout << "WARNING! CreateTileSegConfigMul32FixPoint: NULL ptr" << std::endl;
    return 1;
  }

  SetMul16I16FTileLength(src0[0], manual_tile_length, config);

  void* src_arrays[] = {const_cast<void*>(static_cast<const void*>(src0)),
                        const_cast<void*>(static_cast<const void*>(src1))};
  void* dst_arrays[] = {dst};

  CreateChains1D(src_arrays, 2, dst_arrays, 1, size, sizeof(src0[0]), config, static_cast<uint16_t*>(local_mem_ptr));

  return 0;
}

#endif
