
/* Gnome Encfs Manager (GEncfsM)
 * Copyright (C) 2011 Moritz Molch <mail@moritzmolch.de>
 
 * 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.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

using Gtk;
using GLib;
using Encfs;
using GnomeEncfsManager;
using Secret;
using Gee;

namespace GnomeEncfsManager {
    public class MountDialog {
        private static Dialog dialog;
        private static Builder builder;
        
        public static LinkedList<Stash> queue;
        
        private static ulong sighandler;
        private static bool usedKeyring;
        
        private static bool mounting = false;
        private static string hidden_response = null;
        private static int busy_id;
        
        private static void show() {
            if (dialog != null)
                return;
        
            try {
            	mounting = false;
                builder = new Builder();
                builder.add_from_file(get_glade_file("mount_dialog.ui"));
                builder.connect_signals(null);
                dialog = (Dialog)builder.get_object("mount_dialog");
                if (hidden_response != null) {
		            string failMarkup = "<span color='red'>✘</span> " + hidden_response;
		            ((Label)builder.get_object("label_status")).set_markup(failMarkup);
		            hidden_response = null;
                }
   
                update();
                ((Window)dialog).present();
                ((Window)dialog).set_keep_above(true);
                
                // workaround for compiz on quantal
                {
		            while (Gtk.events_pending())
						Gtk.main_iteration();
		            
		            Timeout.add (100, () => {
		            	try {
		            		Process.spawn_command_line_async("wmctrl -a \"" + ((Window)dialog).get_title() + "\"");
		            	} catch (GLib.Error e) {
		            	}
		            	return false;
		            });
		        }
            } catch (GLib.Error e) {
                stderr.printf("Could not load UI: %s\n", e.message);
            }
        }
        
        public static void update() {
            if (dialog == null)
                return;
                
            ((Label)builder.get_object("label_enter_password")).set_text(
                            "Please enter the password for\n%s".printf(queue.first().mountDir) );
            
            if (((Entry)builder.get_object("entry_password")).get_text() == "") {
                ((Button)builder.get_object("button_ok")).set_sensitive(false);
            }
            else {
                ((Button)builder.get_object("button_ok")).set_sensitive(true);
            }
            
            if (!queue.first().isAvailable) {
                hide();
            }
            
            if (!((Widget)builder.get_object("entry_password")).has_focus) {
            	((Entry)builder.get_object("entry_password")).grab_focus();
            }
        }
        
        private static void on_mountResponse(bool success, string message) {
        	mounting = false;
        	busy(busy_id.to_string());
        	
            if (usedKeyring) {
                if (success) {
                	queue.first().run_custom_command_async("post_mount_command", ()=>{});
                	queue.first().scriptenv = null;

                    queue.first().disconnect(sighandler);
                    queue.remove(queue.first());
                    if (queue.size > 0) {
                        _mount();
                    }
                    return;
                }
                else {
                	hidden_response = message;
                    show();
                }
            }
            else {
                if (dialog == null)
                    return;
                
                
                if (success) {
                    if (queue.first().useKeyring) {
                        string password = ((Entry)builder.get_object("entry_password")).get_text();
                        string keyring_name = queue.first().options.get_string("keyring_name");
                        if (keyring_name == "") {
                        	keyring_name = COLLECTION_DEFAULT;
                        }
                        
                        try {
                            Secret.password_store_sync(Secret.get_schema(Secret.SchemaType.COMPAT_NETWORK),
                                                       keyring_name,
                                                       "Encfs password for "+queue.first().cryptDir,
                                                       password,
                                                       null,
                                                       "server", queue.first().cryptDir);

                        } catch (GLib.Error error) {
                            print("LibSecret:" + error.message + "\n");
                        }
                    }
                    queue.first().run_custom_command_async("post_mount_command", ()=>{});
                    queue.first().scriptenv = null;
                    hide();
                }
                else {
                    string failMarkup = "<span color='red'>✘</span> " + message;
                    ((Label)builder.get_object("label_status")).set_markup(failMarkup);

                    ((Entry)builder.get_object("entry_password")).set_text("");
                    ((Widget)builder.get_object("button_options")).set_sensitive(true);
            		((Widget)builder.get_object("entry_password")).set_sensitive(true);
                    ((Widget)builder.get_object("alignment3")).set_visible(false);
                    ((Spinner)builder.get_object("spinner")).stop();
                    ((Widget)builder.get_object("label_status")).set_visible(true);
                    ((Entry)builder.get_object("entry_password")).grab_focus();
                }
            }
        }
        
        
        private async static void _mount() {

            if ((queue == null) || (queue.size == 0))
                return;
            
            if (queue.first().isMountedReal() || !(queue.first().isAvailable)) {
                queue.remove(queue.first());
                if (queue.size > 0) {
                    _mount();
                }
                return;
            }
            
            queue.first().run_custom_command_async("pre_mount_command", (status) => {
            	if (status == Stash.scriptStatusCode["GENCFSM_CANCEL"]) {
            		queue.first().scriptenv = null;
		            queue.remove(queue.first());
		            if (queue.size > 0) {
		                _mount();
		            }
		            return;
            	}
            	
            	busy_id = busy(Path.get_basename(queue.first().mountDir) + ": " + _("Mounting..."));
		        
		        sighandler = queue.first().mountResponse.connect( on_mountResponse );
		        usedKeyring = false;
		        
		        // use keyring
		        if (queue.first().useKeyring) {
                    string password = Secret.password_lookup_sync(Secret.get_schema(Secret.SchemaType.COMPAT_NETWORK), null, "server", queue.first().cryptDir);
                    if (password != null) {
                        usedKeyring = true;
                        queue.first().mount(password);
                    } else {
                        busy(busy_id.to_string());
                        show();
                    }
		        }
		        else {
			        busy(busy_id.to_string());
		            show();
		        }
            });

        }
        
        public static void mount(Stash s) {
            if (queue == null) {
                queue = new LinkedList<Stash> ();
            }

            queue.add(s);
            
            if (queue.size > 1) {
                return;
            }
            else {
                _mount();
            }

        }
        
        public static void ok() {
            if (((Entry)builder.get_object("entry_password")).get_text() == "") {
                return;
            }        
            ((Label)builder.get_object("label_status")).set_markup("");
            //dialog.set_sensitive(false);
            ((Widget)builder.get_object("button_options")).set_sensitive(false);
            ((Widget)builder.get_object("button_ok")).set_sensitive(false);
            ((Widget)builder.get_object("entry_password")).set_sensitive(false);
            ((Spinner)builder.get_object("spinner")).start();
            ((Widget)builder.get_object("alignment3")).set_visible(true);
            ((Widget)builder.get_object("label_status")).set_visible(false);
            ((Widget)builder.get_object("button_cancel")).grab_focus();
            
            while (Gtk.events_pending()) {
                Gtk.main_iteration();
            }
            
            string password = ((Entry)builder.get_object("entry_password")).get_text();
            usedKeyring = false;
            busy_id = busy(Path.get_basename(queue.first().mountDir) + ": " + _("Mounting..."));
            mounting = true;
            queue.first().mount(password);
        }
        
        public static void options() {
            ConfigureStash.show( queue.first() );
        }
        
        public static void on_cancel() {
        	if (mounting) {
        		queue.first().mount_cancel();
        	}
        	else {
        		hide();
        	}
        }
        
        public static void hide() {
            if (dialog == null || mounting)
                return;
            
            dialog.destroy();
            dialog = (Dialog)null;
            
            queue.first().disconnect(sighandler);
            queue.remove(queue.first());

            if (queue.size > 0) {
                _mount();
            }
        }
        
        public static void kill() {
            if (dialog == null || mounting)
                return;
            
            dialog.destroy();
            dialog = (Dialog)null;
            
            queue.first().disconnect(sighandler);
            queue.clear();
        }
        
    }
}
