using System;
using System.Collections.Generic;
using System.Text;
using Intemi.InTrees.Implements;
using Intemi.Query;

namespace Intemi.InTrees
{
    public class MetaTree2Config : IConfiguration
    {
        public void Configure(ConfigBuilder confBuilder)
        {
            confBuilder.DeclareInput("Dataset",
                new Type[] { typeof(IDataTable), typeof(ITargets) }, false);
            confBuilder.DeclareOutput("Classifier", "ClassSubmachine",
                new Type[] { typeof(IClassifier) });
            //confBuilder.DeclareOutput("Classifier", 
            //    new Type[] { typeof(IClassifier) }, false, "ClassSubmachine", null);
            //confBuilder.DeclareOutput(
        }
        public object Clone()
        {
            MetaTree2Config conf = new MetaTree2Config();
            return conf;
        }
    }

    [Machine("META TREE2", typeof(MetaTree2Config))]
    public class MetaTree2 : IMachine
    {
        IMachineBase machineBase;
        public void SetMachineBase(IMachineBase mb)
        {
            machineBase = mb;
        }

        IClassifier classSubmachine = null;
        public IClassifier ClassSubmachine
        {
            get { return classSubmachine; }
        }

        public void Run(ref bool shouldTerminate)
        {
            IDataTable dataTable = machineBase.GetInput("Dataset") as IDataTable;

            List<ConfigBase> confs = new List<ConfigBase>();
            ConfigBase treeConfig;
            InTreeConfig ccConf;

            #region Meta Konfiguracje
            // Pierwsza konfiguracja do meta przebiegu
            treeConfig = machineBase.Project.GetConfiguration("INTREE");
            ccConf = (InTreeConfig)treeConfig.Configuration;
            ccConf.Pruning = new Pruning2();
            ccConf.NodeTestGenerator = new BinaryTestGenerator();
            ccConf.NodeTestSelector = new Gini();
            ccConf.StoppingCriterium = new NaturalStoppingCriterium();
            ccConf.TargetSelector = new TargetSelector();
            ccConf.PruningMode = InTreeConfig.PRUNING_AUTO;
            confs.Add(treeConfig);

            // Druga konfiguracja do meta przebiegu
            treeConfig = machineBase.Project.GetConfiguration("INTREE");
            ccConf = (InTreeConfig)treeConfig.Configuration;
            ccConf.Pruning = new Pruning2();
            ccConf.NodeTestGenerator = new MultiSplitTestGenerator();
            ccConf.NodeTestSelector = new InfoGainNTS(true);
            ccConf.StoppingCriterium = new NaturalStoppingCriterium();
            ccConf.TargetSelector = new TargetSelector();
            ccConf.PruningMode = InTreeConfig.PRUNING_AUTO;
            confs.Add(treeConfig);

            // Trzecia konfiguracja do meta przebiegu
            treeConfig = machineBase.Project.GetConfiguration("INTREE");
            ccConf = (InTreeConfig)treeConfig.Configuration;
            ccConf.Pruning = new Pruning2();
            ccConf.NodeTestGenerator = new BinaryTestGenerator();
            ccConf.NodeTestSelector = new InfoGainNTS(true);
            ccConf.StoppingCriterium = new NaturalStoppingCriterium();
            ccConf.TargetSelector = new TargetSelector();
            ccConf.PruningMode = InTreeConfig.PRUNING_AUTO;
            confs.Add(treeConfig);

            // Czwarta konfiguracja do meta przebiegu
            treeConfig = machineBase.Project.GetConfiguration("INTREE");
            ccConf = (InTreeConfig)treeConfig.Configuration;
            ccConf.Pruning = new Pruning2();
            ccConf.NodeTestGenerator = new MultiSplitTestGenerator();
            ccConf.NodeTestSelector = new Gini();
            ccConf.StoppingCriterium = new NaturalStoppingCriterium();
            ccConf.TargetSelector = new TargetSelector();
            ccConf.PruningMode = InTreeConfig.PRUNING_AUTO;
            confs.Add(treeConfig);

            // Piąta konfiguracja do meta przebiegu
            treeConfig = machineBase.Project.GetConfiguration("INTREE");
            ccConf = (InTreeConfig)treeConfig.Configuration;
            ccConf.Pruning = new Pruning2();
            ccConf.NodeTestGenerator = new MultiSplitTestGenerator();
            ccConf.NodeTestSelector = new InfoGainNTS(true);
            ccConf.StoppingCriterium = new NodePuritySC(0.8);
            ccConf.TargetSelector = new TargetSelector();
            ccConf.PruningMode = InTreeConfig.PRUNING_NONE;
            confs.Add(treeConfig);

            // Szósta konfiguracja do meta przebiegu
            treeConfig = machineBase.Project.GetConfiguration("INTREE");
            ccConf = (InTreeConfig)treeConfig.Configuration;
            ccConf.Pruning = new Pruning2();
            ccConf.NodeTestGenerator = new BinaryTestGenerator();
            ccConf.NodeTestSelector = new Gini();

            List<IStoppingCriterion> criteriums = new List<IStoppingCriterion>();
            criteriums.Add(new MinNodeSizeSC(6));
            criteriums.Add(new NodePuritySC(0.7));
            ccConf.StoppingCriterium = new CommitteeSC(criteriums, CommitteeSC.OP_AND);

            ccConf.TargetSelector = new TargetSelector();
            ccConf.PruningMode = InTreeConfig.PRUNING_NONE;

            confs.Add(treeConfig);

            #endregion

            int bestConfig = 0;
            double bestRate = 0;
            double[] rating = new double[confs.Count];

            int i = 0;
            foreach (ConfigBase treeConfig1 in confs)
            {
                ccConf = (InTreeConfig)treeConfig1.Configuration;

                Intemi.InputDescription.InputConf binder = InputDescription.InputConf.BindParentInput(2, "Dataset");
                CITools.CV cv = new CITools.CV(treeConfig1, machineBase.Project, binder, 2, 5, 10);
                Capsule cvCaps = machineBase.Submachines.Create(cv.ConfigBase);
                cvCaps.WaitFor();
                Series s = CITools.CV.ResultsTest(cvCaps);

                Console.WriteLine("\nZestaw {0}: {1}", i, s.GetSeries("Mean"));

                rating[i] = (double)s.Items[0]["Mean"];

                double rate = (double)s.Items[0]["Mean"];
                if (rate > bestRate)
                {
                    bestRate = rate;
                    bestConfig = i;
                }
                //Console.WriteLine("Accuracy \n{0}", s.ToStringAllSeries());
                i++;
            }

            //#region Drzewo z ostateczną konfiguracją

            //machineBase.Submachines.WaitAll();

            Console.WriteLine("\n########################################Buduję InTrees z konfiguracją {0}", bestConfig);

            ConfigBase dt2 = machineBase.Project.GetConfiguration("INTREE");
            InTreeConfig dtConfig2 = ((InTreeConfig)dt2.Configuration);

            ccConf = (InTreeConfig)confs[bestConfig].Configuration;
            dtConfig2.NodeTestGenerator = ccConf.NodeTestGenerator;
            dtConfig2.NodeTestSelector = ccConf.NodeTestSelector;
            dtConfig2.StoppingCriterium = ccConf.StoppingCriterium;
            dtConfig2.TargetSelector = ccConf.TargetSelector;
            dtConfig2.Pruning = ccConf.Pruning;
            dtConfig2.PruningConfig = ccConf.PruningConfig;
            dtConfig2.PruningMode = ccConf.PruningMode;

            //ConfigBase dt2 = machineBase.Project.GetConfiguration("INTREE");
            //ConfigBase finalInTree = (ConfigBase)confs[bestConfig];
            dt2.Inputs.BindParentInput("Dataset", "Dataset");

            machineBase.Submachines.RemoveAll();
            machineBase.Submachines.Count = 1;
            machineBase.Submachines.Create(0, dt2);

            machineBase.Submachines.WaitAll();

            // oto ostateczne drzewo
            //this.decisionTree = ((DecisionTree)machineBase.Submachines[0].GetOutput("Decision tree"));

            //Form1 form1 = new Form1(this.decisionTree.Root);
            //form1.ShowDialog();

            //Console.WriteLine(this.decisionTree.Accuracy(dataTable, ref shouldTerminate));

            this.classSubmachine = (IClassifier)machineBase.Submachines[0].GetOutput("Classifier");

            Console.Write("*");
            Console.Write("Meta wybrał:");
            Console.WriteLine(bestConfig);

            //#endregion

        }

    }
}
