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

namespace Intemi
{
    public class StdToyConfig : IConfiguration
    {
        bool onlyOrderedFeatures = true;
        public bool OnlyOrderedFeatures
        {
            get { return onlyOrderedFeatures; }
            set { onlyOrderedFeatures = value; }
        }

        public void Configure(ConfigBuilder confBuilder)
        {
            confBuilder.DeclareInput("Dataset",
                new Type[] { typeof(IDataTable) });
            confBuilder.DeclareOutput("Standardizer", null,
                new Type[] { typeof(IDataSetTransformer) });
            confBuilder.DeclareOutput("Dataset", "StandardizedDataTable",
                new Type[] { typeof(IDataTable) });
        }
        public object Clone() 
        {
            StdToyConfig c = new StdToyConfig();
            c.onlyOrderedFeatures = onlyOrderedFeatures;
            return c; 
        }
    }

    [Machine("Standardization ToyMachine",typeof(StdToyConfig))]
    public class StdToy : IMachine, IDataSetTransformer
    {
        IMachineBase machineBase;
        FeatureStat[] fs;
        IDataTable standardizedDataTable;

        public IDataTable StandardizedDataTable
        {
            get { return standardizedDataTable; }
        }

        public void SetMachineBase(IMachineBase _machineBase)
        {
            machineBase = _machineBase;
        }
        public void Run(ref bool shouldTerminate)
        {
            IDataTable dt = machineBase.GetInput("Dataset") as IDataTable;
            fs = dt.FeatureStatistics;
            standardizedDataTable = (IDataTable)Transform(dt);
        }

        public IDataSet Transform(IDataSet dataSet)
        {
            IDataTable dataTable = dataSet as IDataTable;
            bool onlyOrdered = ((StdToyConfig)machineBase.ConfBase.Configuration).OnlyOrderedFeatures;

            IDataTableBuilder dtb = (IDataTableBuilder)dataTable.GetBuilder();
            dtb.CloneFrom(dataTable);
            IFeaturesInfo fi = dataTable.FeaturesInfo;

            for (int i = 0; i < dataTable.FeaturesInfo.Count; i++)
                if (!onlyOrdered || fi[i].Ordered)
                    dtb.SetOrdered(i, true);

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

            for (int i = 0; i < dataTable.InstanceCount; i++)
            {
                for (int j = 0; j < dataTable.FeaturesInfo.Count; j++)
                    if (!m[i, j] && (!onlyOrdered || fi[j].Ordered))
                    {
                        v[i, j] = (float) ((double)v[i, j] - fs[j].mean);
                        if (fs[j].standardDev != 0)
                            v[i, j] = (float)((double)v[i, j] / fs[j].standardDev);
                    }
            }            
            return dtb.Build();
        }
    }
}
