//
//  UserLoginDialog.cs
//
// Copyright (C) 2010-2019 Thomas Klose & Torsten Schache, Hiperscan GmbH Dresden, Germany
//
//  This program is free software; you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation; either version 2 of the License, or
//  (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with this program; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//

using System;
using System.Security;

using Gdk;

using Glade;

using Gtk;

using Hiperscan.Unix;

using Microsoft.Win32;


namespace Hiperscan.QuickStep.UserLogin
{

    public class UserLoginDialog
    {
        private const string DEACTIVATED_MODE = "Deactivated";

        [Widget] Gtk.Dialog password_dialog = null;
        [Widget] Gtk.Entry password_entry = null;

        private static string exectuion_profile = null;


        private UserLoginDialog()
        {
        }

        private void Show(Pixbuf[] icon)
        {
            Glade.XML gui = new Glade.XML(null, "password.glade", "password_dialog", "Hiperscan");
            gui.Autoconnect(this);

            this.password_dialog.SetWmclass("quickstep", "quickstep");
            this.password_dialog.Title = string.Format(Catalog.GetString("Login for Account: {0}"),
                                                       UserLoginDialog.ExecutionProfile);

            this.password_dialog.IconList = icon;
            this.password_dialog.WidthRequest = 350;
        }

        private void ChangeUser(string[] args)
        {
            this.Password.MakeReadOnly();
            System.Diagnostics.Process process = new System.Diagnostics.Process();
            process.StartInfo.FileName = UserLoginDialog.QuickStepInstallPath;
            process.StartInfo.Arguments = string.Join(" ", args);
            process.StartInfo.CreateNoWindow = true;
            process.StartInfo.UseShellExecute = false;
            process.StartInfo.Password = this.Password;
            process.StartInfo.Domain = UserLoginDialog.ExecutionDomain;
            process.StartInfo.UserName = UserLoginDialog.ExecutionUser;
            process.StartInfo.WorkingDirectory = ".";
            process.StartInfo.LoadUserProfile = true;
            process.Start();
        }

        private void OnPassWordEntryChanged(object sender, EventArgs e)
        {
            this.Password.Clear();
            foreach (char c in (sender as Gtk.Entry).Text)
            {
                this.Password.AppendChar(c);
            }
        }

        private bool MustChangeUser
        {
            get
            {
                if (MainClass.OS != MainClass.OSType.Windows)
                {
                    Console.WriteLine("UserLoginDialog: The current operating system does not support this feature.");
                    return false;
                }

                if (UserLoginDialog.ExecutionProfile == UserLoginDialog.DEACTIVATED_MODE)
                {
                    Console.WriteLine("UserLoginDialog: User Profile change is not activated.");
                    return false;
                }

                Console.WriteLine("UserLoginDialog: ExecutionProfile is {0}", UserLoginDialog.ExecutionProfile);

                if (UserLoginDialog.ExecutionDomain == UserLoginDialog.CurrentDomain &&
                    UserLoginDialog.ExecutionUser == UserLoginDialog.CurrentUser)
                {
                    Console.WriteLine("UserLoginDialog: Already running in requested User Profile.");
                    return false;
                }

                Console.WriteLine("UserLoginDialog: Changing to requested User Profile {0}. Current: {1}\\{2}.",
                                  UserLoginDialog.ExecutionProfile,
                                  UserLoginDialog.CurrentDomain,
                                  UserLoginDialog.CurrentUser);
                return true;
            }
        }

        private static string QuickStepInstallPath
        {
            get
            {
                RegistryKey hiperscan = Registry.LocalMachine.OpenSubKey(@"Software\Hiperscan\CurrentQSVersion");
                string qs_version = (string)hiperscan.GetValue("VersionKey");

                hiperscan = Registry.LocalMachine.OpenSubKey("Software").OpenSubKey("Hiperscan").OpenSubKey(qs_version);
                string path = (string)hiperscan.GetValue("InstallPath");

                return System.IO.Path.Combine(path, "QuickStep.exe");
            }
        }

        private static string ExecutionProfile
        {
            get
            {
                if (string.IsNullOrEmpty(UserLoginDialog.exectuion_profile) == true)
                {
                    RegistryKey hiperscan = Registry.LocalMachine.OpenSubKey(@"Software\Hiperscan");
                    if (hiperscan == null)
                    {
                        UserLoginDialog.exectuion_profile = UserLoginDialog.DEACTIVATED_MODE;
                    }
                    else
                    {
                        UserLoginDialog.exectuion_profile = (string)hiperscan.GetValue("QuickStepExecutionProfile");
                        if (string.IsNullOrEmpty(UserLoginDialog.exectuion_profile) == true)
                            UserLoginDialog.exectuion_profile = UserLoginDialog.DEACTIVATED_MODE;
                    }
                }

                return UserLoginDialog.exectuion_profile;
            }
        }

        public static void Run(string[] args, Pixbuf[] icon)
        {
            try
            {
                UserLoginDialog user_login = new UserLoginDialog();

                if (user_login.MustChangeUser)
                {
                    Application.Init();
                    user_login.Show(icon);

                    while (true)
                    {
                        try
                        {
                            user_login.Password = new SecureString();
                            user_login.password_entry.Text = string.Empty;
                            user_login.password_entry.GrabFocus();
                            if (user_login.password_dialog.Run() == (int)ResponseType.Ok)
                            {
                                Console.WriteLine("Changing User Profile...");
                                user_login.ChangeUser(args);
                                Console.WriteLine("Success. This QuickStep instance will be closed.");
                            }
                            else
                            {
                                Console.WriteLine("User Profile change canceled by user. This QuickStep instance will be closed.");
                            }

                            user_login.password_dialog.Destroy();
                            UserLoginDialog.UserDialogShown = true;
                            break;
                        }
                        catch (System.ComponentModel.Win32Exception ex)
                        {
                            Console.WriteLine(ex.NativeErrorCode);
                            if (ex.NativeErrorCode != 1326)
                                throw;

                            string message = string.Format(Catalog.GetString("Cannot start QuickStep, because user the password " +
                                                                             "is not correct. Do you want to retry?" +
                                                                             "Do you want to retry?"), 
                                                           ex.Message);

                            MessageDialog mdlg = new MessageDialog(null, DialogFlags.Modal, MessageType.Error, ButtonsType.YesNo, message)
                            {
                                IconList = icon
                            };
                            mdlg.SetPosition(WindowPosition.CenterAlways);

                            ResponseType response = (ResponseType)mdlg.Run();
                            mdlg.Destroy();

                            if (response != ResponseType.Yes)
                            {
                                user_login.password_dialog.Destroy();

                                Console.WriteLine("Password prompt canceled by user.");
                                UserLoginDialog.UserDialogShown = true;
                                break;
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                string message = string.Format(Catalog.GetString("Could not start the application 'Quickstep': {0}."), ex.Message);
                MessageDialog mdlg = new MessageDialog(null, DialogFlags.Modal, MessageType.Error, ButtonsType.Close, message)
                {
                    IconList = icon
                };
                mdlg.SetPosition(WindowPosition.CenterAlways);

                mdlg.Run();
                mdlg.Destroy();

                Console.WriteLine("Cannot change User Profile: {0}.", ex);
                UserLoginDialog.UserDialogShown = true;

            }
        }

        public static bool UserChangeModeActive
        {
            get
            {
                if (MainClass.OS != MainClass.OSType.Windows)
                    return false;

                return UserLoginDialog.ExecutionProfile != UserLoginDialog.DEACTIVATED_MODE;
            }
        }

        public static string GetMainWindowTitelExtension
        {
            get
            {
                if (UserLoginDialog.UserChangeModeActive == false)
                    return string.Empty;

                return " " + string.Format(Catalog.GetString("User Profile: {0}"), UserLoginDialog.ExecutionProfile);
            }
        }

        private SecureString Password      { get; set; }
        public static bool UserDialogShown { get; private set; } = false;

        private static string ExecutionDomain => UserLoginDialog.ExecutionProfile.Split('\\')[0];
        private static string ExecutionUser   => UserLoginDialog.ExecutionProfile.Split('\\')[1];
        private static string CurrentDomain   => System.Security.Principal.WindowsIdentity.GetCurrent().Name.Split('\\')[0];
        private static string CurrentUser     => System.Security.Principal.WindowsIdentity.GetCurrent().Name.Split('\\')[1];
    }
}