#!/usr/bin/python3

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
from gi.repository import GObject
from gi.repository import Gdk
from gi.repository import GLib
from gi.repository import GdkPixbuf

import os
import socket
import fcntl
import struct
import string
import random
import math
import subprocess
from time import sleep, time
import threading

SIMULATE = 0

ETHERNET_PREFIX="end"

# -------------------------------------------------------------------
# -------------------------------------------------------------------
SUBMODULE_PATH = "application/netdata"
DEMO_PATH = "/usr/local/demo"
# -------------------------------------------------------------------
# -------------------------------------------------------------------

WIFI_LINUX_INTERFACE_NAME = "wlan0"
WIFI_HOTSPOT_IP="192.168.72.1"

WIFI_DEFAULT_SSID="STDemoNetwork"
WIFI_DEFAULT_PASSWD="stm32mp1"

if SIMULATE > 0:
    WIFI_LINUX_INTERFACE_NAME = "wlp8s0"

# -------------------------------------------------------------------
# -------------------------------------------------------------------
ICON_SIZE_1080 = 260
ICON_SIZE_720 = 160
ICON_SIZE_480 = 160
ICON_SIZE_272 = 48

# return format:
# [ icon_size, font_size ]
SIZES_ID_ICON_SIZE = 0
SIZES_ID_FONT_SIZE = 1
def get_sizes_from_screen_size(width, height):
    minsize =  min(width, height)
    icon_size = None
    font_size = None
    if minsize == 720:
        icon_size = ICON_SIZE_720
        font_size = 25
    elif minsize == 480:
        icon_size = ICON_SIZE_480
        font_size = 20
    elif minsize == 272:
        icon_size = ICON_SIZE_272
        font_size = 10
    elif minsize == 600:
        icon_size = ICON_SIZE_720
        font_size = 15
    elif minsize >= 1080:
        icon_size = ICON_SIZE_1080
        font_size = 32
    return [icon_size, font_size]

def get_icon_size_from_screen_size(width, height):
    minsize =  min(width, height)
    if minsize == 720:
        return ICON_SIZE_720
    elif minsize == 480:
        return ICON_SIZE_480
    elif minsize == 272:
        return ICON_SIZE_272
    elif minsize == 600:
        return ICON_SIZE_1080
    elif minsize >= 1080:
        return ICON_SIZE_1080

# -------------------------------------------------------------------
# -------------------------------------------------------------------
# Get the wlan interface name
def get_wlan_interface_name():
    cmd = ["%s/application/netdata/bin/get_wlan_name.sh" % DEMO_PATH]
    proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    res = proc.stdout.read().decode('utf-8')
    return res
# -------------------------------------------------------------------
# -------------------------------------------------------------------
# Get the wlan interface state ([UP, DOWN])
def get_wlan_interface_state():
    cmd = ["%s/application/netdata/bin/get_wlan_state.sh" % DEMO_PATH]
    proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    res = proc.stdout.read().decode('utf-8')
    return res

# -------------------------------------------------------------------
# -------------------------------------------------------------------
# Get list of ip address
def get_ip_address_list():
    cmd = ["%s/application/netdata/bin/get_ethernet_ip.sh" % DEMO_PATH]
    proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    res = proc.stdout.read().decode('utf-8')
    return res

# -------------------------------------------------------------------
# -------------------------------------------------------------------
# Get the ip address of board
def get_ip_address(ifname):
    ip = "NA"
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        ip = socket.inet_ntoa(fcntl.ioctl(
            s.fileno(),
            0x8915,  # SIOCGIFADDR
            struct.pack('256s', bytes(ifname[:15], 'utf-8'))
        )[20:24])
    except socket.error:
        pass
    return ip
# -------------------------------------------------------------------
# -------------------------------------------------------------------
def _load_image_wlan_eventBox(parent, filename, label_text1, label_text2, scale_w, scale_h):
    # Create box for xpm and label
    box = Gtk.VBox(homogeneous=False, spacing=0)
    # Create an eventBox
    eventBox = Gtk.EventBox()
    # Now on to the image stuff
    pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale(
            filename=filename,
            width=scale_w,
            height=scale_h,
            preserve_aspect_ratio=True)
    image = Gtk.Image.new_from_pixbuf(pixbuf)

    label = Gtk.Label()
    label.set_markup("<span font='10' color='#FFFFFFFF'>%s\n</span>"
                     "<span font='10' color='#FFFFFFFF'>%s</span>" % (label_text1, label_text2))
    #label.set_justify(Gtk.Justification.LEFT)
    label.set_line_wrap(True)

    # Pack the pixmap and label into the box
    box.pack_start(image, True, False, 0)
    box.pack_start(label, True, False, 0)

    # Add the image to the eventBox
    eventBox.add(box)

    return eventBox

# -------------------------------------------------------------------
# -------------------------------------------------------------------
def id_generator(size=6, chars=string.ascii_lowercase + string.digits):
    return "".join(random.choice(chars) for _ in range(size))
# -------------------------------------------------------------------
# -------------------------------------------------------------------

class NetdataWebserver(Gtk.Dialog):
    def __init__(self, parent, log=0):
        Gtk.Dialog.__init__(self, "Wifi", parent, 0)
        self.log = log

        if SIMULATE > 0:
            self.screen_width = 800
            self.screen_height = 480
            self.set_default_size(self.screen_width, self.screen_height)
        else:
            self.maximize()
            try:
                display = Gdk.Display.get_default()
                monitor = display.get_primary_monitor()
                geometry = monitor.get_geometry()
                scale_factor = monitor.get_scale_factor()
                self.screen_width = scale_factor * geometry.width
                self.screen_height = scale_factor * geometry.height
            except:
                self.screen_width = self.get_screen().get_width()
                self.screen_height = self.get_screen().get_height()

        self.icon_size = get_icon_size_from_screen_size(self.screen_width, self.screen_height)
        sizes = get_sizes_from_screen_size(self.screen_width, self.screen_height)
        self.font_size = sizes[SIZES_ID_FONT_SIZE]

        self.set_decorated(False)
        rgba = Gdk.RGBA(0.31, 0.32, 0.31, 0.8)
        self.override_background_color(0,rgba)

        mainvbox = self.get_content_area()

        self.page_ip = Gtk.VBox(homogeneous=False, spacing=0)
        self.page_ip.set_border_width(10)
        self.set_border_width(10)

        self.title = Gtk.Label()
        self.title.set_markup("<span font='%d' color='#FFFFFFFF'><b>Access information to netdata</b></span>" % (self.font_size+5))
        self.page_ip.add(self.title)
        self.label_eth = Gtk.Label()
        self.label_eth.set_markup("<span font='%d' color='#FFFFFFFF'>netdata over Ethernet:</span>" % self.font_size)
        self.label_eth.set_xalign (0.0)
        self.label_ip_ethernet = Gtk.Label()
        #self.label_ip_ethernet.set_xalign (0.0)
        self.label_wifi = Gtk.Label()
        self.label_wifi.set_markup("<span font='%d' color='#FFFFFFFF'>netdata over Wifi:</span>" % self.font_size)
        self.label_wifi.set_xalign (0.0)
        self.label_ip_wlan0 = Gtk.Label()
        #self.label_ip_wlan0.set_xalign (0.0)
        self.label_hotspot = Gtk.Label()
        self.label_hotspot.set_xalign (0.0)

        self.previous_click_time=0
        self.wifi_ssid=WIFI_DEFAULT_SSID
        self.wifi_passwd=WIFI_DEFAULT_PASSWD

        self.info_grid = Gtk.Grid()
        self.info_grid.set_column_spacing(2)
        self.info_grid.set_row_spacing(2)

        self.info_grid.attach(self.label_eth, 0, 1, 1, 1)
        self.info_grid.attach(self.label_ip_ethernet, 1, 1, 1, 1)

        if self.is_wifi_available():
            self.print_debug(1, "wlan0 is available")
            self.hotspot_switch = Gtk.Switch()

            # set wlan switch state on first execution
            ip_wlan0 = get_ip_address(get_wlan_interface_name())
            state_wlan0 = get_wlan_interface_state()
            if state_wlan0 == "UP":
                self.hotspot_switch.set_active(True)
            else:
                self.hotspot_switch.set_active(False)

            self.hotspot_switch.connect("notify::active", self.on_switch_activated)
            self.info_grid.attach(self.label_wifi, 0, 2, 1, 1)
            self.info_grid.attach(self.hotspot_switch, 0, 3, 1, 1)
            self.info_grid.attach(self.label_hotspot, 1, 3, 1, 1)

        else:
            self.print_debug(1, "wlan0 interface not available")
            self.info_grid.attach(self.label_hotspot, 0, 3, 1, 1)

        self.page_ip.add(self.info_grid)
        self.refresh_network_page()
        self.connect("button-release-event", self.on_page_press_event)

        mainvbox.pack_start(self.page_ip, False, True, 3)
        self.show_all()

    def is_wifi_available(self):
        interface_name = get_wlan_interface_name()
        if len(interface_name) > 0:
            return True
        return False

    def get_wifi_config(self):
        filepath = "/etc/default/hostapd"
        if os.path.isfile(filepath):
            file = open(filepath, "r")
            i=0
            for line in file:
                if "HOSTAPD_SSID" in line:
                    self.wifi_ssid = (line.split('=')[1]).rstrip('\r\n')
                    i+=1
                if "HOSTAPD_PASSWD" in line:
                    self.wifi_passwd=(line.split('=')[1]).rstrip('\r\n')
                    i+=1
            file.close()
            if (i==2):
                self.print_debug(3, "[Wifi: use hostapd configuration: ssid=%s, passwd=%s]\n" %(self.wifi_ssid, self.wifi_passwd))
            else:
                self.wifi_ssid=WIFI_DEFAULT_SSID
                self.wifi_passwd=WIFI_DEFAULT_PASSWD
                self.print_debug(3, "[Wifi: use default configuration: ssid=%s, passwd=%s]\n" %(self.wifi_ssid, self.wifi_passwd))
        else:
            self.print_debug(3, "[Wifi: use default configuration: ssid=%s, passwd=%s]\n" %(self.wifi_ssid, self.wifi_passwd))

    def set_random_wifi_config(self):
        self.wifi_ssid="ST-" + id_generator()
        #self.wifi_passwd=id_generator(6, string.ascii_lowercase)
        self.set_wifi_config(self.wifi_ssid, self.wifi_passwd)

    def set_wifi_config(self, ssid, password):
        filepath = "/tmp/hostapd"
        file = open(filepath, "w")
        self.print_debug(3, "[Wifi: set hostapd config: ssid=%s, passwd=%s]" %(ssid, password))
        file.write('HOSTAPD_SSID=%s\nHOSTAPD_PASSWD=%s\n' %(ssid, password))
        file.close()
        os.system('su -c \"cp /tmp/hostapd /etc/default/hostapd\"')


    def refresh_network_page(self):
        self.print_debug(3, "[Refresh network page]\n")

        ip_list=get_ip_address_list().split()
        if len(ip_list) > 0:
            ip_ethernet = ip_list[0]
            ethernet_status = "<span font='%d' color='#FFFFFFFF'>  %s</span>" % (self.font_size, ip_ethernet)
        else:
            ip_ethernet = get_ip_address('{}0'.format(ETHERNET_PREFIX))
            if ip_ethernet == "NA":
                ip_ethernet = get_ip_address('{}1'.format(ETHERNET_PREFIX))
            if ip_ethernet != "NA":
                ethernet_status = "<span font='%d' color='#FFFFFFFF'>  http://%s:19999</span>" % (self.font_size, ip_ethernet)
            else:
                ethernet_status = "<span font='%d' color='#FF0000FF'>  No Ethernet connection</span>"  % self.font_size
        self.label_ip_ethernet.set_markup(ethernet_status)

        if self.is_wifi_available():
            self.print_debug(1, "wlan0 is available")
            ip_wlan0 = get_ip_address(get_wlan_interface_name())
            state_wlan0 = get_wlan_interface_state()

            self.print_debug(1, "Ip address of Wlan0 are: {} {}<".format(ip_wlan0, state_wlan0))
            if state_wlan0 == "UP" and ip_wlan0 == "NA":
                sleep(1)
                ip_wlan0 = get_ip_address(get_wlan_interface_name())
                state_wlan0 = get_wlan_interface_state()
                self.print_debug(1, "Ip address of Wlan0 are(2): ", ip_wlan0, state_wlan0)
            if state_wlan0 == "DOWN" or ip_wlan0 == "NA":
                hotspot_status = "<span font='%d' color='#FF0000FF'>  Wifi not started</span>" % self.font_size
                self.info_grid.remove_row(6)
            elif ip_wlan0 == WIFI_HOTSPOT_IP:
                self.get_wifi_config()
                hotspot_status = "<span font='%d' color='#00AA00FF'>  Wifi hotspot started</span>" % self.font_size

                wifi_qrcode_cmd = "WIFI:S:%s;T:WPA;P:%s;;" %(self.wifi_ssid, self.wifi_passwd)
                self.print_debug(3, "%s/bin/build_qrcode.sh {} -o /tmp/qr-code_wifi_access.png {} .".format(os.path.join(DEMO_PATH,SUBMODULE_PATH), wifi_qrcode_cmd))
                cmd = ["%s/bin/build_qrcode.sh" % os.path.join(DEMO_PATH,SUBMODULE_PATH), "-o /tmp/qr-code_wifi_access.png", wifi_qrcode_cmd]
                proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
                result = proc.stdout.read().decode('utf-8')

                url_qrcode_cmd = "http://%s:19999" % ip_wlan0
                cmd2 = ["%s/bin/build_qrcode.sh" % os.path.join(DEMO_PATH,SUBMODULE_PATH), "-o /tmp/qr-code_netdata_url.png", url_qrcode_cmd]
                proc = subprocess.Popen(cmd2, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
                result = proc.stdout.read().decode('utf-8')

                self.wifi_credential = _load_image_wlan_eventBox(self, "/tmp/qr-code_wifi_access.png", "ssid: %s" % self.wifi_ssid, "passwd: %s" % self.wifi_passwd, -1, self.icon_size)
                self.netdata_url = _load_image_wlan_eventBox(self, "/tmp/qr-code_netdata_url.png", "url: http://%s:19999" % ip_wlan0, "", -1, self.icon_size)
                self.info_grid.attach(self.wifi_credential, 0, 6, 1, 1)
                self.info_grid.attach(self.netdata_url, 1, 6, 1, 1)

                self.show_all()
            else:
                hotspot_status = "<span font='%d' color='#FF0000FF'>Wifi started but not configured as hotspot</span>" % self.font_size
                self.info_grid.remove_row(6)

                self.label_ip_wlan0.set_markup("<span font='%d' color='#FFFFFFFF'>NetData over Wifi: http://%s:19999</span>" % (self.font_size, ip_wlan0))
                self.info_grid.attach(self.label_ip_wlan0, 0, 6, 2, 1)
                self.show_all()
        else:
            self.print_debug(1, "wlan0 interface not available")
            hotspot_status = "<span font='%d' color='#FF0000FF'>  Wifi not available on board</span>" % self.font_size

        self.label_hotspot.set_markup(hotspot_status)

    def on_page_press_event(self, widget, event):
        self.click_time = time()
        #print(self.click_time - self.previous_click_time)
        # TODO : a fake click is observed, workaround hereafter
        if (self.click_time - self.previous_click_time) < 0.01:
            self.previous_click_time = self.click_time
        elif (self.click_time - self.previous_click_time) < 0.3:
            self.print_debug(3, "double click : exit")
            self.destroy()
        else:
            #print ("simple click")
            self.previous_click_time = self.click_time

    def on_switch_activated(self, switch, gparam):
        if switch.get_active():
            self.set_random_wifi_config()
            self.wifi_hotspot_start()
        else:
            self.wifi_hotspot_stop()
        self.refresh_network_page()

    def wifi_hotspot_start(self):
        self.print_debug(3, '[DEBUG]: %s/application/netdata/bin/wifi_start.sh' % DEMO_PATH)
        os.system('%s/application/netdata/bin/wifi_start.sh' % DEMO_PATH)


    def wifi_hotspot_stop(self):
        self.print_debug(3, '[DEBUG]:%s/application/netdata/bin/wifi_stop.sh\"' % DEMO_PATH)
        os.system('%s/application/netdata/bin/wifi_stop.sh' % DEMO_PATH)

    def print_debug(self, level, msg):
        if level <= self.log:
            print("[NETDATA DEBUG] {}".format(str(msg)))

def create_subdialogwindow(parent, log=0):
    _window = NetdataWebserver(parent, log=log)
    _window.show_all()
    response = _window.run()
    _window.destroy()


# -------------------------------------------------
# -------------------------------------------------
#               test submodule
class TestUIWindow(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self, title="Test Launcher")
        create_subdialogwindow(self)
        self.show_all()

if __name__ == "__main__":
    win = TestUIWindow()
    win.connect("delete-event", Gtk.main_quit)
    win.show_all()
