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

namespace Intemi.InTrees
{
    public class DTConfig : IConfiguration
    {
        private INodeTestGenerator nodeTestGenerator;
        public INodeTestGenerator NodeTestGenerator
        {
            get { return nodeTestGenerator; }
            set { nodeTestGenerator = value; }
        }

        private INodeTestSelector nodeTestSelector;
        public INodeTestSelector NodeTestSelector
        {
            get { return nodeTestSelector; }
            set { nodeTestSelector = value; }
        }

        private IStoppingCriterion stoppingCriterium;
        public IStoppingCriterion StoppingCriterium
        {
            get { return stoppingCriterium; }
            set { stoppingCriterium = value; }
        }

        private ITargetSelector targetSelector;
        public ITargetSelector TargetSelector
        {
            get { return targetSelector; }
            set { targetSelector = value; }
        }

        private IPruning pruning = null;
        public IPruning Pruning
        {
            get { return pruning; }
            set { pruning = value; }
        }

        private IPruningConfiguration pruningConfig = null;
        public IPruningConfiguration PruningConfig
        {
            get { return pruningConfig; }
            set { pruningConfig = value; }
        }

        private bool usePruning = false;
        public bool UsePruning
        {
            get { return usePruning; }
            set { usePruning = value; }
        }

        public void Configure(ConfigBuilder confBuilder)
        {
            confBuilder.DeclareInput("Train dataset",
                new Type[] { typeof(IDataTable), typeof(ITargets) }, false);
            confBuilder.DeclareOutput("Decision tree","Tree",
                new Type[] { typeof(DecisionTree) });
            confBuilder.DeclareOutput("Output train dataset","DataTable",
                new Type[] { typeof(IDataTable) });
        }
        public object Clone() 
        {
            DTConfig cnf = new DTConfig();
            cnf.NodeTestGenerator = this.NodeTestGenerator;
            cnf.NodeTestSelector = this.NodeTestSelector;
            cnf.Pruning = this.Pruning;
            cnf.PruningConfig = this.PruningConfig;
            cnf.StoppingCriterium = this.StoppingCriterium;
            cnf.TargetSelector = this.TargetSelector;
            cnf.UsePruning = this.UsePruning;
            return cnf; 
        }
    }
    [Machine("DT", typeof(DTConfig))]
    public class DT : IMachine
    {
        IMachineBase MachineBase;
        public void SetMachineBase(IMachineBase mb) 
        { 
            MachineBase = mb; 
        }

        //IFeaturesInfo targetsInfo;
        //public IFeaturesInfo TargetsInfo 
        //{ 
        //    get 
        //    { 
        //        return targetsInfo; 
        //    } 
        //}

        //private Node<DTNode> root;

        private DecisionTree tree;
        public DecisionTree Tree
        {
            get { return tree; }
            //set { tree = value; }
        }

        private IDataTable dataTable;
        public IDataTable DataTable
        {
            get {return dataTable;}
        }

        public void Run(ref bool shouldTerminate)
        {
            dataTable = MachineBase.GetInput("Train dataset") as IDataTable;
            //targetsInfo = (dataTable as ITargets).Targets.FeaturesInfo;

            DTConfig dtConf = MachineBase.ConfBase.Configuration as DTConfig;
            TDIDT3 tdidt = new TDIDT3(dtConf.NodeTestGenerator, 
                dtConf.NodeTestSelector, 
                dtConf.StoppingCriterium, 
                dtConf.TargetSelector, 
                ref shouldTerminate);
            
            this.tree = tdidt.Run(dataTable,ref shouldTerminate);

            if (dtConf.UsePruning)
            {
                if (dtConf.Pruning != null && dtConf.PruningConfig != null)
                {
                    IPruning pruning = dtConf.Pruning;
                    this.tree = pruning.Prune(this.tree,dtConf.PruningConfig, dataTable, ref shouldTerminate);
                }
                else
                {
                    throw new ExceptionIncorectPruningParameters();
                }
            }

            //Console.WriteLine("Tree acc: " + InTree.TreeAccuracy(root, dataTable, ref shouldTerminate));
            //Form1 form1 = new Form1(this.root);
            //form1.ShowDialog();
            
            ////MachineBase.CloseInput("Train dataset");
        }
    }
}
