using Microsoft.Xna.Framework;
using NAudio.Dsp;
using NAudio.Wave;
using System;

namespace RhythmBullet.Audio
{
    public class TransparentSampleProvider : ISampleProvider
    {
        private const int FFT_SIZE = 2048;
        private readonly int m; 
        private ISampleProvider source;
        private Complex[] fftBuffer;
        private volatile bool updatedSpectrum;
        private readonly float[] currentSpectrum;
        private int channelCount;
        public bool performFFT;



        public TransparentSampleProvider(ISampleProvider sampleProvider)
        {
            m = (int)Math.Log(FFT_SIZE);
            source = sampleProvider;
            channelCount = sampleProvider.WaveFormat.Channels;
            fftBuffer = new Complex[FFT_SIZE];
            currentSpectrum = new float[FFT_SIZE];
        }

        public WaveFormat WaveFormat
        {
            get
            {
                return source.WaveFormat;
            }
        }

        public float[] GetCurrentSpectrum()
        {
            if (updatedSpectrum)
            {
                lock (fftBuffer)
                {
                    for (int binID = 0; binID < currentSpectrum.Length; binID++)
                    {
                        currentSpectrum[binID] = fftBuffer[binID].X;
                    }
                }
            }

            return currentSpectrum;
        }

        public int Read(float[] buffer, int offset, int count)
        {
            int sampleCount = source.Read(buffer, offset, count);

            if (performFFT)
            {
                int fftOffset = 0;
                for (int s = 0; s < sampleCount; s += channelCount)
                {
                    if (s >= FFT_SIZE)
                    {
                        lock (fftBuffer)
                        {
                            FastFourierTransform.FFT(true, m, fftBuffer);
                        }
                        updatedSpectrum = true;
                        fftOffset -= FFT_SIZE;
                    }
                    float greatestVal = 0;
                    for (int c = 0; c < channelCount; c++)
                    {
                        greatestVal = MathHelper.Max(buffer[s + offset + c], greatestVal);
                    }

                    fftBuffer[s + fftOffset].X = (float)(buffer[s + offset] * FastFourierTransform.HammingWindow(s, FFT_SIZE));
                    fftBuffer[s + fftOffset].Y = 0;

                }

            }

            return sampleCount;
        }
    }
}
