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

namespace Intemi.InTrees.Implements
{
    /// <summary>
    /// Klasa odpowiedzialna za test znajdujący się w węźle drzewa.
    /// </summary>
    public class NodeTest : INodeTest
    {

        private double testRate;
        public double TestRate
        {
            get { return testRate; }
            set { testRate = value; }
        }

        /// <summary>
        /// Lista reguł używanych w teście węzła
        /// </summary>
        private List<IClassificationRule> nodeRules;
        
        /// <summary>
        /// Konstruktor
        /// </summary>
        public NodeTest()
        {
            nodeRules = new List<IClassificationRule>();
            this.TestRate = 0;
        }

        /// <summary>
        /// Dodaje regułę
        /// </summary>
        /// <param name="rule"></param>
        public void AddRule(IClassificationRule rule)
        {
            nodeRules.Add(rule);
        }

        /// <summary>
        /// Zwraca regułę
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        public IClassificationRule GetRule(int index)
        {
            return nodeRules[index];
        }

        public override string ToString()
        {
            string s = "";
            foreach (IClassificationRule rule in nodeRules)
            {
                s += rule.ToString() + ";";
            }
            return (s);
        }

        public string ToHtml()
        {
            return (ToString());
        }

        public string ToString(int rule)
        {
            return nodeRules[rule].ToString();
        }

        public string ToHtml(int rule)
        {
            return nodeRules[rule].ToHtml();
        }

        /// <summary>
        /// Wskazuje na ile podzbiorów podzieli zbiór danych ten test
        /// </summary>
        /// <returns></returns>
        public int SplitCount()
        {
            return (nodeRules.Count);
        }

        /// <summary>
        /// Wskazuje numer podzbioru do którego należy dany wektor po podziale
        /// </summary>
        /// <param name="data"></param>
        /// <param name="missing"></param>
        /// <param name="fi"></param>
        /// <returns></returns>
        public int SplitData(float[] data, bool[] missing, IFeaturesInfo fi,ref bool shouldTerminate)
        {
            int split = -1;
            IClassificationRule rule;
            for (int i = 0; !shouldTerminate && i < SplitCount(); i++)
            {
                rule = nodeRules[i];
                if (rule.Satisfied(data, missing, fi))
                {
                    split = i;
                    break;
                }
            }

            if (shouldTerminate)
                split = -1;

            return (split);
        }

        /// <summary>
        /// Zwraca podzbiory danych po podziale
        /// </summary>
        /// <param name="dataTable"></param>
        /// <returns></returns>
        public IDataTable[] SplitData(IDataTable dataTable,ref bool shouldTerminate)
        {
            IDataTable[] newData = new IDataTable[this.SplitCount()];
            //int[,] subsets = new int[this.SplitCount(),dataTable.InstanceCount];
            List<int>[] subsets = new List<int>[SplitCount()];

            for (int i = 0; i < SplitCount(); i++)
            {
                subsets[i] = new List<int>();
            }


            IClassificationRule rule;
            IVectorEnumerator ve = (IVectorEnumerator)dataTable.InstanceEnumerator();
            bool[] miss;
            float[] data;

            for (int i = 0; !shouldTerminate && i < dataTable.InstanceCount; i++)
            {
                ve.GoToInstance(i);
                miss = ve.Missing;
                data = ve.Vector;

                for (int j = 0; j < SplitCount(); j++)
                {
                    rule = nodeRules[j];
                    if (rule.Satisfied(data, miss, dataTable.FeaturesInfo)) 
                    {
                        subsets[j].Add(i);
                        break;
                    }
                }
            }

            for (int j = 0; !shouldTerminate && j < this.SplitCount(); j++)
            {
                newData[j] = (IDataTable)dataTable.SelectInstances(subsets[j].ToArray());
            }

            if(shouldTerminate)
                newData = new IDataTable[0];

            return (newData);
        }
    }
}
