#include "SpectralMesh.h"
#include <iostream>
#include <cstring>

SpectralMesh::SpectralMesh(ShaderProgram *shader, std::size_t size): Mesh(shader, size) {
	_data = new float[size*size];
	_spectrLine = new float[2*size];
	_spectrLineComplex = (fftwf_complex*)fftwf_malloc((_size + 1)*sizeof(fftwf_complex));
}

SpectralMesh::~SpectralMesh() {
	delete[] _data;
	delete[] _spectrLine;
	fftwf_free(_spectrLineComplex);
}

float SpectralMesh::heightMap(std::size_t nx, std::size_t ny) const {
	return  *(_data + _size*ny + nx);
}

float SpectralMesh::heightMap(float, float) const {
	return 0.f;
}

void SpectralMesh::addLine(float *line, std::size_t depth) {
	fftwf_plan plan = fftwf_plan_dft_r2c_1d(2*_size, line, _spectrLineComplex, FFTW_ESTIMATE);
	fftwf_execute(plan);

	for(std::size_t i = 0; i < _size; ++i) {
		float real = _spectrLineComplex[i][0], imag = _spectrLineComplex[i][1];
		_spectrLine[i] = sqrtf(real*real + imag*imag);
	}

//	normalizeArray(_spectrLine, _size);
	float dbDepth = fabsf(20.0f*log10f(1.0f/powf(2.0f, depth)));
	for (std::size_t j = 0; j < _size; ++j) {
		_spectrLine[j] = (20.0f*log10f(_spectrLine[j]) + dbDepth - 80)/dbDepth;
		if(_spectrLine[j] < 0) {
			_spectrLine[j] = 0;
		}
	}
	//normalizeArray(_spectrLine, _size);

	memmove(_data + _size, _data, _size*(_size - 1)*sizeof(float));
	memcpy(_data, _spectrLine, _size*sizeof(float));

	fftwf_destroy_plan(plan);
}

void SpectralMesh::normalizeArray(float *array, std::size_t size) {
	float min = FLT_MAX, max = 0.0f;

	// calc min and max elements
	for(std::size_t i = 0; i < size; ++i) {
		float cur = array[i];
		if(cur < min)
			min = cur;

		if(cur > max)
			max = cur;
	}

    // actual normalization
    for(std::size_t i = 0; i < size; ++i) {
        array[i] = (array[i] - min)/(max - min);
    }
}
