#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Tue Dec 10 19:58:52 2019

@author: mputzlocher
"""

import tkinter as tk
from math import floor


#+++++++++++++++++++++++            
# Model
#+++++++++++++++++++++++


grades = list()

average = 0

def calc_average():
    gsum = 0
    cnt = 0
    for g in grades:
        gsum += g
        cnt += 1
    if cnt > 0:
        avg = gsum / cnt
    else:
        avg = 0
    avgout = floor(avg * 100) / 100
    return avgout
    


#+++++++++++++++++++++++            
# Controller
#+++++++++++++++++++++++


class Controller():
    def __init__(self, app):
        self.app = app
        self.vali = Validator(self)

    def update_avg(self):
        a = calc_average()
        app.update_avg(a)
        global average
        average = a
        
    def add_grade(self, event=None):
        try:
            g = self.app.grade.get()
            print(g)
        except:
            print("no value")
            return False
        grades.append(g)
        print(grades)
        self.app.update_entries(grades)
        self.app.update_canvas_histo()
        self.app.update_canvas_circ()
        self.app.update_cnt(len(grades))
        self.update_avg()
        
    def del_last_entry(self, event=None):
        if len(grades) > 0:
            grades.pop()
            self.app.update_entries(grades)
            self.app.update_canvas_histo()
            self.app.update_canvas_circ()
            self.app.update_cnt(len(grades))
            self.update_avg()
        else:
            # Nothing to do
            pass
        
    def save_to_file(self, event=None):
        f = open("mygrades.dat", "w+")
        for g in grades:
            f.write(str(g) + "\n")    
        
        f.write("----------\n")
        f.write(str(average))
        f.close()

#+++++++++++++++++++++++
# Validator
#+++++++++++++++++++++++
class Validator():
    def __init__(self, controller):
        self.con = controller
        
    def validateGrade(self, P):
        print("got {}".format(P))
        if P == "":
            return True
        else:
            pass
        
        try:
            P_num = int(P)
            if P_num <= 6 and P_num >= 1:
                return True
            else:
                print("not in range")
                return False
        except:
            print("no number")
            return False

## +++++++++++++++
# View
## +++++++++++++++

class MainWindow(tk.Frame):
    def __init__(self, master=None):
        super().__init__(master)
        self.master = master
        
        #top=self.winfo_toplevel()
        #top.rowconfigure(0, weight=1)
        #top.columnconfigure(0, weight=1)
        #self.rowconfigure(0, weight=1)
        #self.columnconfigure(0, weight=1)
        
        self.grid(sticky=tk.N+tk.S+tk.E+tk.W)
        #self.configure(width=500, height=500)
        
        self.create_widgets()
        
        self.controller = Controller(self)
        
        self.activate_controller()


    def create_widgets(self):
        self.rowconfigure(0, weight=1)
        
        self.f_input = tk.LabelFrame(self, text="Eingabe")
        self.f_input.grid(row=0, column=0, sticky="nwse")
        
        self.f_input.rowconfigure(0, weight=1)
        self.f_input.columnconfigure(0, weight=1)
        self.f_input.columnconfigure(1, weight=1)
        self.f_input.columnconfigure(2, weight=1)
        
        self.grade = tk.IntVar()
        self.grade.set(1)
        self.e_grade = tk.Entry(self.f_input, width = 3, textvariable=self.grade, bd=2, justify="center", bg="white", fg="blue")
        self.e_grade.grid(row = 0, column = 0, sticky="we")
        self.e_grade.focus()
        self.e_grade.select_range(0,"end")
        
        self.b_grade = tk.Button(self.f_input, text="Eintragen", padx=5, pady=2)
        self.b_grade.grid(row = 0, column = 1, sticky = "e")
        
        self.b_del_last = tk.Button(self.f_input, text="Letzte Löschen", padx=5, pady=2)
        self.b_del_last.grid(row = 0, column = 2, sticky = "e")
        
        self.b_load = tk.Button(self, text="Laden")
        self.b_load.grid(row = 0, column = 2)
        
        #self.ll_entries = tk.Label(self, text="Einträge:")
        #self.ll_entries.grid(row = 1, column = 0)
        
        self.f_entries = tk.LabelFrame(self, text="Einträge")
        self.f_entries.grid(row = 1, column = 0, sticky="nwse")
        
        self.l_entries = tk.Label(self.f_entries, text="")
        self.l_entries.grid(row = 0, column = 0, sticky = "we")
        
        self.f_data = tk.LabelFrame(self, text="Daten")
        self.f_data.grid(row = 2, column = 0, sticky="nwse")
        self.f_data.columnconfigure(0, weight=1)
        self.f_data.columnconfigure(1, weight=1)
        
        self.f_avg = tk.Frame(self.f_data)
        self.f_avg.grid(row=0, column=0)
        self.ll_avg = tk.Label(self.f_avg, text="Durchschnitt:")
        self.ll_avg.grid(row = 0, column = 0)
        self.l_avg = tk.Label(self.f_avg, text="")
        self.l_avg.grid(row = 0, column = 1)
        
        self.f_cnt = tk.Frame(self.f_data)
        self.f_cnt.grid(row=0, column=1)
        self.ll_cnt = tk.Label(self.f_cnt, text="Anzahl:")
        self.ll_cnt.grid(row = 0, column = 0)
        self.l_cnt = tk.Label(self.f_cnt, text="0")
        self.l_cnt.grid(row = 0, column = 1)
        
        self.b_save = tk.Button(self, text="Speichern")
        self.b_save.grid(row = 2, column = 2)
        
        self.f_diagrams = tk.Frame(self)
        self.f_diagrams.grid(row=3, column = 0, sticky="nwse")
        
        self.cv_histo = tk.Canvas(self.f_diagrams, width = 210, height = 140, bg="white")
        self.cv_histo.grid(row=3, column = 0)
        self.fill_canvas_histo()
        
        self.cv_circ = tk.Canvas(self.f_diagrams, width = 125, height = 125, bg = "lightgray")
        self.cv_circ.grid(row=3, column = 1)
        self.fill_canvas_circ()
    
    def fill_canvas_histo(self):
        cv = self.cv_histo
        cv.update_idletasks()
        maxw = cv.winfo_width()
        maxh = cv.winfo_height()
        
        diagh = maxh - 30
        
        w = (maxw-20) // 6 - 4
        border = 10
        dist = 4
        
        #columns = list()
        #columns_counts = list()
        
        for i in range(6):
            left = border + dist + i*(w + dist)
            tag = "c"+str(i+1)
            c = cv.create_rectangle(left, diagh, left +w, diagh, fill="blue", tags=(tag))
            #columns.append(c)
            
            if i>0 and i % 2 == 0:
                cv.create_line(left - 2, maxh, left - 2, diagh, fill="gray", dash="2 1")
            else:
                pass
            
            pos = left + w //2
            tag = "cnt"+str(i+1)
            cl = cv.create_text(pos, diagh-8, text="0", tags=(tag), fill="white", font="sans 8")
            #columns_counts.append(cl)
            
            tag = "pc"+str(i+1)
            cp = cv.create_text(pos, diagh+8, text="0 %", tags=(tag), fill="black", font="sans 8")
            
            if i % 2 == 0:
                pos = left + (2*w + dist)//2
                tag = "pc2step"+str(i+1)
                cp2 = cv.create_text(pos, diagh+20, text="0 %", tags=(tag), fill="black", font="sans 8")
            else:
                pass
    
    def update_canvas_histo(self):
        cv = self.cv_histo
        maxh = cv.winfo_height()
        maxw = cv.winfo_width()
        diagh = maxh - 30
        
        w = (maxw-20) // 6 - 4
        border = 10
        dist = 4
        
        maxcount = 0
        counts = list()
        percentages = list()
        l = len(grades)
        for i in range(6):
            grade = i+1
            cnt = grades.count(grade)
            counts.append(cnt)
            if l > 0:
                p = int(round(cnt/l*100,0))
            else:
                p = 0
            percentages.append(p)
            
            if cnt > maxcount:
                maxcount = cnt
            else:
                pass
            
        if maxcount > 0:
            step = (diagh-10) // maxcount
        else:
            step = 0
        for i in range(6):
            left = border + dist + i*(w + dist)
            tag = "c"+str(i+1)
            height = counts[i] * step
            cv.coords(tag, (left, diagh, left +w, diagh-height))
            
            pos = left + w //2
            tag = "cnt"+str(i+1)
            cv.coords(tag, (pos, diagh-height+6))
            cv.itemconfigure(tag, text=str(counts[i]))
            
            tag = "pc"+str(i+1)
            cv.itemconfigure(tag, text=str(percentages[i]) + " %")
            
            if i % 2 == 0:
                pos = left + (2*w + dist)//2
                tag = "pc2step"+str(i+1)
                if l > 0:
                    p = int(round((counts[i] + counts[i+1])/l*100,0))
                else:
                    p = 0
                cv.itemconfigure(tag, text = str(p) + " %")
            else:
                pass
    
    def fill_canvas_circ(self):
        cv = self.cv_circ
        cv.update_idletasks()
        maxw = cv.winfo_width()
        maxh = cv.winfo_height()
        
        center = [maxw // 2, maxh // 2]
        radius = maxh // 2 - 2
        
        colors = ["#3bd63b", "#30adad", "#ff9a46", "#ff9797", "#ff4646", "#d00404"]
        
        parts = list()
        for i in range(6):
            tag = "p"+str(i+1)
            c = cv.create_arc(center[0]-radius, center[1]-radius, center[0]+radius, center[1]+radius,
                              fill=colors[i], tags=(tag), activewidth=3, activeoutline = "white",
                              start = 0, extent = 0)
            parts.append(c)
    
    def update_canvas_circ(self):
        cv = self.cv_circ
        cv.update_idletasks()
        cnt_all = len(grades)
        counts = list()
        for i in range(6):
            grade = i+1
            cnt = grades.count(grade)
            counts.append(cnt)
        
        if cnt_all > 0:
            angles = [360*cnt / cnt_all for cnt in counts]
        else:
            angles = [0 for cnt in counts]
        startangles = [0]
        partsum = 0
        for i in range(5):
            partsum += angles[i]
            startangles.append(partsum)
        
        for i in range(6):
            tag = "p"+str(i+1)
            startangle = startangles[i]
            extangle = angles[i]
            #print("from {} extent {}".format(startangle, extangle))
            cv.itemconfig(tag, start=startangle, extent= extangle)
            
        cv.update_idletasks()
    
    def update_cnt(self, c):
        self.l_cnt["text"] = str(c)
    
    def update_avg(self, a):
        self.l_avg["text"] = str(a)
        
    def update_entries(self, grades):
        entries_str = grades
        self.l_entries["text"] = entries_str
        self.e_grade.focus()
        self.e_grade.select_range(0,"end")

    def activate_controller(self):
        vcmd = (self.e_grade.register(self.controller.vali.validateGrade), '%P')
        self.e_grade.bind("<Return>", self.controller.add_grade)
        self.e_grade.bind("<KP_Enter>", self.controller.add_grade)
        self.e_grade["validate"]="key"
        self.e_grade["validatecommand"]=vcmd
        self.b_grade["command"] = self.controller.add_grade
        self.b_del_last["command"] = self.controller.del_last_entry
        self.b_save["command"] = self.controller.save_to_file

## +++++++++++++++
# Ausführung
## +++++++++++++++
        
root = tk.Tk()
root.title("Notendurchschnitt")
#root.attributes('-zoomed', True)

app = MainWindow(master=root)
app.mainloop()