# Signaturassistent
# Version 1.4
# Datei: mainframe.py

import wx

from PIL import Image

from processor import SignatureProcessor


class RotationDialog(wx.Dialog):
    """
    Fragt nach der Drehrichtung, wenn der Ausschnitt
    höher als breit ist. Eigener Dialog statt
    wx.SingleChoiceDialog, damit die Buttons sicher
    "OK" und "Abbrechen" heißen (die Standard-
    dialoge zeigen je nach System englische Labels).
    """

    def __init__(self, parent, choices):
        super().__init__(
            parent,
            title="Ausschnitt drehen"
        )

        text = wx.StaticText(
            self,
            label="Der Ausschnitt ist höher als breit. "
                  "Vermutlich lag das Blatt quer. "
                  "Wie soll das Ergebnis gedreht werden?"
        )

        self.listbox = wx.ListBox(
            self,
            choices=choices
        )

        self.listbox.SetSelection(0)

        ok_button = wx.Button(
            self,
            wx.ID_OK,
            "&OK"
        )

        cancel_button = wx.Button(
            self,
            wx.ID_CANCEL,
            "&Abbrechen"
        )

        ok_button.SetDefault()

        button_sizer = wx.BoxSizer(wx.HORIZONTAL)

        button_sizer.Add(ok_button, 0, wx.RIGHT, 8)
        button_sizer.Add(cancel_button, 0)

        sizer = wx.BoxSizer(wx.VERTICAL)

        sizer.Add(text, 0, wx.ALL, 12)

        sizer.Add(
            self.listbox,
            1,
            wx.LEFT | wx.RIGHT | wx.EXPAND,
            12
        )

        sizer.Add(
            button_sizer,
            0,
            wx.ALL | wx.ALIGN_RIGHT,
            12
        )

        self.SetSizerAndFit(sizer)

        self.Centre()

        self.listbox.SetFocus()

        # Enter in der Liste bestätigt direkt
        self.listbox.Bind(
            wx.EVT_LISTBOX_DCLICK,
            lambda event: self.EndModal(wx.ID_OK)
        )

    def GetSelection(self):
        return self.listbox.GetSelection()


class MainFrame(wx.Frame):

    def __init__(self):
        super().__init__(
            None,
            title="Signaturassistent 1.4",
            size=(550, 320)
        )

        self.processor = SignatureProcessor()
        self.result_image = None

        self._create_gui()
        self._create_accelerators()

        self.Centre()
        self.open_button.SetFocus()

    def _create_gui(self):

        panel = wx.Panel(self)

        self.open_button = wx.Button(
            panel,
            label="Bild öffnen... (Strg+O)"
        )

        self.save_button = wx.Button(
            panel,
            label="PNG speichern... (Strg+S)"
        )

        self.save_button.Disable()

        self.log_ctrl = wx.TextCtrl(
            panel,
            style=wx.TE_MULTILINE |
                  wx.TE_READONLY
        )

        sizer = wx.BoxSizer(wx.VERTICAL)

        sizer.Add(
            self.open_button,
            0,
            wx.ALL | wx.EXPAND,
            8
        )

        sizer.Add(
            self.save_button,
            0,
            wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND,
            8
        )

        sizer.Add(
            self.log_ctrl,
            1,
            wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND,
            8
        )

        panel.SetSizer(sizer)

        self.open_button.Bind(wx.EVT_BUTTON, self.on_open)
        self.save_button.Bind(wx.EVT_BUTTON, self.on_save)

        self.log("Bereit.")

    def _create_accelerators(self):

        table = wx.AcceleratorTable([
            (wx.ACCEL_CTRL, ord("O"), wx.ID_OPEN),
            (wx.ACCEL_CTRL, ord("S"), wx.ID_SAVE)
        ])

        self.SetAcceleratorTable(table)

        self.Bind(wx.EVT_MENU, self.on_open, id=wx.ID_OPEN)
        self.Bind(wx.EVT_MENU, self.on_save, id=wx.ID_SAVE)

    def log(self, text):
        self.log_ctrl.AppendText(text + "\n")

    def on_open(self, event):

        wildcard = (
            "Alle Dateien (*.*)|*.*|"
            "Bilddateien (*.png;*.jpg;*.jpeg;*.bmp)|*.png;*.jpg;*.jpeg;*.bmp|"
            "PNG (*.png)|*.png|"
            "JPEG (*.jpg;*.jpeg)|*.jpg;*.jpeg|"
            "Bitmap (*.bmp)|*.bmp"
        )

        with wx.FileDialog(
            self,
            "Scan auswählen",
            wildcard=wildcard,
            style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST
        ) as dlg:

            if dlg.ShowModal() != wx.ID_OK:
                return

            filename = dlg.GetPath()

        self.log(f"Öffne: {filename}")

        try:

            self.result_image = self.processor.process(filename)

            if self.result_image is None:

                self.save_button.Disable()

                wx.MessageBox(
                    "Keine Signatur gefunden.",
                    "Hinweis",
                    wx.OK | wx.ICON_INFORMATION
                )

                self.log("Keine Signatur erkannt.")
                return

            self.result_image = self._check_orientation(
                self.result_image
            )

            self.save_button.Enable()
            self.save_button.SetFocus()

            self.log("Signatur erkannt.")

        except Exception as e:

            self.save_button.Disable()

            wx.MessageBox(
                str(e),
                "Fehler",
                wx.OK | wx.ICON_ERROR
            )

            self.log(str(e))

    def _check_orientation(self, image):
        """
        Ist der Ausschnitt höher als breit, lag das
        Blatt bei der Aufnahme vermutlich quer. Die
        Software kann die Drehrichtung nicht wissen,
        der Nutzer aber schon: Er weiß, wie das Blatt
        im Scanner bzw. in der Scanhilfe lag.
        """

        width, height = image.size

        if height <= width:
            return image

        choices = [
            "90 Grad im Uhrzeigersinn "
            "(Blatt lag mit dem Kopf nach links)",
            "90 Grad gegen den Uhrzeigersinn "
            "(Blatt lag mit dem Kopf nach rechts)",
            "180 Grad",
            "Nicht drehen"
        ]

        with RotationDialog(self, choices) as dlg:

            if dlg.ShowModal() != wx.ID_OK:
                return image

            selection = dlg.GetSelection()

        if selection == 0:
            image = image.transpose(
                Image.Transpose.ROTATE_270
            )
            self.log("Um 90 Grad im Uhrzeigersinn gedreht.")

        elif selection == 1:
            image = image.transpose(
                Image.Transpose.ROTATE_90
            )
            self.log("Um 90 Grad gegen den Uhrzeigersinn gedreht.")

        elif selection == 2:
            image = image.transpose(
                Image.Transpose.ROTATE_180
            )
            self.log("Um 180 Grad gedreht.")

        return image

    def on_save(self, event):

        if self.result_image is None:
            return

        with wx.FileDialog(
            self,
            "PNG speichern",
            wildcard="PNG (*.png)|*.png",
            style=wx.FD_SAVE |
                  wx.FD_OVERWRITE_PROMPT
        ) as dlg:

            if dlg.ShowModal() != wx.ID_OK:
                return

            filename = dlg.GetPath()

        try:

            self.processor.save_png(
                self.result_image,
                filename
            )

            self.log("PNG gespeichert.")

            self.open_button.SetFocus()

        except Exception as e:

            wx.MessageBox(
                str(e),
                "Fehler",
                wx.OK | wx.ICON_ERROR
            )

            self.log(str(e))
