// Copyright 2025 RnD Center "ELVEES", JSC

/*! \file
 *  \brief Реализация вспомогательных функций
 */

#include "common.h"

#include <math.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void create_spectrum(float *dst, const int size, const int freq, const float amplitude) {
  for (size_t i = 0; i < size; ++i) {
    dst[2 * i + 1] = amplitude * cosf(2 * M_PI * i * freq / size);
    dst[2 * i] = amplitude * sinf(2 * M_PI * i * freq / size);
  }
}

float maximum_norm(const float *dsp_res, const float *ref_res, const int size) {
  float diff = fabs(ref_res[0] - dsp_res[0]);
  for (size_t i = 1; i < 2 * size; ++i) {
    float diff_i = fabs(ref_res[i] - dsp_res[i]);
    if (diff_i > diff) diff = diff_i;
  }

  return diff;
}

void print_vector(float *src, const int size) {
  for (size_t i = 0; i < size; ++i) {
    if (src[2 * i] > 0)
      printf("%f + %fi, ", src[2 * i + 1], src[2 * i]);
    else
      printf("%f - %fi, ", src[2 * i + 1], fabs(src[2 * i]));
  }
  fflush(stdout);
}

void print_vector_to_file(float *src, const int size, char path[]) {
  FILE *fp;
  fp = fopen(path, "w");
  for (size_t i = 0; i < size; ++i) {
    fprintf(fp, "%f + %fi, ", src[2 * i + 1], src[2 * i]);
  }
  fclose(fp);
}

void create_spectrum_2d(float *dst, const int height, const int length, const int freq1, const int freq2,
                        const int data_type) {
  float *exp1 = malloc(2 * height * sizeof(float));
  float *exp2 = malloc(2 * length * sizeof(float));
  switch (data_type) {
    case 1:
    case 3:
      create_spectrum(exp1, height, freq1, 1.0);
      create_spectrum(exp2, length, freq2, 1.0);
      break;
    case 2:
      create_spectrum(exp1, height, freq1, 0.99);
      create_spectrum(exp2, length, freq2, 0.99);
      break;
  }

  for (size_t i = 0; i < height * 2; i += 2)
    for (size_t j = 0; j < length * 2; j += 2) {
      dst[i * length + j] = exp1[i] * exp2[j + 1] + exp1[i + 1] * exp2[j];
      dst[i * length + j + 1] = exp1[i + 1] * exp2[j + 1] - exp1[i] * exp2[j];
    }

  free(exp1);
  free(exp2);
}

float maximum_norm_conv2d(const float *dsp_res, const float *ref_res, const int rows, const int cols) {
  const int32_t cols2 = 1 << (int)(ceil(log2f(cols)));
  float diff = fabs(ref_res[0] - dsp_res[0]);
  for (size_t i = 0; i < rows; i += 2) {
    for (size_t j = 0; j < cols * 2; ++j) {
      float diff_i = fabs(ref_res[i * cols + j] - dsp_res[i * cols2 + j]);
      if (diff_i > diff) diff = diff_i;
    }
  }

  return diff;
}
