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

namespace Intemi
{
    public class MDMissingGenConfig : IConfiguration
    {
        int mLossRate = 10;
        public int LossRate
        {
            get { return mLossRate; }
            set 
            {
                if (value < 0)
                {
                    mLossRate = 0;
                }
                else if (value > 100)
                {
                    mLossRate = 100;
                }
                else
                {
                    mLossRate = value;
                }
            }
        }
        public void Configure(ConfigBuilder confBuilder)
        {
            confBuilder.DeclareInput("Dataset",
                new Type[] { typeof(IDataTable) }, false);
            confBuilder.DeclareOutput("MissingDataGenerator", null,
                new Type[] { typeof(IDataSetTransformer) });
            confBuilder.DeclareOutput("Dataset", "MissingDataTable",
                new Type[] { typeof(IDataTable) });
        }
        public object Clone()
        {
            MDMissingGenConfig c = new MDMissingGenConfig();
            return c;
        }
    }

    [Machine("MDMissingGen", typeof(MDMissingGenConfig))]
    public class MDMissingGen : IMachine, IDataSetTransformer
    {
        IMachineBase modelBase;
        IDataTable mMissingDataTable;

        public IDataTable MissingDataTable
        {
            get { return mMissingDataTable; }
        }

        public void SetMachineBase(IMachineBase _modelBase)
        {
            modelBase = _modelBase;
        }
        public void Run(ref bool shouldTerminate)
        {
            IDataTable dt = modelBase.GetInput("Dataset") as IDataTable;
            mMissingDataTable = (IDataTable)Transform(dt);
        }
        
        public IDataSet Transform(IDataSet dataSet)
        {
            IDataTable dataTable = dataSet as IDataTable;
            IDataTableBuilder dtb = (IDataTableBuilder)dataTable.GetBuilder();
            int lossRate = ((MDMissingGenConfig)modelBase.ConfBase.Configuration).LossRate;

            dtb.CloneFrom(dataTable);

            float[,] values = dtb.Values;
            bool[,] missing = dtb.Missing;

            // Lista pomocnicza z lista pojedynczych elementów danych
            // celem usuwania danych bez powtorzen
            List<int> elemsList = new List<int>();

            int counter = 0;
            for (int i = 0; i < dataTable.InstanceCount; i++)
            {
                for (int j = 0; j < dataTable.FeaturesInfo.Count; j++)
                {
                    elemsList.Add(counter);
                    counter++;
                }
            }

            Random randObj = new Random();

            // Usuwanie elementów
            for (int p = 0; p < dataTable.InstanceCount * dataTable.FeaturesInfo.Count * lossRate / 100; p++)
            {
                int randValue = (randObj.Next() % counter);
                int elemPos = elemsList[randValue];
                counter--;
                elemsList.Remove(randValue);

                int row = (int)((float)elemPos / dataTable.FeaturesInfo.Count);
                int col = elemPos % dataTable.FeaturesInfo.Count;

                values[row, col] = 10000000;
                missing[row, col] = true;
            }

            return dtb.Build();
        }
    }
}

