
/* 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 Encfs;
using Gtk;
using Gee;

#if ENABLE_APPINDICATOR
using AppIndicator;
#endif

namespace GnomeEncfsManager {
    
    #if !ENABLE_APPINDICATOR
    public enum IndicatorCategory {
        APPLICATION_STATUS = 0
    }
    public enum IndicatorStatus {
        ACTIVE = 0,
        PASSIVE,
        ATTENTION
    }
    #endif

    public class Indicator : GLib.Object {
        #if ENABLE_APPINDICATOR
        private AppIndicator.Indicator appindicator;
        bool hasAppIndicator = true;
        #else
        bool hasAppIndicator = false;
        #endif

        bool useAppIndicator = true;    
        private StatusIcon status_icon;
        private IndicatorStatus status;
        private string icon_name_normal;
        private string icon_name_attention;
        private Gtk.Menu menu;

        public bool connected;

        public Indicator(  string name,
                    string icon,
                    IndicatorCategory category ) {
            #if ENABLE_APPINDICATOR
            string force_traysystem = settings.get_string("force-traysystem");
            switch (force_traysystem) {
                case "appindicator": {
                    useAppIndicator = useAppIndicator && true;
                    break;
                }
                case "classic": {
                    useAppIndicator = false;
                    break;
                }
                default: {
                    string session = Environment.get_variable("DESKTOP_SESSION");
                    useAppIndicator = useAppIndicator && !( session == "gnome-classic" );
                    useAppIndicator = useAppIndicator && !( session == "gnome" );
                    break;
                }
                
            }
            #endif
            
            useAppIndicator = hasAppIndicator && useAppIndicator;
            
            if (useAppIndicator) {
                #if ENABLE_APPINDICATOR
                GLib.stdout.printf("Using AppIndicator\n");
                appindicator = new AppIndicator.Indicator("Gnome Encfs Manager",
                                                          "gnome-encfs-manager-panel",
                                                          IndicatorCategory.APPLICATION_STATUS);
                #endif
            } else {
                GLib.stdout.printf("Using Classic TrayIcon\n");
                connected = false;
                icon_name_normal = icon;
                status_icon = new StatusIcon.from_icon_name(icon);

                status_icon.popup_menu.connect( (button, time) => {
                    menu.popup( null, null, status_icon.position_menu, button, time);
                });
                status_icon.activate.connect( () => {
                    menu.popup( null, null, status_icon.position_menu, 0, Gtk.get_current_event_time());
                });
            }
        }

        public void set_title( string title ) {
            if (useAppIndicator) {
                #if ENABLE_APPINDICATOR
                appindicator.set_title( title );
                #endif
            } else {
                status_icon.title = title;
            }
        }

        public void set_status( IndicatorStatus status ) {
            if (useAppIndicator) {
                #if ENABLE_APPINDICATOR
                switch (status) {
                    case IndicatorStatus.ACTIVE:
                        appindicator.set_status( AppIndicator.IndicatorStatus.ACTIVE );
                        set_icon("gnome-encfs-manager-panel");
                        break;
                    case IndicatorStatus.PASSIVE:
                         appindicator.set_status( AppIndicator.IndicatorStatus.PASSIVE );
                        break;
                    case IndicatorStatus.ATTENTION:
                        appindicator.set_status( AppIndicator.IndicatorStatus.ACTIVE );
                        set_icon("gnome-encfs-manager-panel-attention");
                        break;
                }
                appindicator.set_status( status );
                #endif
            } else {
                this.status = status;
                switch (status) {
                    case IndicatorStatus.ACTIVE:
                        status_icon.set_from_icon_name(icon_name_normal);
                        status_icon.set_visible(true);
                        break;
                    case IndicatorStatus.PASSIVE:
                        status_icon.set_visible(false);
                        break;
                    case IndicatorStatus.ATTENTION:
                        status_icon.set_from_icon_name(icon_name_attention);
                        status_icon.set_visible(true);
                        break;
                }
            }
        }

        public void set_icon_theme_path( string path ) {
            if (useAppIndicator) {
                #if ENABLE_APPINDICATOR
                appindicator.set_icon_theme_path( path );
                #endif
            } else {
            }
        }

        public void set_attention_icon( string icon ) {
            if (useAppIndicator) {
                #if ENABLE_APPINDICATOR
                appindicator.set_attention_icon_full(icon, "Busy");
                #endif
            } else {
                icon_name_attention = icon;
            }
        }
        public void set_icon( string icon ) {
            if (useAppIndicator) {
                #if ENABLE_APPINDICATOR
                appindicator.set_icon_full(icon, null);
                #endif
            } else {
                icon_name_normal = icon;
                status_icon.set_from_icon_name(icon);
                set_status(status);
            }
        }

        public void set_menu( Gtk.Menu menu ) {
            if (useAppIndicator) {
                #if ENABLE_APPINDICATOR
                menu.ref();
                appindicator.set_menu( menu );
                #endif
            } else {
                this.menu = menu;
            }
        }

        public IndicatorStatus get_status() {
            if (useAppIndicator) {
                #if ENABLE_APPINDICATOR
                return appindicator.get_status();
                #else
                return IndicatorStatus.PASSIVE;
                #endif
            } else {
                return status;
            }
        }

    }


    public class TrayIcon : GLib.Object {
        private static GnomeEncfsManager.Indicator indicator;
        
        public enum State {
			Normal = 0,
			Busy,
			NUM
		}

        public static void show() {
            if (indicator == null) {
                indicator = new GnomeEncfsManager.Indicator("Gnome Encfs Manager",
                                                            "gnome-encfs-manager-panel",
                                                            IndicatorCategory.APPLICATION_STATUS);
            }

            indicator.set_title(_("Gnome Encfs Manager"));
            indicator.set_icon_theme_path(get_data_path() + "/../icons");
            //indicator.set_attention_icon("gnome-encfs-manager-panel-attention");
			
            indicator.set_status(IndicatorStatus.ACTIVE);
            update();
            
            #if ENABLE_APPINDICATOR

            // Work around some bugs
            /*int i = 9;
            Timeout.add (100, () => {
            	if (indicator.connected == true) {
            		return false;
            	}
            	i--;
            	indicator.set_icon("gnome-encfs-manager-panel-attention");
            	indicator.set_icon("gnome-encfs-manager-panel");
            	
            	if (i > 0) {
            		return true;
            	} else {
            		return false;
            	}
            });
            int j = 10;
            Timeout.add (1000, () => {
            	if (indicator.connected == true) {
            		return false;
            	}
            	j--;
            	indicator.set_icon("gnome-encfs-manager-panel-attention");
            	indicator.set_icon("gnome-encfs-manager-panel");
            	
            	if (j > 0) {
            		return true;
            	} else {
            		return false;
            	}
            });*/
            #endif
        }
        
        public static void setState( State state ) {
        	if (indicator == null) return;
        
        	switch (state) {
		    	case State.Normal:
		    		indicator.set_status(IndicatorStatus.ACTIVE);
		    		break;
		    	case State.Busy:
		    		indicator.set_status(IndicatorStatus.ATTENTION);
		    		break;
        	}
        	return;
        }
        
        public static void hide() {
            if (indicator == null)
                return;
                
            indicator.set_status(IndicatorStatus.PASSIVE);
        }
        
        public static bool is_visible() {
            return ((indicator != null) && (indicator.get_status() != IndicatorStatus.PASSIVE));
        }
        
        
        public static void update() {
            if ((indicator == null) || (indicator.get_status() == IndicatorStatus.PASSIVE))
                return;
        
            var menu = new Gtk.Menu();

            var item = new Gtk.MenuItem.with_label(_("Encrypted folders:"));

            item.set_sensitive(false);
            menu.append(item);
            
            stashes_mutex.lock();
            if (GnomeEncfsManager.stashes != null) {
                if (settings.get_boolean("tray-stash-groups")) {
                    string[] group_names = settings.get_strv("stash-groups");
                    ArrayList<Stash> tmp = new ArrayList<Stash>();
     
		            foreach (Stash s in GnomeEncfsManager.stashes) {
		                if (!s.isAvailable && !s.isMounted)
		                    continue;
		                
		                if (!s.showInTrayMenu)
		                    continue;
		            
		                if (s.options.get_string("stash_group") == "") {
		                    tmp.add(s);
		                }
		            }
		            
		            foreach (Stash s in tmp) {
                        var cmitem = new CheckMenuItem.with_label(Path.get_basename(s.mountDir));
                        cmitem.set_active(s.isMounted);
                        
                        cmitem.activate.connect( (source) => {
                            if (cmitem.get_active()) {
                                update();
                                MountDialog.mount(s);
                            }
                            else
                                s.unmount();
                        });
                        menu.append(cmitem);
		            }
		            
		            bool sep_drawn = false;
                    foreach (string key in group_names) {
                        tmp.clear();
		                foreach (Stash s in GnomeEncfsManager.stashes) {
		                    if (!s.isAvailable && !s.isMounted)
		                        continue;
		                    
		                    if (!s.showInTrayMenu)
		                        continue;
		                
		                    if (s.options.get_string("stash_group") == key) {
		                        tmp.add(s);
		                    }
		                }
		                if (tmp.size > 0) {
		                    if (!sep_drawn) {
		                        menu.append(new SeparatorMenuItem());
		                        sep_drawn = true;
		                    }
                            var submenu_item = new Gtk.MenuItem.with_label(key);
                            menu.append(submenu_item);
                            var submenu = new Gtk.Menu ();
                            submenu_item.set_submenu(submenu);
                            foreach (Stash s in tmp) {
	                            var cmitem = new CheckMenuItem.with_label(Path.get_basename(s.mountDir));
	                            cmitem.set_active(s.isMounted);
	                            
	                            cmitem.activate.connect( (source) => {
	                                if (cmitem.get_active()) {
	                                    update();
	                                    MountDialog.mount(s);
	                                }
	                                else
	                                    s.unmount();
	                            });
	                            submenu.append(cmitem);
                            }
		                }
		            }
		        } else {
		            foreach (Stash s in stashes) {
		                if (!s.isAvailable && !s.isMounted)
		                    continue;
		                
		                if (!s.showInTrayMenu)
		                    continue;
		                    
                        var cmitem = new CheckMenuItem.with_label(Path.get_basename(s.mountDir));
                        cmitem.set_active(s.isMounted);
                        
                        cmitem.activate.connect( (source) => {
                            if (cmitem.get_active()) {
                                update();
                                MountDialog.mount(s);
                            }
                            else
                                s.unmount();
                        });
                        menu.append(cmitem);
		            }
		        }
		    }
		    stashes_mutex.unlock();
            
            menu.append(new SeparatorMenuItem());

            var citem = new CheckMenuItem.with_label(_("Show Manager"));
            citem.set_active(Manager.is_visible());
            
            citem.activate.connect( () => {
                if (Manager.is_visible()) {
                    Manager.close();
                }
                else {
                    Manager.show();
                }
            });
            menu.append(citem);
            
            menu.append(new SeparatorMenuItem());

            item = new ImageMenuItem.from_stock(Gtk.Stock.QUIT, null);
            item.activate.connect( () => {
                GnomeEncfsManager.quit();
            });
            menu.append(item);
            menu.show_all();
            indicator.set_menu(menu);
        }
    }
}
