/* -*- Mode: vala; tab-width: 4; intend-tabs-mode: t -*- */
/* alm
 * Copyright (C) 2012 Stefano Candori <scandori@gnome.org>
 *
 * alm is free software: you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 * 
 * alm 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 Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.";
 */
 
using Gtk;
using Gee;
using GLib;
using Zeitgeist;

namespace Alm {

	enum ItemType {
		FILE,
		APPLICATION
	}
	
	public class PrivacyWidget : Box {
		private Blacklist blacklist;
		
		//File/Folder Stuffs
		private bool file_type_fire_signal = true;
		private FileTypeBlacklist files_type_blacklist;
		private PathBlacklist path_blacklist;
		
		private HashMap<string, string> mime_dict;
		private HashMap<string, CheckButton> checkboxes;
		private HashSet<CheckButton> button_list;
		
		private HashMap<string, UserDirectory> defined_dirs;
		
		//Application stuffs
		private ApplicationBlacklist app_blacklist;
		private ApplicationsChooserDialog app_dialog;
		private ApplicationsTreeView app_treeview;
		private Gtk.Box container_box;

		private HashTable<string, AppChooseInfo> blocked_list;
		private HashTable<string, AppChooseInfo> unblocked_list;

		private bool app_change_recursive;
		
		//General stuffs
		private TreeView exception_list;
		private ListStore exception_list_store;
		
		private Switch record_button;
		
		private Button del_button;
		private DeleteHistoryDialog delete_dialog;
		
		private Gdk.Pixbuf? stock_folder_icon;
		
		private Gtk.Menu exception_menu;
		
		public PrivacyWidget (Blacklist blacklist_interface) {
			GLib.Object (orientation: Orientation.VERTICAL, spacing:10);
			
			this.blacklist = blacklist_interface;
			//File/Folder stuffs
			this.checkboxes = new HashMap<string, CheckButton>();
			this.button_list = new HashSet<CheckButton>();
			
			this.files_type_blacklist = new FileTypeBlacklist(blacklist_interface, 
												this.checkboxes);
			this.path_blacklist = new PathBlacklist(blacklist_interface);
			
			blacklist_interface.template_added.connect(
				(blacklist_id, blacklist_template) => {
					if(blacklist_id.has_prefix(FileTypeBlacklist.interpretation_prefix))
					{
						file_type_fire_signal = false;
						var inter = blacklist_template.get_subject(0).get_interpretation ();
						if(checkboxes.has_key(inter))
							checkboxes.get(inter).active = false;
						file_type_fire_signal = true;
					}
				});
			blacklist_interface.template_removed.connect(
				(blacklist_id, blacklist_template) => {
					if(blacklist_id.has_prefix(FileTypeBlacklist.interpretation_prefix))
					{
						file_type_fire_signal = false;
						var inter = blacklist_template.get_subject(0).get_interpretation ();
						if(checkboxes.has_key(inter))
							checkboxes.get(inter).active = true;
						file_type_fire_signal = true;
					}
				});

			this.path_blacklist.folder_added.connect((folder) => {
				if(!this.path_blacklist.is_duplicate(folder))
					add_folder_to_view(folder);
			});

			this.path_blacklist.folder_removed.connect((folder) => {
				remove_folder_from_view(folder);
			});
			
			mime_dict = new HashMap<string, string>(str_hash, str_equal);
			mime_dict.set(_("Music"), NFO_AUDIO);
			mime_dict.set(_("Videos"), NFO_VIDEO);
			mime_dict.set(_("Pictures"), NFO_IMAGE);
			mime_dict.set(_("Documents"), NFO_DOCUMENT);
			mime_dict.set(_("Presentations"), NFO_PRESENTATION);
			mime_dict.set(_("Spreadsheets"), NFO_SPREADSHEET);
			mime_dict.set(_("Instant Messaging"), NMO_IMMESSAGE);
			mime_dict.set(_("Emails"), NMO_EMAIL);
			mime_dict.set(_("Websites"), NFO_WEBSITE);
			
			UserDirectory[] special_dirs =
			{
				UserDirectory.DESKTOP,
				UserDirectory.DOCUMENTS,
				UserDirectory.DOWNLOAD,
				UserDirectory.MUSIC,
				UserDirectory.PICTURES,
				UserDirectory.PUBLIC_SHARE,
				UserDirectory.TEMPLATES,
				UserDirectory.VIDEOS
			};
			
			for(int i = 0; i < special_dirs.length; i++) {
				string dir_path = Environment.get_user_special_dir(special_dirs[i]);
				if (dir_path != null) {
					defined_dirs.set(dir_path, special_dirs[i]);
				}
			}
			
			//FIXME: Not sure if the correct icon is being fetched for stock folder
			stock_folder_icon = this.render_icon_pixbuf(Stock.DIRECTORY, IconSize.LARGE_TOOLBAR);
			
			//Application Stuffs
			this.blocked_list = new HashTable<string, AppChooseInfo>(str_hash, str_equal);
			this.unblocked_list = new HashTable<string, AppChooseInfo>(str_hash, str_equal);

			this.app_blacklist = new ApplicationBlacklist (blacklist_interface);
			this.app_treeview = new ApplicationsTreeView(app_blacklist, blocked_list, unblocked_list);
			
			this.app_blacklist.application_removed.connect((app, event) => {
				if(!app_change_recursive)
					this.remove_app_from_view(app);
				app_change_recursive = false;
			});
			this.app_blacklist.application_added.connect((app, event) => {
				if(!app_change_recursive)
					this.add_app_to_view(app);
				app_change_recursive = false;
			});

			this.setup_ui();
		}

		private void setup_ui() {
			this.set_border_width(12);

			string text = _("This Operating System keeps track of Files and Applications you've used to provide extra functionality. If other people can see or access your user account, you may wish to limit which items are recorded.");
			var label = new Label("");
			label.set_markup("%s".printf(text));
			label.set_line_wrap(true);
			label.set_line_wrap_mode(Pango.WrapMode.WORD);
			label.set_alignment(0, 0.5f);
			this.pack_start(label, false);
			
			record_button = new Switch();
			Label record_label = new Label("");
			record_label.set_markup("<b>%s</b>".printf(_("Record file and application usage")));
			
			record_button.active = !blacklist.get_incognito();
			blacklist.incognito_toggled.connect((status) => {
				this.record_button.active = !status;
			});

			record_button.notify["active"].connect (() => {
				var recording = !blacklist.get_incognito();
				if (this.record_button.active != recording) {
					blacklist.set_incognito(recording);
				}
			});
			
			this.del_button = new Button.from_stock(Stock.DELETE);
			del_button.set_label(_("Clear Usage Data..."));

			del_button.clicked.connect(()=> {
				delete_dialog.on_delete_history ();
			});

			var hbox = new Box (Orientation.HORIZONTAL, 3);
			hbox.pack_start(record_button, false, false, 3);
			hbox.pack_start(record_label, false, false, 3);
			hbox.pack_start(new Label(""), true, true, 3);
			hbox.pack_start(del_button, false, false, 3);
			
			this.pack_start (hbox, false);

			// Checkbox Box
			var checkbox_hbox = new Box(Orientation.VERTICAL, 0);

			CompareFunc<string> mime_compare = (s1, s2) => {
				return s1.collate(s2);
			};
			Gee.ArrayList<string> keys = new Gee.ArrayList<string>();
			keys.add_all(mime_dict.keys);
			keys.sort (mime_compare);
			foreach(string key in keys) {
				var check_button = new CheckButton.with_label (key);
				check_button.active = true;
				
				this.button_list.add(check_button);
				this.checkboxes.set(mime_dict[key], check_button);

				checkbox_hbox.pack_start (check_button, false, false, 0);
			}
			
			this.files_type_blacklist.populate_file_types();
			
			foreach(CheckButton check_button in this.button_list)
			{
				check_button.toggled.connect(() => {
					if(file_type_fire_signal)
					{
						file_type_fire_signal = false;
						if(check_button.active)
							files_type_blacklist.unblock(mime_dict[check_button.label]);
						else
							files_type_blacklist.block(mime_dict[check_button.label]);
						file_type_fire_signal = true;
					}
				});
			}
			
			var checkbox_label = new Label (_("Include:"));
			var al = new Alignment (0, 0.5f, 0, 0);
			al.add (checkbox_label);
			
			var checkbox_vbox = new Box(Orientation.VERTICAL, 0);
			checkbox_vbox.pack_start (al, false);
			checkbox_vbox.pack_start (checkbox_hbox, true);
			
			//Exception List
			var exception_vbox = new Box(Orientation.VERTICAL, 0);
			var exception_label = new Label (_("Exclude:"));
			var al2 = new Alignment (0, 0.5f, 0, 0);
			al2.add (exception_label);
			exception_vbox.pack_start (al2, false, false, 5);

			// Exception TreeView
			this.exception_list_store = new ListStore (4, 
				typeof(string),      // Full file path of application desktop file.
				typeof(Gdk.Pixbuf?), // Pixbuf
				typeof(string),      // File basename or ApplicationName
				typeof(ItemType));   // File or Application?

			this.exception_list = new TreeView.with_model (this.exception_list_store);
			this.exception_list.set_headers_visible (false);
			this.exception_list.set_rules_hint (true);

			var column_pix_name = new TreeViewColumn ();
			column_pix_name.set_title (_("Name"));
			this.exception_list.append_column (column_pix_name);
			
			var pix_rend = new ExceptionCellRenderer ();
			column_pix_name.pack_start (pix_rend, false);
			column_pix_name.add_attribute (pix_rend, "pixbuf", 1);
			column_pix_name.add_attribute (pix_rend, "text", 2);
			
			var scroll = new ScrolledWindow(null, null);
			scroll.add(this.exception_list);
			scroll.set_policy (PolicyType.NEVER, PolicyType.AUTOMATIC);
			scroll.set_shadow_type (ShadowType.IN);
			scroll.set_border_width (1);
			exception_vbox.pack_start(scroll, true, true);

			// Add/Remove buttons
			var exception_toolbar = new Toolbar();
			exception_toolbar.toolbar_style = ToolbarStyle.ICONS;
			exception_toolbar.icon_size = 1;
			exception_toolbar.icon_size_set = true;
			exception_toolbar.visible = true;
			
			scroll.get_style_context().set_junction_sides(Gtk.JunctionSides.BOTTOM);
			exception_toolbar.get_style_context().add_class(Gtk.STYLE_CLASS_INLINE_TOOLBAR);
			exception_toolbar.get_style_context().set_junction_sides(Gtk.JunctionSides.TOP);

			var exception_add = new ToolButton(null, _("Add Item"));
			exception_add.set_icon_name("list-add-symbolic");
			exception_add.clicked.connect(on_add_exception);

			var exception_remove = new ToolButton(null, _("Remove Item"));
			exception_remove.set_icon_name("list-remove-symbolic");
			exception_remove.clicked.connect(on_remove_exception);

			exception_toolbar.insert(exception_add, 0);
			exception_toolbar.insert(exception_remove, 1);
			
			exception_menu = new Gtk.Menu ();
			var folder_menu = new Gtk.MenuItem.with_label ("Add Folder...");
			folder_menu.activate.connect (on_add_folder);
			//TODO Alm can't blacklist a single file atm.
//			var file_menu = new Gtk.MenuItem.with_label ("Add File...");
//			file_menu.activate.connect (on_add_file);
			var app_menu = new Gtk.MenuItem.with_label ("Add Application...");
			app_menu.activate.connect (on_add_application);
			exception_menu.append(folder_menu);
			//exception_menu.append(file_menu);
			exception_menu.append(app_menu);
			exception_menu.show_all ();

			exception_vbox.pack_start(exception_toolbar, false, false);
			
			var general_hbox = new Box(Orientation.HORIZONTAL, 0);
			general_hbox.pack_start(checkbox_vbox, true);
			general_hbox.pack_start(exception_vbox, true);
			
			this.pack_start(general_hbox, false);
			
			this.app_dialog = new ApplicationsChooserDialog (app_blacklist, blocked_list, unblocked_list);
			this.delete_dialog = new DeleteHistoryDialog (del_button);
			
			//File/Folder population
			this.folders_populate();
			//App/Population
			this.app_populate();
		}
		
		public int compare_mimes (string s1, string s2)
		{
			return s1.collate(s2);
		}
		
		private void folders_populate () {
			foreach(string folder in path_blacklist.all_folders)
			{
				add_folder_to_view(folder);
			}
		}
		
		private void app_populate () {
			foreach(string app in app_blacklist.all_apps)
			{
				add_app_to_view(app);
			}
		}
		
		private void on_add_exception() {
			exception_menu.popup (null, null, null, 1, get_current_event_time ());
		}

		private void on_remove_exception () {
			TreeSelection sel = this.exception_list.get_selection ();
			if(sel != null)
			{
				TreeModel model;
				TreeIter iter;
				if(sel.get_selected(out model, out iter))
				{
					string name;
					ItemType type;
					model.get(iter, 0, out name, 3, out type);
					if(name != null)
					{
						exception_list_store.remove(iter);
						if (type == ItemType.FILE)
							this.path_blacklist.unblock(name);
						else
							this.app_blacklist.unblock(name);
					}
				}
			}
		}
		
		private void on_add_folder() {
			var chooser = new FileChooserDialog(
				_("Select a directory to blacklist"), 
				null, FileChooserAction.SELECT_FOLDER);
			chooser.add_buttons (Stock.OK, ResponseType.OK, Stock.CANCEL, ResponseType.CANCEL);
			int res = chooser.run();
			chooser.hide();
			if(res == ResponseType.OK)
			{
				string folder = chooser.get_filename ();
				if(!this.path_blacklist.is_duplicate(folder))
				{
					add_folder_to_view(folder);
					this.path_blacklist.block(folder);
				}
			}
		}
		
		private void on_add_file() {
			var chooser = new FileChooserDialog(
				_("Select a file to blacklist"), 
				null, FileChooserAction.OPEN);
			chooser.add_buttons (Stock.OK, ResponseType.OK, Stock.CANCEL, ResponseType.CANCEL);
			int res = chooser.run();
			chooser.hide();
			if(res == ResponseType.OK)
			{
				string filename = chooser.get_filename ();
				if(!this.path_blacklist.is_duplicate(filename))
				{
					add_folder_to_view(filename);
					this.path_blacklist.block(filename);
				}
			}
		}
		
		private void on_add_application() {
			this.app_dialog.set_transient_for((Gtk.Window)this.get_toplevel());
			this.get_toplevel().set_sensitive(false);
			this.app_dialog.set_modal(true);
			app_dialog.set_title(_("Select Application"));
			//FIXME: use proper modality
			int res = this.app_dialog.run();
			this.get_toplevel().set_sensitive(true);
			if(res == ResponseType.OK) {
				TreeSelection sel = this.app_dialog.tree.get_selection ();
				TreeModel model;
				TreeIter iter;
				sel.get_selected(out model, out iter);
				string app;
				model.get(iter, 2, out app);
				this.app_dialog.liststore.remove (iter);

				// Add the App to View
				app_change_recursive = true;
				this.add_app_to_view(app);
				this.app_blacklist.block(app);

				AppChooseInfo info = unblocked_list.lookup(app);
				if(info != null)
				{
					unblocked_list.remove(app);
					if(blocked_list.lookup(app) == null)
						blocked_list.insert(app, info);
					else
						blocked_list.replace(app, info);
				}
			}
			this.app_dialog.hide();			
		}
		
		private void add_folder_to_view (string folder) {

			Gdk.Pixbuf? icon = stock_folder_icon;
			ThemedIcon? nautilus_icon = null;
			if(defined_dirs.has_key(folder))
			{
				UserDirectory dir = defined_dirs.get(folder);
				if (dir.to_string() == "G_USER_DIRECTORY_DOCUMENTS")
					nautilus_icon = new ThemedIcon("folder-documents");
				else if (dir.to_string() == "G_USER_DIRECTORY_DOWNLOAD")
					nautilus_icon = new ThemedIcon("folder-download");
				else if (dir.to_string() == "G_USER_DIRECTORY_MUSIC")
					nautilus_icon = new ThemedIcon("folder-music");
				else if (dir.to_string() == "G_USER_DIRECTORY_DESKTOP")
					nautilus_icon = new ThemedIcon("user-desktop");
				else if (dir.to_string() == "G_USER_DIRECTORY_PICTURES")
					nautilus_icon = new ThemedIcon("folder-pictures");
				else if (dir.to_string() == "G_USER_DIRECTORY_VIDEOS")
					nautilus_icon = new ThemedIcon("folder-videos");
				else if (dir.to_string() == "G_USER_DIRECTORY_TEMPLATES")
					nautilus_icon = new ThemedIcon("folder-templates");
				else if (dir.to_string() == "G_USER_DIRECTORY_PUBLIC_SHARE")
					nautilus_icon = new ThemedIcon("folder-publicshare");
				if(nautilus_icon != null) {
					var pixbuf = ApplicationsTreeView.get_pixbuf_from_gio_icon(nautilus_icon, 24);
					if (pixbuf != null)
						icon = pixbuf;
				}
			}
			
			string name = Path.get_basename(folder.strip());
			TreeIter iter;
			this.exception_list_store.append(out iter);
			// First element is full path, second is icon and third is just the path basename
			this.exception_list_store.set(iter, 0, folder, 1, icon, 2, name, 3, ItemType.FILE, -1);
		}

		private bool remove_folder_from_view (string folder) {
			var model = this.exception_list.get_model ();
			TreeIter iter;
			model.get_iter_first (out iter);
			while (true)
			{
				Value can_app_value;
				model.get_value(iter, 0, out can_app_value);
				string cand_folder = can_app_value.get_string();
				if(folder == cand_folder)
				{
					this.exception_list_store.remove(iter);
					return true;
				}
				bool more_entires = model.iter_next(ref iter);
				if(!more_entires)
				{
					return false;
				}
			}
		}
		
		private void add_app_to_view (string app) {
			DesktopAppInfo app_info = new DesktopAppInfo(app);
			if (app_info != null ) {
				var pix = ApplicationsTreeView.get_pixbuf_from_gio_icon(app_info.get_icon(), 24);
				var markup = ApplicationsTreeView.markup_for_app(app_info);
				TreeIter iter;
				this.exception_list_store.append(out iter);
				this.exception_list_store.set(iter, 0, app,
													1, pix,
													2, app_info.get_name (),
													3, ItemType.APPLICATION, -1);

				// Insert only when it is empty
				if(this.blocked_list.lookup(app) == null)
					this.blocked_list.insert(app, new AppChooseInfo(
														app_info.get_id(),
														app_info.get_name(),
														pix,
														"",
														0,
														0));
			}
		}
		private void remove_app_from_view (string app) {
			var model = this.exception_list.get_model ();
			TreeIter iter;
			model.get_iter_first (out iter);
			while (true)
			{
				Value can_app_value;
				model.get_value(iter, 2, out can_app_value);
				string can_app = can_app_value.get_string();
				if(app == can_app)
				{
					this.exception_list_store.remove(iter);
					break;
				}
				bool more_entires = model.iter_next(ref iter);
				if(!more_entires)
				{
					break;
				}
			}
		}
	}
//Based on gnome-contacts contacts-cell-renderer-shape.vala
public class ExceptionCellRenderer : CellRenderer {

	private const int PIXBUF_SIZE = 24;
	private const int xspacing = 3; 
	
	private const int default_width = 60;
	private const int renderer_height = 30;
	
	private Widget current_widget;
	
	private Gdk.Pixbuf pixbuf_;
	private string text_;
	
	public Gdk.Pixbuf pixbuf {
			get {
				return pixbuf_;
			}
			set {
				pixbuf_ = value;
			}
	}
	
	public string text {
			get {
				return text_;
			}
			set {
				text_ = value;
			}
	}
	
	public ExceptionCellRenderer () {
		GLib.Object ();
	}
	
	private Pango.Layout get_text_layout (Widget widget,
					Gdk.Rectangle? cell_area,
					CellRendererState flags,
					string text,
					bool bold,
					int size) {
		Pango.Layout layout;
		int xpad;
		var attr_list = new Pango.AttrList ();

		layout = widget.create_pango_layout (text);

		var attr = new Pango.AttrSize (size * Pango.SCALE);
		attr.absolute = 1;
		attr.start_index = 0;
		attr.end_index = attr.start_index + text.length;
		attr_list.insert ((owned) attr);

		if (bold) {
			var desc = new Pango.FontDescription();
			desc.set_weight (Pango.Weight.BOLD);
			var attr_f = new Pango.AttrFontDesc (desc);
			attr_list.insert ((owned) attr_f);
		}
		layout.set_attributes (attr_list);

		get_padding (out xpad, null);

		layout.set_ellipsize (Pango.EllipsizeMode.END);

		Pango.Rectangle rect;
		int width, text_width;

		layout.get_extents (null, out rect);
		text_width = rect.width;

		if (cell_area != null)
			width = (cell_area.width - xpad) * Pango.SCALE;
		else
			width = default_width * Pango.SCALE;

		width = int.min (width, text_width);
		layout.set_width (width);

		Pango.Alignment align;
		if (widget.get_direction () == TextDirection.RTL)
			align = Pango.Alignment.RIGHT;
		else
			align = Pango.Alignment.LEFT;
		layout.set_alignment (align);

		return layout;
	}

	public override void get_size (Widget        widget,
				 Gdk.Rectangle? cell_area,
				 out int       x_offset,
				 out int       y_offset,
				 out int       width,
				 out int       height) {
		x_offset = y_offset = width = height = 0;
		// Not used
	}

	private void do_get_size (Widget       widget,
				Gdk.Rectangle? cell_area,
				Pango.Layout? layout,
				out int       x_offset,
				out int       y_offset) {
		Pango.Rectangle rect;
		int xpad, ypad;

		get_padding (out xpad, out ypad);

		layout.get_pixel_extents (null, out rect);

		if (cell_area != null) {
			rect.width  = int.min (rect.width, cell_area.width - 2 * xpad + xspacing);

		if (widget.get_direction () == TextDirection.RTL)
			x_offset = cell_area.width - (rect.width + xpad);
		else
			x_offset = xpad;

		x_offset = int.max (x_offset, 0);
		} else {
			x_offset = 0;
		}

		y_offset = ypad;
	}


	public override void render (Cairo.Context   cr,
			       Widget          widget,
			       Gdk.Rectangle   background_area,
			       Gdk.Rectangle   cell_area,
			       CellRendererState flags) {
		StyleContext context;
		Pango.Layout text_layout;
		int text_x_offset = 0;
		int text_y_offset = 0;
		int xpad;
		Pango.Rectangle text_rect;

		current_widget = widget;

		context = widget.get_style_context ();
		var font_size = context.get_font (StateFlags.NORMAL).get_size () / Pango.SCALE;
		get_padding (out xpad, null);

		text_layout = get_text_layout (widget, cell_area, flags, text, true, font_size);
		do_get_size (widget, cell_area, text_layout, out text_x_offset, out text_y_offset);
		text_layout.get_pixel_extents (null, out text_rect);
		text_x_offset = text_x_offset - text_rect.x;

		cr.save ();

		Gdk.cairo_rectangle (cr, cell_area);
		cr.clip ();

		Gdk.cairo_set_source_pixbuf (cr, this.pixbuf, cell_area.x, cell_area.y);
		cr.paint ();

		context.render_layout (cr,
				cell_area.x + text_x_offset + this.pixbuf.width+ xspacing ,
				cell_area.y + text_y_offset + 2,
				text_layout);
		cr.restore ();
	}
	
	public override void get_preferred_width (Widget       widget,
					    out int      min_width,
					    out int      nat_width) {
		int xpad;

		get_padding (out xpad, null);

		nat_width = min_width = xpad + default_width;
	}

	public override void get_preferred_height_for_width (Widget       widget,
						       int          width,
						       out int      minimum_height,
						       out int      natural_height) {
		int ypad;

		get_padding (null, out ypad);
		minimum_height = renderer_height + ypad;
		natural_height = renderer_height + ypad;
	}

	public override void get_preferred_height (Widget       widget,
					     out int      minimum_size,
					     out int      natural_size) {
		int min_width;

		get_preferred_width (widget, out min_width, null);
		get_preferred_height_for_width (widget, min_width,
					out minimum_size, out natural_size);
	}
}

public class DeleteHistoryDialog : Gtk.Dialog {

		RadioButton r_hour;
		RadioButton r_day;
		RadioButton r_week;
		RadioButton r_calendar;
		RadioButton r_ever;
		
		private Zeitgeist.Log zg_log;
		
		private CalendarWidget calendar_box;

		public DeleteHistoryDialog (Button del_button) {
			this.set_title (_("Clear Usage Data"));
			this.set_destroy_with_parent (true);
			this.set_skip_taskbar_hint (true);
			this.set_border_width (12);
			this.resizable = false;
			
			zg_log = new Zeitgeist.Log ();
			this.calendar_box = new CalendarWidget(del_button);
			this.set_up_ui ();
		}

		private void set_up_ui () {
			var label = new Gtk.Label(_("Delete records of which files and applications were used:"));
			label.set_line_wrap(true);
			label.set_line_wrap_mode(Pango.WrapMode.WORD);
			label.set_alignment(0, 0.5f);
			
			r_hour = new Gtk.RadioButton.with_label (null, _("In the past hour"));
			r_day = new Gtk.RadioButton.with_label (r_hour.get_group(),_("In the past day"));
			r_week = new Gtk.RadioButton.with_label (r_hour.get_group(),_("In the past week"));
			r_calendar = new Gtk.RadioButton.with_label_from_widget (r_hour, _("From:"));
			r_ever = new Gtk.RadioButton.with_label_from_widget (r_hour, _("From all time"));
			
			var hbox_calendar = new Box (Orientation.HORIZONTAL, 5);
			hbox_calendar.pack_start (r_calendar, false, false, 0);
			hbox_calendar.pack_start (this.calendar_box, false, false, 0);
			
			var vbox = new Box (Orientation.VERTICAL, 5);
			vbox.pack_start (label, false);
			vbox.pack_start (r_hour, false);
			vbox.pack_start (r_day, false);
			vbox.pack_start (r_week, false);
			vbox.pack_start (hbox_calendar, false);
			vbox.pack_start (r_ever, false);
			
			var area = this.get_content_area () as Gtk.Box;
			area.pack_start(vbox, false, false, 0);
			this.add_buttons (Stock.CANCEL, ResponseType.CANCEL, Stock.OK, ResponseType.OK);
		}
		
		public int get_active_radio_button () {
			if (r_hour.get_active ())
				return 0;
			else if (r_day.get_active ())
				return 1;
			else if (r_week.get_active ())
				return 2;
			else if (r_calendar.get_active ())
				return 3;
			else if (r_ever.get_active ())
				return 4;
			else return -1;
		}
		
		public void on_delete_history () {
			this.show_all ();
			int res = this.run();
			if(res == ResponseType.OK) {
				Zeitgeist.TimeRange tr;
				var index = this.get_active_radio_button();
				if (index < 3) {
					int range = 60*60*1000;
					if (index == 0)
						range = 1 * range;
					else if (index == 1)
						range = range*24;
					else if (index == 2)
						range = range * 24 * 7;
					int64 end = Zeitgeist.Timestamp.now ();
					int64 start = end - range;
					tr = new Zeitgeist.TimeRange (start, end);
					get_history.begin (tr);
				}
				else if (index == 3){
					tr = this.calendar_box.get_range();
					get_history.begin (tr);
				}
				else if (index == 4){
					tr = new Zeitgeist.TimeRange.anytime();
					get_history.begin (tr);
				}
			}
			
			this.hide();
		}
		
		private async void get_history(TimeRange tr) {
			Idle.add (get_history.callback, Priority.LOW);
			yield;
			
			var dialog = new Gtk.Dialog();
			dialog.add_button(Stock.CANCEL, ResponseType.CANCEL);
			dialog.add_button(Stock.YES, ResponseType.OK);
			dialog.set_title("");
			
			var label = new Gtk.Label(_("This operation cannot be undone, are you sure you want to delete this activity?"));
			label.set_line_wrap(true);
			label.set_line_wrap_mode(Pango.WrapMode.WORD);
			label.set_padding(9,9);
			((Gtk.Container) dialog.get_content_area ()).add(label);
			
			dialog.set_transient_for((Gtk.Window)this.get_toplevel());
			dialog.set_modal(true);
			dialog.show_all();
			int res = dialog.run();
			dialog.destroy();
			
			if(res == ResponseType.OK) {
				var ptr_arr = new PtrArray ();
				ptr_arr.add (new Zeitgeist.Event ());
				try {
					Array<int> ids = yield zg_log.find_event_ids (tr, (owned) ptr_arr,
							Zeitgeist.StorageState.ANY, 0, 0, null);
					delete_history.begin(ids);
				}
				catch (Error err) {
					warning ("%s", err.message);
				}
			}
			
		}

		private async void delete_history (Array<int>? ids) {
			Idle.add (delete_history.callback, Priority.LOW);
			yield;
			try {
				bool rs = yield zg_log.delete_events(ids, null);
			}
			catch (Error err) {
				warning ("%s", err.message);
			}
		}
	}
}



