"""
input validation
"""
import re
import tkinter as tk
from typing import TYPE_CHECKING

import netaddr
from netaddr import IPNetwork

if TYPE_CHECKING:
    from core.gui.app import Application


class InputValidation:
    def __init__(self, app: "Application"):
        self.master = app.master
        self.positive_int = None
        self.positive_float = None
        self.name = None
        self.ip4 = None
        self.rgb = None
        self.hex = None
        self.register()

    def register(self):
        self.positive_int = self.master.register(self.check_positive_int)
        self.positive_float = self.master.register(self.check_positive_float)
        self.name = self.master.register(self.check_node_name)
        self.ip4 = self.master.register(self.check_ip4)
        self.rgb = self.master.register(self.check_rbg)
        self.hex = self.master.register(self.check_hex)

    def ip_focus_out(self, event: tk.Event):
        value = event.widget.get()
        try:
            IPNetwork(value)
        except netaddr.core.AddrFormatError:
            event.widget.delete(0, tk.END)
            event.widget.insert(tk.END, "invalid")

    def focus_out(self, event: tk.Event, default: str):
        value = event.widget.get()
        if value == "":
            event.widget.insert(tk.END, default)

    def check_positive_int(self, s: str) -> bool:
        if len(s) == 0:
            return True
        try:
            int_value = int(s)
            if int_value >= 0:
                return True
            return False
        except ValueError:
            return False

    def check_positive_float(self, s: str) -> bool:
        if len(s) == 0:
            return True
        try:
            float_value = float(s)
            if float_value >= 0.0:
                return True
            return False
        except ValueError:
            return False

    def check_node_name(self, s: str) -> bool:
        if len(s) < 0:
            return False
        if len(s) == 0:
            return True
        for char in s:
            if not char.isalnum() and char != "_":
                return False
        return True

    def check_canvas_int(self, s: str) -> bool:
        if len(s) == 0:
            return True
        try:
            int_value = int(s)
            if int_value >= 0:
                return True
            return False
        except ValueError:
            return False

    def check_canvas_float(self, s: str) -> bool:
        if not s:
            return True
        try:
            float_value = float(s)
            if float_value >= 0.0:
                return True
            return False
        except ValueError:
            return False

    def check_ip4(self, s: str) -> bool:
        if not s:
            return True
        pat = re.compile("^([0-9]+[.])*[0-9]*$")
        if pat.match(s) is not None:
            _32bits = s.split(".")
            if len(_32bits) > 4:
                return False
            for _8bits in _32bits:
                if (
                    (_8bits and int(_8bits) > 255)
                    or len(_8bits) > 3
                    or (_8bits.startswith("0") and len(_8bits) > 1)
                ):
                    return False
            return True
        else:
            return False

    def check_rbg(self, s: str) -> bool:
        if not s:
            return True
        if s.startswith("0") and len(s) >= 2:
            return False
        try:
            value = int(s)
            if 0 <= value <= 255:
                return True
            else:
                return False
        except ValueError:
            return False

    def check_hex(self, s: str) -> bool:
        if not s:
            return True
        pat = re.compile("^([#]([0-9]|[a-f])+)$|^[#]$")
        if pat.match(s):
            if 0 <= len(s) <= 7:
                return True
            else:
                return False
        else:
            return False