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

namespace Intemi.InTrees.Implements
{
    /// <summary>
    /// Kryterium stopu.
    /// Najbardziej naturalne kryterium stopu. Proces budowy drzewa jest wstrzymywany gdy wystąpi jedna z sytuacji:
    /// 1. Nie ma już dostępnych testów
    /// 2. Został tylko jeden wektor
    /// 3. Wszystkie wektory należą do tej samej klasy
    /// </summary>
    public class NaturalStoppingCriterium : IStoppingCriterion
    {
        public bool Stop(IDataTable dataTable,ref bool shouldTerminate)
        {
            bool stop;

            //  gdy nie ma juz dostepnych testow lub został tylko jeden wektor...
            if (dataTable.InstanceCount <= 1)
            {
                stop = true;
            }
            // lub gdy wszystkie waektory należą do tej samej klasy 
            else if (isSingleTarget(dataTable))
            {
                stop = true; // ...kryterium stopu mówi przerwać
            }
            else
            {
                stop = false;
            }

            if (shouldTerminate)
                stop = true;

            return (stop);
        }

        public bool Stop(IDataTable dataTable, List<INodeTest> nodeTests, ref bool shouldTerminate)
        {
            bool stop;
            if (nodeTests.Count == 0)
            {
                stop = true;
            }
            else
            {
                stop = Stop(dataTable, ref shouldTerminate);
            }
            return (stop);
        }

        private bool isSingleTarget(IDataTable dataTable)
        {
            bool ret = true;
            IOneFeatureData tt = (dataTable as ITargets).Targets;
            int[] counts = tt.FeatureStatistics.counts;
            bool thisIsSecondNonZero = false;
            foreach (int count in counts)
            {
                // znalazl taka etykiete klasy, do ktorej sa przypisane wektory
                if (count != 0)
                {
                    // jezeli to jesy juz druga etykieta ktora ma przypisane jakies wektory,
                    // to znaczy, ze nie wszystkie naleza do jednej i tej samej klasy
                    if (thisIsSecondNonZero)
                    {
                        ret = false;
                        break;
                    }
                    else
                    {
                        // zazanczamy ze jedna z etykiet ma juz przypisane wektory
                        thisIsSecondNonZero = true;
                    }
                }
                // w efekcie dzialanie tej petli jezeli tylko jedna z etykiet ma przypisane jakies wektory zwracane jest true
            }

            return (ret);
        }
    }
}
