#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Mon Nov 18 12:04:53 2024

@author: angoosh

references:
https://pygobject.gnome.org/tutorials/gtk4/introduction.html
https://docs.gtk.org/gtk3/index.html#classes
"""
import sys
import os
import gi
import subprocess
import json
from cryptography.fernet import Fernet
gi.require_version('Gtk', '4.0')
gi.require_version('Adw', '1')
from gi.repository import Gtk, Adw, Gdk, Gio
import keyring

APPID = "com.angoosh.RDPConnect"
HOMEDIR = os.path.expanduser('~')

VERSION = "1.3.0"

conn_info = {}
hist_info = {}
settings = {}
settings["extra_params"] = {}
fernet = ""

def load_keys():
    global fernet
    cryptoKey = ""
    try:
        with open(HOMEDIR+"/.config/rdpconnect/.key", "r") as keyfile:
            cryptoKey = str.encode(keyfile.readline())
            print("Encription key loaded")
    except:
        cryptoKey = Fernet.generate_key()
        with open(HOMEDIR+"/.config/rdpconnect/.key", "w") as keyfile:
            keyfile.write(cryptoKey.decode("utf-8"))
            print("Encription key generated")

    fernet = Fernet(cryptoKey)

def load_config():
    global conn_info, settings
    loaded_json = ""
    try:
        with open(HOMEDIR+"/.config/rdpconnect/history.json", "r") as history_file:
            for line in history_file:
                loaded_json += line

            hist_info = json.loads(loaded_json)
            last_conn = hist_info[max(hist_info)]
            conn_info["user"] = last_conn.split('@')[0]
            conn_info["ip"] = last_conn.split('@')[1]
            conn_info["passwd"] = keyring.get_password("com.angoosh.RDPConnect", last_conn)

    except:
        try:
            with open(HOMEDIR+"/.config/rdpconnect/connection.json", "r") as connection_file:
                for line in connection_file:
                    loaded_json += line

                conn_info = json.loads(loaded_json)

                conn_info["passwd"] = fernet.decrypt(str.encode(conn_info["passwd"])).decode()
        except:
            print("[WARN] FILE: "+HOMEDIR+"/.config/rdpconnect/connection.json doesn't exist")

    loaded_json = ""
    try:
        with open(HOMEDIR+"/.config/rdpconnect/settings.json", "r") as settings_file:
            for line in settings_file:
                loaded_json += line

            settings = json.loads(loaded_json)
    except:
        print("[WARN] FILE: "+HOMEDIR+"/.config/rdpconnect/settings.json doesn't exist")

class HistoryWindow(Gtk.Window):
    def __init__(self, **kargs):
        super().__init__(**kargs, title='History')

        self.set_default_size(100, 300)

        self.scroll = Gtk.ScrolledWindow()
        self.scroll.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)

        self.grid = Gtk.Grid()

        self.scroll.set_child(self.grid)

        index = 0
        for i in hist_info:
            self.addRow(hist_info[i], index)
            index += 1

        self.set_child(self.scroll)

    def addRow(self, entry, index):
        runb = Gtk.Button(label=entry)
        runb.connect("clicked", self.apply_contents)

        self.grid.attach(runb, 0, index, 1, 1)

    def apply_contents(self, button):
        conn_info["user"] = button.get_label().split('@')[0]
        conn_info["ip"] = button.get_label().split('@')[1]
        try:
            conn_info["passwd"] = keyring.get_password("com.angoosh.RDPConnect", button.get_label())
        except:
            pass

class PreferencesWindow(Gtk.Window):
    global settings
    def __init__(self, **kwargs):
        super().__init__(**kwargs)

        self.builder = Gtk.Builder(self)
        self.builder.add_from_file("/app/preferences.ui")

        self.resx = self.builder.get_object("resx")
        self.resy = self.builder.get_object("resy")
        self.monitors = self.builder.get_object("monitors")
        self.fullscreen = self.builder.get_object("fullscreen")
        self.xfree = self.builder.get_object("xfree")
        self.sound = self.builder.get_object("sound")
        self.mic = self.builder.get_object("mic")
        self.dynres = self.builder.get_object("dynres")
        self.clipboard = self.builder.get_object("clipboard")

        try:
            self.clipboard.set_state(settings["extra_params"]["clipboard"])
            self.clipboard.set_active(settings["extra_params"]["clipboard"])
        except:
            pass
        try:
            self.dynres.set_state(settings["extra_params"]["dynamic-resolution"])
            self.dynres.set_active(settings["extra_params"]["dynamic-resolution"])
        except:
            pass
        try:
            self.mic.set_state(settings["extra_params"]["microphone"])
            self.mic.set_active(settings["extra_params"]["microphone"])
        except:
            pass
        try:
            self.sound.set_state(settings["extra_params"]["sound"])
            self.sound.set_active(settings["extra_params"]["sound"])
        except:
            pass
        try:
            if settings["rdp_bin"] == "xfreerdp":
                self.xfree.set_state(True)
                self.xfree.set_active(True)
        except:
            pass
        try:
            self.fullscreen.set_state(settings["extra_params"]["f"])
            self.fullscreen.set_active(settings["extra_params"]["f"])
        except:
            pass
        try:
            self.monitors.get_buffer().set_text(str(settings["extra_params"]["monitors"]), len(settings["extra_params"]["monitors"]))
        except:
            pass
        try:
            self.resx.get_buffer().set_text(str(settings["extra_params"]["w"]), len(settings["extra_params"]["w"]))
        except:
            pass
        try:
            self.resy.get_buffer().set_text(str(settings["extra_params"]["h"]), len(settings["extra_params"]["h"]))
        except:
            pass

        pref_window = self.builder.get_object("pref_window")
        pref_window.show()

    def f_resx(self, app):
        settings["extra_params"]["w"] = self.resx.get_buffer().get_text()

    def f_resy(self, app):
        settings["extra_params"]["h"] = self.resy.get_buffer().get_text()

    def monconf(self, app):
        settings["extra_params"]["monitors"] = self.monitors.get_buffer().get_text()

    def clipboard(self, app, state):
        if state:
            settings["extra_params"]["clipboard"] = True
        else:
            settings["extra_params"]["clipboard"] = False

    def dynres(self, app, state):
        if state:
            settings["extra_params"]["dynamic-resolution"] = True
        else:
            settings["extra_params"]["dynamic-resolution"] = False

    def microphone(self, app, state):
        if state:
            settings["extra_params"]["microphone"] = True
        else:
            settings["extra_params"]["microphone"] = False

    def sound(self, app, state):
        if state:
            settings["extra_params"]["sound"] = True
        else:
            settings["extra_params"]["sound"] = False

    def xfree(self, app, state):
        if state:
            settings["rdp_bin"] = "xfreerdp"
        else:
            settings["rdp_bin"] = "sdl-freerdp"

    def fscr(self, app, state):
        if state:
            settings["extra_params"]["f"] = True
        else:
            settings["extra_params"]["f"] = False

    def on_destroy(self, app):
        print("Saving settings config to "+HOMEDIR+"/.config/rdpconnect/settings.json")
        with open(HOMEDIR+"/.config/rdpconnect/settings.json", "w") as settings_file:
            js = json.dumps(settings, sort_keys=True, indent=4, separators=(',', ': '))
            settings_file.write(js)


class MyApp(Adw.Application):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.connect('activate', self.on_activate)

    def on_activate(self, app):
        builder = Gtk.Builder()
        builder.add_from_file("/app/"+APPID+".ui")
        buildermenu = Gtk.Builder()
        buildermenu.add_from_file("/app/menu.ui")
        menu_model = buildermenu.get_object('app-menu')

        css_provider = Gtk.CssProvider()
        if Adw.StyleManager().get_default().get_dark():
            css_provider.load_from_file(Gio.File.new_for_path("/app/style-dark.css"))
        else:
            css_provider.load_from_file(Gio.File.new_for_path("/app/style-light.css"))
        Gtk.StyleContext.add_provider_for_display(Gdk.Display.get_default(), css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)

        connect = builder.get_object("connect")
        connect.connect("clicked", self.connectRDP)

        self.ip = builder.get_object("ip")
        self.user = builder.get_object("user")
        self.passwd = builder.get_object("pass")

        self.save_conf = builder.get_object("save_conf")

        try:
            if settings["save_conn"]:
                self.ip.get_buffer().set_text(str(conn_info["ip"]), len(conn_info["ip"]))
                self.user.get_buffer().set_text(str(conn_info["user"]), len(conn_info["user"]))
                self.passwd.get_buffer().set_text(str(conn_info["passwd"]), len(conn_info["passwd"]))

                self.save_conf.set_active(True)
        except:
            pass

#menu config
        self.win = builder.get_object("main_window")
        header_bar = Gtk.HeaderBar()
        self.win.set_titlebar(header_bar)

        menubutton = Gtk.MenuButton(menu_model=menu_model, icon_name='open-menu-symbolic')
        header_bar.pack_end(menubutton)

        self.win.set_application(self)
        self.win.present()

    def do_startup(self):
        Gtk.Application.do_startup(self)

        action = Gio.SimpleAction(name='preferences')
        action.connect('activate', self.on_preferences)
        self.add_action(action)

        action = Gio.SimpleAction(name='about')
        action.connect('activate', self.on_about)
        self.add_action(action)

        #action = Gio.SimpleAction(name='history')
        #action.connect('activate', self.on_history)
        #self.add_action(action)

    def on_about(self, action, param):
        about_dialog = Gtk.AboutDialog(transient_for=self.win, modal=True)
        about_dialog.set_copyright("Antonin Kaplan")
        about_dialog.set_program_name("RDP Connect")
        about_dialog.set_license_type(Gtk.License(16))
        about_dialog.set_logo_icon_name("com.angoosh.RDPConnect")
        about_dialog.set_version(VERSION)
        about_dialog.set_website("https://gitea.farmdash.org/angoosh/Flatpaks")
        about_dialog.present()

    def on_preferences(self, action, param):
        PreferencesWindow()

    def on_history(self, action, param):
        HistoryWindow()

    def saveConnConf(self):
        if settings["save_conn"]:
            password = conn_info["passwd"]
            useratip = conn_info["user"] + "@" + conn_info["ip"]
            with open(HOMEDIR+"/.config/rdpconnect/history.json", "w") as hist_file:
                hist_id = str(int(max(hist_info, default=0)) + 1)
                hist_info[hist_id] = useratip
                js = json.dumps(hist_info, sort_keys=True, indent=4, separators=(',', ': '))
                hist_file.write(js)
            try:
                keyring.set_password("com.angoosh.RDPConnect", useratip, password)
            except:
                conn_info["passwd"] = fernet.encrypt(password.encode()).decode("utf-8")

                print("Saving connection config to "+HOMEDIR+"/.config/rdpconnect/connection.json")
                with open(HOMEDIR+"/.config/rdpconnect/connection.json", "w") as connection_file:
                    js = json.dumps(conn_info, sort_keys=True, indent=4, separators=(',', ': '))
                    connection_file.write(js)

                conn_info["passwd"] = password
        else:
            with open(HOMEDIR+"/.config/rdpconnect/connection.json", "w") as connection_file:
                connection_file.write("")

        print("Saving settings config to "+HOMEDIR+"/.config/rdpconnect/settings.json")
        with open(HOMEDIR+"/.config/rdpconnect/settings.json", "w") as settings_file:
            js = json.dumps(settings, sort_keys=True, indent=4, separators=(',', ': '))
            settings_file.write(js)

    def connectRDP(self, button):
        conn_info["ip"] = self.ip.get_buffer().get_text()
        conn_info["user"] = self.user.get_buffer().get_text()
        conn_info["passwd"] = self.passwd.get_buffer().get_text()

        if self.save_conf.get_active():
            settings["save_conn"] = True
        else:
            settings["save_conn"] = False
        if not "rdp_bin" in settings:
            settings["rdp_bin"] = "sdl-freerdp"

        self.saveConnConf()

        extra_params = []
        for item in settings["extra_params"]:
            #check if is boolean
            if type(settings["extra_params"][item]) == type(True):
                if settings["extra_params"][item]:
                    extra_params.append("/"+str(item))
            else:
                if str(settings["extra_params"][item]) != "":
                    print(str(settings["extra_params"][item]))
                    extra_params.append("/"+str(item)+":"+str(settings["extra_params"][item]))

        print(extra_params)

        try:
            print("Running", settings["rdp_bin"])
            subprocess.run([settings["rdp_bin"], "/cert:ignore", "/v:"+str(conn_info["ip"]), "/u:"+str(conn_info["user"]), "/p:"+str(conn_info["passwd"])]+extra_params)
        except:
            print("Running sdl-freerdp")
            subprocess.run(["sdl-freerdp", "/cert:ignore", "/v:"+str(conn_info["ip"]), "/u:"+str(conn_info["user"]), "/p:"+str(conn_info["passwd"])]+extra_params)

if not os.path.isdir(HOMEDIR+"/.config/rdpconnect"):
    os.makedirs(HOMEDIR+"/.config/rdpconnect")

load_keys()
load_config()
app = MyApp(application_id=APPID)
app.run(sys.argv)
