#!/usr/bin/env python3

from tkinter import *
from tkinter import ttk


class FeetToMeter(Tk):
    def __init__(self):
        super().__init__()
        self.title("Feet to Meters")
        self.status = 1  # 1 - neue Eingabe, 2 - Eingabe verarbeitet

        # Event Handler (Validator) registrieren
        self.check_entry_wrapper = self.register(self.check_entry)

        self.create_styles()
        self.create_widgets()
        self.bind_events()


    def create_styles(self):
        """ Erstellen der speziellen Stil-Konfigurationen.

        :return:
        """
        self.s = ttk.Style()
        self.s.configure('aFrame.TFrame', background="yellow")
        self.s.configure('bFrame.TFrame', background="green")
        self.s.configure('cFrame.TFrame', background="red")
        return True

    def create_widgets(self):
        """ Erstellen der Fenster-Bestandteile.

        :return:
        """
        # Rahmen im Hauptfenster (aus ttk für Farbanpassung)
        mainframe = ttk.Frame(self, padding="3 3 12 12")
        mainframe.grid(column=0, row=0, sticky=N+W+S+E)

        # mainframe darf sich ausdehnen.
        self.columnconfigure(0, weight=1)
        self.rowconfigure(0, weight=1)

        # Eingabefeld für Länge in feet
        self.feet = StringVar()
        feet_entry = ttk.Entry(mainframe, width=7, textvariable=self.feet,
                               validatecommand=(self.check_entry_wrapper, '%P'),
                               validate='key')
        feet_entry.grid(column=2, row=1, sticky=W+E)

        # Einheit-Label für Eingabefeld der Länge in feet
        ttk.Label(mainframe, text="feet").grid(column=3, row=1, sticky=W)

        # Label für Ausgabefeld der Länge in Metern
        ttk.Label(mainframe, text="ist äquivalent zu").grid(column=1, row=2, sticky=E)

        # Einheit-Label für Ausgabefeld der Länge in Metern
        ttk.Label(mainframe, text="Meter").grid(column=3, row=2, sticky=W)

        # Ausgabefeld für Länge in Metern
        self.meters = StringVar()
        meters_entry = ttk.Entry(mainframe, width=7, textvariable=self.meters)
        meters_entry.grid(column=2, row=2, sticky=(W, E))
        meters_entry.configure(state='readonly')  # keine Eingabe, aber selektierbar

        # Button für Berechnung

        button_calc = ttk.Button(mainframe, text="Berechne", command=self.calculate)
        button_calc.grid(column=3, row=3, sticky=W)

        # schönere Abstände
        for child in mainframe.winfo_children():
            child.grid_configure(padx=5, pady=5)

        # Statusbar

        self.frame_statusbar = ttk.Frame(self)
        self.frame_statusbar['relief'] = 'sunken'
        self.frame_statusbar['height'] = 12
        self.frame_statusbar['style'] = 'aFrame.TFrame'
        self.frame_statusbar.grid_propagate(0)  # Feste Größe an Grid-Packer weitergeben
        self.frame_statusbar.grid(column=0, row=1, sticky=W+S+E)

        # Setze Fokus in Eingabefeld
        feet_entry.focus()


    def bind_events(self):
        """ Ereignisse an Kommandos binden.

        :return:
        """
        self.bind("<Return>", self.calculate)
        self.bind("<KP_Enter>", self.calculate)


    def switch_status(self, new_status: int = None):
        """ Verändert den globalen Status

        :param new_status: neuer Statuswert
        :return: None
        """
        self.status
        if not new_status:
            if self.status == 1:
                self.status = 2
            else:
                self.status = 1
        else:
            self.status = new_status
        self.update_statusbar()


    def update_statusbar(self):
        """ Passt die Farbe der Statuszeile an den Status an.

        :return: None
        """
        if self.status == 1:
            self.frame_statusbar['style'] = 'aFrame.TFrame'
        elif self.status == 2:
            self.frame_statusbar['style'] = 'bFrame.TFrame'
        else:
            self.frame_statusbar['style'] = 'cFrame.TFrame'


    def calculate(self, *args):
        """ Berechnet aus der eingegebenen Länge in feet die Länge in Metern.

        :param args:
        :return: None
        """
        try:
            stringvalue = self.feet.get()
            stringvalue = stringvalue.replace(",", ".")
            value = float(stringvalue)
            m_value = 0.3048 * value
            m_value = round(m_value, 2)
            self.meters.set(m_value)
            # Berechnung abgeschlossen.
            self.switch_status(2)
        except ValueError:
            pass
        return True


    def check_entry(self, what: str = ""):
        """ Validiert, ob Eingabe leer oder eine Fließkommazahl ist.

        :param what: str eingegebene Zeichenkette
        :return: boolean
        """
        self.switch_status(1)
        if what == "":
            # Nichts eingegeben
            return True
        else:
            try:
                # DEBUG
                print(what)
                what = what.replace(',', '.')
                float(what)
                return True
            except ValueError:
                return False


if __name__ == "__main__":
    app = FeetToMeter()
    app.mainloop()
