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

using LabelerCore.Data;


namespace LabelerCore.Loop
{
    public static class CmpSampleAttributes
    {
        //sets samples mnvPD and mahanobisDist 
        public static void SetMultivariateGaussian(Sample[] samples)
        {
            // cmp multivariate gaussian for each class
            HashSet<string> classes = new HashSet<string>(samples.Select(x => x.vehicleClass));
            var clMg = new Dictionary<string, LabelerCore.Model.MultivariateGaussian>();
            foreach (string cl in classes)
            {
                double[][] X = samples.Where( x => x.vehicleClass == cl).Select(x => x.FeatureArray).ToArray();
                clMg.Add(cl, new LabelerCore.Model.MultivariateGaussian());
                clMg[cl].Fit(X);
            }

            foreach (Sample s in samples)
            {
                try
                {
                    var res = clMg[s.vehicleClass].Predict(s.FeatureArray);
                    s.mvnPd = res.probDensity;
                    s.mahalonobisDist = res.mahalonobisDistance;
                }
                catch (Exception)
                {
                    ;
                }
            }
        }

        public static void SetDistToMean(List<Sample> samples)
        {
            //key - class, value - features mean vector
            Dictionary<string, double[]> clMean = new Dictionary<string, double[]>();
            HashSet<string> classes = new HashSet<string>(samples.Select(x => x.vehicleClass));
            foreach (string cl in classes)
                clMean.Add(cl, new double[Sample.Features.Length]);

            //fit MinMax and compute mean for each class 
            var clTf = new Dictionary<string, LabelerCore.Model.Transformers.MinMaxScaler>();
            foreach (string cl in clMean.Keys.ToArray())
            {
                double[][] X = samples.Where(x => x.vehicleClass == cl).Select(x => x.FeatureArray).ToArray();
                clTf.Add(cl, new LabelerCore.Model.Transformers.MinMaxScaler());
                X = clTf[cl].FitTransform(X);
                clMean[cl] = LabelerCore.Model.Math.Stats.Mean(X);
            }
            //set distance do mean
            foreach (Sample s in samples)
                s.distToMean = LabelerCore.Model.Math
                                   .Metrics
                                   .SquaredEuclideanDistance(clTf[s.vehicleClass].Transform(s.FeatureArray),
                                                             clMean[s.vehicleClass]);
        }

    }
}
