/*
 * BackupBox.vala
 *
 * Copyright 2012-2018 Tony George <teejeetech@gmail.com>
 *
 * 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 Gee;

#if XAPP
using XApp;
#endif

using TeeJee.Logging;
using TeeJee.FileSystem;
using TeeJee.JsonHelper;
using TeeJee.ProcessHelper;
using TeeJee.GtkHelper;
using TeeJee.System;
using TeeJee.Misc;

class BackupBox : Gtk.Box{
	private Gtk.Box details_box;
	private Gtk.Spinner spinner;
	public Gtk.Label lbl_msg;
	public Gtk.Label lbl_status;
	public Gtk.Label lbl_remaining;
	public Gtk.ProgressBar progressbar;
	public Gtk.Label lbl_unchanged;
	public Gtk.Label lbl_created;
	public Gtk.Label lbl_deleted;
	public Gtk.Label lbl_modified;
	public Gtk.Label lbl_checksum;
	public Gtk.Label lbl_size;
	public Gtk.Label lbl_timestamp;
	public Gtk.Label lbl_permissions;
	public Gtk.Label lbl_owner;
	public Gtk.Label lbl_group;

	private Gtk.Window parent_window;

	private bool thread_is_running = false;
	private bool thread_status_success = false;

	public BackupBox (Gtk.Window _parent_window) {

		log_debug("BackupBox: BackupBox()");
		
		//base(Gtk.Orientation.VERTICAL, 6); // issue with vala
		GLib.Object(orientation: Gtk.Orientation.VERTICAL, spacing: 6); // work-around
		parent_window = _parent_window;
		margin = 12;
		
		add_label_header(this, _("Creating Snapshot..."), true);

		add_progress_area();

		// add count labels ---------------------------------
		
		Gtk.SizeGroup sg_label = null;
		Gtk.SizeGroup sg_value = null;

		details_box = new Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6);
		add(details_box);

		var label = add_label(details_box, _("File and directory counts:"), true);
		label.margin_bottom = 6;
		label.margin_top = 12;
		
		lbl_unchanged = add_count_label(details_box, _("No Change"), ref sg_label, ref sg_value);
		lbl_created = add_count_label(details_box, _("Created"), ref sg_label, ref sg_value);
		lbl_deleted = add_count_label(details_box, _("Deleted"), ref sg_label, ref sg_value);
		lbl_modified = add_count_label(details_box, _("Changed"), ref sg_label, ref sg_value, 12);

		label = add_label(details_box, _("Changed items:"), true);
		label.margin_bottom = 6;
		
		lbl_checksum = add_count_label(details_box, _("Checksum"), ref sg_label, ref sg_value);
		lbl_size = add_count_label(details_box, _("Size"), ref sg_label, ref sg_value);
		lbl_timestamp = add_count_label(details_box, _("Timestamp"), ref sg_label, ref sg_value);
		lbl_permissions = add_count_label(details_box, _("Permissions"), ref sg_label, ref sg_value);
		lbl_owner = add_count_label(details_box, _("Owner"), ref sg_label, ref sg_value);
		lbl_group = add_count_label(details_box, _("Group"), ref sg_label, ref sg_value, 24);

		lbl_deleted.sensitive = false;

		log_debug("BackupBox: BackupBox(): exit");
    }

	private void add_progress_area(){
		
		var hbox_status = new Gtk.Box(Orientation.HORIZONTAL, 6);
		add (hbox_status);
		
		spinner = new Gtk.Spinner();
		spinner.active = true;
		hbox_status.add(spinner);
		
		//lbl_msg
		lbl_msg = add_label(hbox_status, _("Preparing..."));
		lbl_msg.hexpand = true;
		lbl_msg.ellipsize = Pango.EllipsizeMode.END;
		lbl_msg.max_width_chars = 50;

		lbl_remaining = add_label(hbox_status, "");

		//progressbar
		progressbar = new Gtk.ProgressBar();
		add (progressbar);

		//lbl_status
		lbl_status = add_label(this, "");
		lbl_status.ellipsize = Pango.EllipsizeMode.MIDDLE;
		lbl_status.max_width_chars = 45;
		lbl_status.margin_bottom = 6;
	}
	
	private Gtk.Label add_count_label(Gtk.Box box, string text,
		ref Gtk.SizeGroup? sg_label, ref Gtk.SizeGroup? sg_value,
		int add_margin_bottom = 0){
			
		var hbox = new Gtk.Box(Orientation.HORIZONTAL, 6);
		box.add (hbox);

		var label = add_label(hbox, text + ":");
		label.xalign = (float) 1.0;
		label.margin_start = 12;
		label.margin_end = 6;
		var text_label = label;
		
		if (add_margin_bottom > 0){
			label.margin_bottom = add_margin_bottom;
		}

		// add to size group
		if (sg_label == null){
			sg_label = new Gtk.SizeGroup(SizeGroupMode.HORIZONTAL);
		}
		sg_label.add_widget(label);

		label = add_label(hbox, "");
		label.xalign = (float) 0.0;

		if (add_margin_bottom > 0){
			label.margin_bottom = add_margin_bottom;
		}

		// add to size group
		if (sg_value == null){
			sg_value = new Gtk.SizeGroup(SizeGroupMode.HORIZONTAL);
		}
		sg_value.add_widget(label);

		label.notify["sensitive"].connect(()=>{
			text_label.sensitive = label.sensitive;
		});

		return label;
	}

	public bool take_snapshot(){

		try {
			thread_is_running = true;
			new Thread<void>.try ("snapshot-taker", () => {take_snapshot_thread();});
		}
		catch (Error e) {
			log_error (e.message);
			return false;
		}

		if (App.btrfs_mode){
			
			while (thread_is_running){
				
				gtk_do_events();
				sleep(200);

				#if XAPP
				XApp.set_window_progress_pulse(parent_window, true);
				#endif
			}

			#if XAPP
			XApp.set_window_progress_pulse(parent_window, false);
			#endif
		}
		else{
			
			//string last_message = "";
			int wait_interval_millis = 100;
			int status_line_counter = 0;
			int status_line_counter_default = 1000 / wait_interval_millis;
			string status_line = "";
			string last_status_line = "";
			int remaining_counter = 10;

			while (thread_is_running){
                string task_status_line;
                double fraction;
                string task_stat_time_remaining;

				bool checking = App.space_check_task != null;

				details_box.visible = !checking;

                if (checking)
                {
                    task_status_line = App.space_check_task.status_line;
                    fraction = App.space_check_task.progress;
                    task_stat_time_remaining = App.space_check_task.stat_time_remaining;
                }
                else
                {
                    task_status_line = App.task.status_line;
                    fraction = App.task.progress;
                    task_stat_time_remaining = App.task.stat_time_remaining;
                }

				status_line = escape_html(task_status_line);
				if (status_line != last_status_line){
					lbl_status.label = status_line;
					last_status_line = status_line;
					status_line_counter = status_line_counter_default;
				}
				else{
					status_line_counter--;
					if (status_line_counter < 0){
						status_line_counter = status_line_counter_default;
						lbl_status.label = "";
					}
				}

				// time remaining
				remaining_counter--;
				if (remaining_counter == 0){
					lbl_remaining.label =
						task_stat_time_remaining + " " + _("remaining");

					remaining_counter = 10;
				}	
				
				if (fraction < 0.99){
					progressbar.fraction = fraction;
					#if XAPP
					XApp.set_window_progress(parent_window, (int)(fraction * 100.0));
					#endif
				}

				lbl_msg.label = escape_html(App.progress_text);

				if (!checking)
				{
					lbl_unchanged.label = "%'d".printf(App.task.count_unchanged);
					lbl_created.label = "%'d".printf(App.task.count_created);
					lbl_deleted.label = "%'d".printf(App.task.count_deleted);
					lbl_modified.label = "%'d".printf(App.task.count_modified);
					lbl_checksum.label = "%'d".printf(App.task.count_checksum);
					lbl_size.label = "%'d".printf(App.task.count_size);
					lbl_timestamp.label = "%'d".printf(App.task.count_timestamp);
					lbl_permissions.label = "%'d".printf(App.task.count_permissions);
					lbl_owner.label = "%'d".printf(App.task.count_owner);
					lbl_group.label = "%'d".printf(App.task.count_group);
				}

				gtk_do_events();

				sleep(100);
				//gtk_do_events();
			}

			#if XAPP
			XApp.set_window_progress(parent_window, 0);
			#endif
		}

		return thread_status_success;

		//TODO: low: check if snapshot was created successfully.
	}
	
	private void take_snapshot_thread(){
		
		thread_status_success = App.create_snapshot(true,parent_window);
		thread_is_running = false;
	}
}
