using System;
using System.Collections.Generic;
using System.Linq;

using Hiperscan.Spectroscopy;

namespace Hiperscan.Spectroscopy.Math
{
    public static class NoiseGenerator
    {
        private static System.Random _global_random = null;

        public static DataSet GenerateWhiteNoise(DataSet origin, double amplitude, int smoothness, int seed_modifier, bool use_true_random)
        {
            throw new NotSupportedException("Noise generator is not supported anymore.");

#pragma warning disable CS0162 // Unerreichbarer Code wurde entdeckt.
            Random random = use_true_random ?
                            NoiseGenerator.TrueRandomizer :
                            new Random(BitConverter.ToInt32(BitConverter.GetBytes((float)origin.Corr() * uint.MaxValue), 0) ^ seed_modifier);

            int expand = smoothness / 2;
            double[] noise = new double[origin.Count + 2 * expand];
            double[] x_values = new double[noise.Length];
            origin.X.CopyTo(0, x_values, expand, origin.Count);
            double x_min = origin.XMin();
            double x_max = origin.XMax();

            for (int i=0 ; i < expand ; i++)
            {
                x_values[i]                       = x_min - expand + i;
                x_values[x_values.Length - 1 - i] = x_max + expand - i;
            }

            for (int i=0 ; i < noise.Length ; i++)
                noise[i] = (random.NextDouble() * 2.0 - 1.0) * amplitude;

            return new DataSet(x_values, noise).Filter(3, smoothness).GetRange(x_min, x_max);
#pragma warning restore CS0162 // Unerreichbarer Code wurde entdeckt.
        }

        public static DataSet GenerateWhiteNoise(DataSet origin, double amplitude, int smoothness)
        {
            return NoiseGenerator.GenerateWhiteNoise(origin, amplitude, smoothness, 0, false);
        }

        public static DataSet AddWhiteNoise(DataSet origin, double amplitude, int smoothness, int seed_modifier, bool use_true_random)
        {
            return origin + NoiseGenerator.GenerateWhiteNoise(origin, amplitude, smoothness, seed_modifier, use_true_random);
        }

        public static DataSet AddWhiteNoise(DataSet origin, double amplitude, int smoothness)
        {
            return origin + NoiseGenerator.GenerateWhiteNoise(origin, amplitude, smoothness);
        }

        public static DataSet GenerateWhiteNoise(Spectrum origin, double amplitude, int smoothness, int seed_modifier, bool use_true_random)
        {
            DataSet ds = origin.Intensity;
            if (origin.HasReference)
                ds += origin.Reference.Intensity;

            return NoiseGenerator.GenerateWhiteNoise(ds, amplitude, smoothness, seed_modifier, use_true_random);
        }

        public static DataSet GenerateWhiteNoise(Spectrum origin, double amplitude, int smoothness)
        {
            return NoiseGenerator.GenerateWhiteNoise(origin, amplitude, smoothness, 0, false);
        }

        public static Spectrum GenerateWhiteNoiseSpectrum(Spectrum origin, double amplitude, int smoothness, int seed_modifier, bool use_true_random)
        {
            Spectrum spectrum = origin.Clone();
            DataSet dark_intensity = NoiseGenerator.GenerateWhiteNoise(origin.RawIntensity, amplitude, smoothness, seed_modifier, use_true_random);

            spectrum.RawIntensity = NoiseGenerator.GenerateWhiteNoise(origin, amplitude, smoothness, seed_modifier, use_true_random);
            if (origin.HasReference)
            {
                Spectrum reference = spectrum.Reference.Clone();
                reference.RawIntensity = NoiseGenerator.GenerateWhiteNoise(origin.Reference,
                                                                            amplitude,
                                                                            smoothness,
                                                                            seed_modifier,
                                                                            use_true_random);
                spectrum.Reference = reference;
            }

            spectrum.DarkIntensity = new DarkIntensity(origin.DarkIntensity.Intensity, dark_intensity.YSigma());

            return spectrum;
        }

        public static Spectrum GenerateWhiteNoiseSpectrum(Spectrum origin, double amplitude, int smoothness)
        {
            return NoiseGenerator.GenerateWhiteNoiseSpectrum(origin, amplitude, smoothness, 0, false);
        }

        public static Spectrum AddWhiteNoise(Spectrum origin, double amplitude, int smoothness, int seed_modifier, bool use_true_random)
        {
            Spectrum spectrum = origin.Clone();
            Spectrum white_noise = NoiseGenerator.GenerateWhiteNoiseSpectrum(origin, amplitude, smoothness, seed_modifier, use_true_random);

            spectrum.DarkIntensity = new DarkIntensity(white_noise.DarkIntensity);
            spectrum.RawIntensity = new DataSet(spectrum.RawIntensity) +  new DataSet(white_noise.RawIntensity);
            if (spectrum.HasReference && white_noise.HasReference)
            {
                Spectrum reference = spectrum.Reference;
                reference.RawIntensity = new DataSet(reference.RawIntensity) + new DataSet(white_noise.Reference.RawIntensity);
                spectrum.Reference = reference;
            }

            return new Spectrum(spectrum);
        }

        public static Spectrum AddWhiteNoise(Spectrum origin, double amplitude, int smoothness)
        {
            return NoiseGenerator.AddWhiteNoise(origin, amplitude, smoothness, 0, false);
        }

        private static Random TrueRandomizer
        {
            get
            {
                if (_global_random ==  null)
                    _global_random = new System.Random(new Guid().GetHashCode());

                return new Random(_global_random.Next());
            }
        }
    }
}
