import itertools
from Training_list import lista

class Tree(object):
    def __init__(self):
        self.node = []
        for x in range(len(lista)):
            self.node.append(0)
        self.pytania = []
        self.odpowiedzi = []


    def Questions(self, column, number):
        for i in self.myset:
            if lista[i][column] <= number:
                self.node[i] = self.ob1

            else:
                self.node[i] = self.ob2


# sprawdza "czystość" jak często losowo wybrany element będzie źle zindentyfikowany
    def Gini(self, x, suma):
        return 1 - (x[0] / suma) ** 2 - (x[1] / suma) ** 2 - (x[2] / suma) ** 2

    def Algorithm(self):
        open_node = [0] #sprawdza jakie do jakich wierzchółków jeszcze musimy wejść
        closed_node = [] #aby sprawdzic w ktorych już byliśmy
        długość = 0
        while open_node:
            # x to wierzchołek w którym obecnie jesteśmy
            for x in open_node:
                if x in closed_node:
                    break
                self.ob1 = długość + 1
                self.ob2 = długość + 2
                długość += 2
                self.myset = []
                opt = []
                imp = 1

                for i in range(len(self.node)):
                    if self.node[i] == x:
                        self.myset.append(i)
                for y in itertools.product(range(3), range(1, 11)):
                    self.Questions(y[0], y[1])
                    s1 = [0, 0, 0]
                    s2 = [0, 0, 0]
                    for z in range(len(lista)):
                        if self.node[z] == self.ob1:
                            if lista[z][3] == "zły":
                                s1[0] = s1[0] + 1
                            elif lista[z][3] == "neutralny":
                                s1[1] = s1[1] + 1
                            elif lista[z][3] == "dobry":
                                s1[2] = s1[2] + 1
                        elif self.node[z] == self.ob2:
                            if lista[z][3] == "zły":
                                s2[0] = s2[0] + 1
                            elif lista[z][3] == "neutralny":
                                s2[1] = s2[1] + 1
                            elif lista[z][3] == "dobry":
                                s2[2] = s2[2] + 1
                    s1_suma = s1[0] + s1[1] + s1[2]
                    s2_suma = s2[0] + s2[1] + s2[2]
                    if s1_suma > 0 and s2_suma > 0:
                        # szukamy kombinacji z najniższym zanieczyszczeniem
                        impurity = s1_suma / (s1_suma + s2_suma) * self.Gini(s1, s1_suma) + s2_suma / (s1_suma + s2_suma) * self.Gini(s2, s2_suma)
                        if imp > impurity:
                            imp = impurity # imp = najmniejsze imp jakie uzyskalismy
                            opt = y
                            # gini wskazuje na czystosc lewego i prawego wierzcholka
                            l_gini = self.Gini(s1, s1_suma)
                            p_gini = self.Gini(s2, s2_suma)
                            odp_s1 = s1
                            odp_s2 = s2
                self.pytania.append([x, opt, [self.ob1, self.ob2]])
                self.Questions(opt[0], opt[1])

                if l_gini != 0:
                    open_node.append(self.ob1)
                else:

                    for y in range(3):
                        if odp_s1[y] != 0:
                            odp = y
                    self.odpowiedzi.append([self.ob1, odp])
                if p_gini != 0:
                    open_node.append(self.ob2)
                else:
                    for y in range(3):
                        if odp_s2[y] != 0:
                            odp = y
                    self.odpowiedzi.append([self.ob2, odp])
                closed_node.append(x)
            if open_node == closed_node:
                break




    def Answers(self, a, b, pole):
        if pole[a] <= b:
            return self.pytania[self.ind][2][0]
        else:
            return self.pytania[self.ind][2][1]


#na podstawie drzewa podejmuje decyzje ktory ze stanów gleby przydzieli polu
    def Solution(self, pole):
        x = 0
        lista_wierzch_kończących = []
        # generujemy liste wszystkisch wierzch ktore sa w odpowiedzi
        for i in range(len(self.odpowiedzi)):
            lista_wierzch_kończących.append(self.odpowiedzi[i][0])
        while True:
            if x in lista_wierzch_kończących:
                for i in range(len(self.odpowiedzi)):
                    if self.odpowiedzi[i][0] == x:
                        self.ind = i
                        break
                if self.odpowiedzi[self.ind][1] == 0:
                    return("Gleba na polu jest w złym stanie. Wymaga natychmiastowej interwencji")
                elif self.odpowiedzi[self.ind][1] == 1:
                    return("Gleba na polu jest w neutralnym stanie.")
                elif self.odpowiedzi[self.ind][1] == 2:
                    return("Gleba na polu jest w dobrym stanie. Nie będzie wymagać interwencji przez jakiś czas.")
                break
            else:
                for i in range(len(self.pytania)):
                    if self.pytania[i][0] == x:
                        self.ind = i
                        break
                x = self.Answers(self.pytania[self.ind][1][0], self.pytania[self.ind][1][1], pole)