using System;
using System.Collections.Generic;
using System.Text;

namespace Intemi
{
    public enum AnalyzeStyle { acrossFeatures, acrossVectors };
    public class MDNaiveMethodConfig : IConfiguration
    {
        AnalyzeStyle analyzeStyle = AnalyzeStyle.acrossVectors;
        public AnalyzeStyle AnalyzeStyle
        {
            get { return analyzeStyle; }
            set { analyzeStyle = value; }
        }
        public void Configure(ConfigBuilder confBuilder)
        {
            confBuilder.DeclareInput("Dataset",
                new Type[] { typeof(IDataTable) }, false);
            confBuilder.DeclareOutput("MissingDataFiller", null,
                new Type[] { typeof(IDataSetTransformer) });
            confBuilder.DeclareOutput("Dataset", "FilledDataTable", 
                new Type[] { typeof(IDataTable) });
        }
        public object Clone()
        {
            MDNaiveMethodConfig c = new MDNaiveMethodConfig();
            return c;
        }
    }

    [Machine("NaiveMethod", typeof(MDNaiveMethodConfig))]
    public class NaiveMethod : IMachine, IDataSetTransformer
    {
        IMachineBase modelBase;
        FeatureStat[] fs;
        IDataTable filledDataTable;

        public IDataSet FilledDataTable
        {
            get { return filledDataTable; }
        }

        public void SetMachineBase(IMachineBase _modelBase)
        {
            modelBase = _modelBase;
        }
        public void Run(ref bool shouldTerminate)
        {
            IDataTable dt = modelBase.GetInput("Dataset") as IDataTable;
            fs = dt.FeatureStatistics;
            filledDataTable = (IDataTable)Transform(dt);
        }
        public IDataSet Transform(IDataSet dataSet)
        {
            IDataTable dataTable = dataSet as IDataTable;
            AnalyzeStyle analyzeStyle = ((MDNaiveMethodConfig)modelBase.ConfBase.Configuration).AnalyzeStyle;
            IDataTableBuilder dtb = (IDataTableBuilder)dataTable.GetBuilder();
            dtb.CloneFrom(dataTable);

            IFeaturesInfo fi = dataTable.FeaturesInfo;

            double[] filledData;
            int dataCounter;

            float[,] v = dtb.Values;
            bool[,] m = dtb.Missing;

            switch (analyzeStyle)
            {
                case AnalyzeStyle.acrossVectors:
                    filledData = new double[dataTable.FeaturesInfo.Count];
                    for (int i = 0; i < dataTable.FeaturesInfo.Count; i++)
                    {
                        filledData[i] = fs[i].mean;
                    }
                    for (int i = 0; i < dataTable.FeaturesInfo.Count; i++)
                    {
                        for (int j = 0; j < dataTable.InstanceCount; j++)
                        {
                            if (m[j, i])
                            {
                                v[j, i] = (float)filledData[i];
                                m[j, i] = false;
                            }
                        }
                    }
                    break;
                case AnalyzeStyle.acrossFeatures:;
                    filledData = new double[dataTable.InstanceCount];
                    for (int i = 0; i < dataTable.InstanceCount; i++)
                    {
                        filledData[i] = 0;
                        dataCounter = 0;
                        for (int j = 0; j < dataTable.FeaturesInfo.Count; j++)
                        {
                            if (!m[i, j])
                            {
                                filledData[i] += v[i, j];
                                dataCounter++;
                            }
                        }
                        filledData[i] /= dataCounter;
                    }
                    for (int i = 0; i < dataTable.FeaturesInfo.Count; i++)
                    {
                        for (int j = 0; j < dataTable.InstanceCount; j++)
                        {
                            if (m[j, i])
                            {
                                v[j, i] = (float)filledData[i];
                                m[j, i] = false;
                            }
                        }
                    }
                    break;
            };


            /* Debuging */
            /*for (int j = 0; j < dataTable.InstanceCount; j++)
            {
                for (int i = 0; i < dataTable.FeaturesInfo.Count; i++)
                {
                    Console.Write(v[j, i] + " ");
                }
                Console.WriteLine();
            }
            for (int i = 0; i < dataTable.FeaturesInfo.Count; i++)
            {
                Console.Write(fs[i].mean + " ");
            }
            */
            return dtb.Build();
        }
    }
}

