using Gtk;
using System;
using System.Linq;

namespace SSHVPNApplication {
    class SSHVPNLauncher {
        static string[] profiles;
        static int selected_profile_index = 0;
        static Window window = null;
        static void Main(string[] args) {
            var xdg_config_home = System.Environment.GetEnvironmentVariable("XDG_CONFIG_HOME");
            if (xdg_config_home == null) {
                xdg_config_home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + "/.config";
            }

            // normalise xdg_config_home
            if (xdg_config_home[xdg_config_home.Length-1] != '/') {
                xdg_config_home += "/";
            }

            string config_file_directory = xdg_config_home + "com.bangsparks.sshvpnapplication";
            string profiles_directory = config_file_directory + "/profiles";

            System.IO.Directory.CreateDirectory(config_file_directory);
            System.IO.Directory.CreateDirectory(profiles_directory);

            string config_docs_name = config_file_directory + "/CONFIG_README.txt";
            System.IO.File.WriteAllText(config_docs_name, "Configuration files\n\nConfigurations for this application are stored in in the 'profiles' directory.  Each profile is stored as a file with the name of the profile (extensions are interpreted as part of the name).  If no profile is specified on launch, 'default' will be assumed.\nThe contents of the file should be a single line, in the format 'user@host:port' or 'user@host' (port assumed to be 22).  To specify custom ssh keys, put them in the same folder as the config file and use the same name as the profile they are for, but append '.id_rsa', '.id_dsa', '.id_ecdsa' or '.id_ed25519'.  Such custom keys will be used alongside your normal SSH keys, and multiple of these can be present.\n\nNote that ssh key auth must be used.");

            string[] files = System.IO.Directory.GetFiles(profiles_directory);
            profiles = new String[files.Length];
            bool found_a_valid_profile = false;
            int profile_index = 0;
            int default_profile_index = 0;

            foreach (string potential_profile in files) {
                if (!(potential_profile.EndsWith(".id_rsa") || potential_profile.EndsWith(".id_dsa") || potential_profile.EndsWith(".id_ecdsa") || potential_profile.EndsWith(".id_ed25519"))) {
                    found_a_valid_profile = true;
                    profiles[profile_index] = potential_profile.Split("/").Last();
                    if (profiles[profile_index] == "default") {
                        default_profile_index = profile_index;
                    }
                    profile_index++;
                }
            }


            Application.Init();

            if (found_a_valid_profile) {
                window = new Window("Sshuttle GUI Launcher");

                VBox widget_box = new VBox(false, 10);

                ComboBox combo_box = new ComboBox(profiles);
                combo_box.Changed += on_selected_profile_change;
                combo_box.Active = default_profile_index;

                Button start_button = new Button();
                start_button.Label = "Start";
                start_button.Clicked += start_main_application;

                widget_box.Add(combo_box);
                widget_box.Add(start_button);

                window.Add(widget_box);

                window.ShowAll();

                // calls delete_event when window closed
                window.DeleteEvent += delete_event;

                // make a border for the window
                window.BorderWidth = 10;
            } else {
                Window error_window = new Window("Sshuttle GUI - Configuration Error");
                Label label = new Label("Please specify a configuration as documented by the text file in '" + config_file_directory + "'.");
                label.Show();

                error_window.Add(label);
                error_window.Show();

                // calls delete_event when window closed
                error_window.DeleteEvent += delete_event;

                // make a border for the window
                error_window.BorderWidth = 10;
            }

            Application.Run();
        }

        static void delete_event(object obj, DeleteEventArgs args) {
            // cleanly exit the application, so it doesnt remain running in the background
            Application.Quit();
        }

        static void start_main_application(object obj, EventArgs args) {
            string profile_name = profiles[selected_profile_index];

            // queue a request to withdraw the window
            window.Hide();
            
            // must be a loop since multiple events will almost certainly be pending, so we finish these to ensure the window is hidden
            while (Gtk.Application.EventsPending ()) {
                Gtk.Application.RunIteration();
            }

            System.Diagnostics.Process gui_process = System.Diagnostics.Process.Start("mono", /*System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) +*/ "/usr/bin/csharp_sshuttle_gui.exe " + profile_name);

            //System.Threading.Thread.Sleep(10000);

            bool gui_process_running = true;
            while (gui_process_running) {
                // only check the status of the launched process once every 10 seconds so that the launcher does not end up using an entire cpu core checking
                System.Threading.Thread.Sleep(10000);
                gui_process.Refresh();
                if (gui_process.HasExited) {
                    Application.Quit();
                    // loop must be broken, or Application.Quit() will never be processed.
                    gui_process_running = false;
                }
            }
        }

        static void on_selected_profile_change(object obj, EventArgs args) {
            ComboBox combo_box = (ComboBox) obj;
            selected_profile_index = combo_box.Active;
        }
    }
}
