/* 
   MultiSync Backup Plugin - Backup your PIM data
   Copyright (C) 2002-2003 Bo Lincoln <lincoln@lysator.liu.se>

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License version 2 as
   published by the Free Software Foundation;

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
   SOFTWARE IS DISCLAIMED.
*/

/*
 *  $Id: gui.c,v 1.5 2003/06/28 11:23:25 lincoln Exp $
 */

#include <stdlib.h>
#include <glib.h>
#include <gmodule.h>
#include <gtk/gtkmain.h>
#include <gtk/gtksignal.h>
#include <multisync.h>
#include <dirent.h>
#include "backup_plugin.h"
#include "gui.h"
#include "interface.h"
#include "support.h"
#include <iconv.h>

GtkWidget* backupwindow = NULL;
backup_connection *backupconn = NULL;

gboolean backup_find_model_iter(GtkTreeModel *model, GtkTreeIter *iter,
				int pos, gpointer data) {
  int n = 0;
  while (gtk_tree_model_iter_nth_child(model, iter, NULL, n)) {
    gpointer nodedata = NULL;
    gtk_tree_model_get (model, iter, pos, &nodedata, -1);
    if (nodedata == data)
      return(TRUE);
    n++;
  }
  return(FALSE);
}

char *backup_conv_charset(char *value, char *from, char* to) {
  char *ret = NULL;
  iconv_t ic;
  ic = iconv_open(to, from);
  if (ic >= 0) {
    char *utfvalue = g_malloc0(256);
    size_t inbytes = strlen(value);
    size_t outbytes = 256;
    char *inbuf = value, *outbuf = utfvalue;
    iconv(ic, &inbuf, &inbytes, &outbuf, &outbytes);
    ret = utfvalue;
    iconv_close(ic);
  }
  return(ret);
}

void backup_show_list(void) {
  GtkListStore *backupstore = NULL;
  char *columns[] = {NULL, NULL, NULL, NULL, NULL};
  int t;

  backupstore = g_object_get_data(G_OBJECT(backupwindow), "backupstore");
  gtk_list_store_clear(backupstore);
  for (t = 0; t < g_list_length(backupconn->entries); t++) {
    backup_object *entry;
    entry = g_list_nth_data(backupconn->entries, t);
    if (entry) {
      GtkTreeIter   iter;
      char *fname;
      FILE *f;
      char buf[32768];
      char *summ = NULL;
      int row;

      columns[1] = (entry->object_type==SYNC_OBJECT_TYPE_CALENDAR?"Event":
		    (entry->object_type==SYNC_OBJECT_TYPE_TODO?"ToDo":
		     (entry->object_type==SYNC_OBJECT_TYPE_PHONEBOOK?"Contact":"Unknown")));
      switch(entry->type) {
      case BACKUP_TYPE_DELETED:
	columns[0] = "Deleted";
	break;
      case BACKUP_TYPE_RESTORE:
	columns[0] = "To be restored";
	break;
      case BACKUP_TYPE_REBACKUP:
	columns[0] = "Backup again";
	break;
      case BACKUP_TYPE_SAVED:
      default:
	columns[0] = "";
	break;
      }
      
      fname = g_strdup_printf("%s/%s", backupconn->backupdir, entry->uid);
      if ((f = fopen(fname, "r"))) {
	buf[32767] = 0;
	fread(buf, 1, 32767, f);
	fclose(f);
	
	switch(entry->object_type) {
	case SYNC_OBJECT_TYPE_CALENDAR:
	case SYNC_OBJECT_TYPE_TODO:
	  if ((summ = backup_get_entry_data(buf, "SUMMARY")))
	    columns[2] = summ;
	  else
	    columns[2] = "No summary";
	  break;
	case SYNC_OBJECT_TYPE_PHONEBOOK:
	  if ((summ = backup_get_entry_data(buf, "FN")))
	    columns[2] = summ;
	  else if ((summ = backup_get_entry_data(buf, "N")))
	    columns[2] = summ;
	  else
	    columns[2] = "No summary";
	  break;
	default:
	  columns[2] = "No information";
	}
      } else
	columns[2] = "No information";
      g_free(fname);
      columns[3] = entry->uid;
      columns[2] = summ;
	  
      gtk_list_store_append (backupstore, &iter);
      gtk_list_store_set(backupstore, &iter, 0, columns[0], 1, columns[1],
			 2, columns[2], 3, columns[3], 4, entry, -1);
      if (summ)
	g_free(summ);
    }
  }
}

GtkWidget* open_option_window(sync_pair *pair, connection_type type) {
  if (!backupwindow) {  
    GtkListStore *backupstore;
    GtkTreeView *backuplist;
    GtkCellRenderer *renderer = gtk_cell_renderer_text_new ();
    GtkTreeSelection *select;
    GtkTreeViewColumn *column;

    backupwindow = create_backup_window();
    backupstore = gtk_list_store_new(5, G_TYPE_STRING, G_TYPE_STRING,
				     G_TYPE_STRING, G_TYPE_STRING, 
				     G_TYPE_POINTER);
    backuplist = GTK_TREE_VIEW(lookup_widget(backupwindow, 
					     "backuplist"));  
    gtk_tree_view_set_model(backuplist, GTK_TREE_MODEL(backupstore));
    g_object_set_data(G_OBJECT(backupwindow), "backupstore", backupstore);
    g_object_unref(G_OBJECT(backupstore));
    column = gtk_tree_view_column_new_with_attributes("Status", renderer, 
						      "text", 0, NULL);
    gtk_tree_view_column_set_min_width(column, 50);
    gtk_tree_view_column_set_reorderable (column, TRUE);
    gtk_tree_view_column_set_sort_column_id (column, 0);
    gtk_tree_view_column_set_resizable(column, TRUE);
    gtk_tree_view_append_column (backuplist, column);
    column = gtk_tree_view_column_new_with_attributes("Type", renderer, 
						      "text", 1, NULL);
    gtk_tree_view_column_set_min_width(column, 50);
    gtk_tree_view_column_set_reorderable (column, TRUE);
    gtk_tree_view_column_set_sort_column_id (column, 1);
    gtk_tree_view_column_set_resizable(column, TRUE);
    gtk_tree_view_append_column (backuplist, column);
    column = gtk_tree_view_column_new_with_attributes("Summary", renderer, 
						      "text", 2, NULL);
    gtk_tree_view_column_set_min_width(column, 200);
    gtk_tree_view_column_set_reorderable (column, TRUE);
    gtk_tree_view_column_set_sort_column_id (column, 2);
    gtk_tree_view_column_set_resizable(column, TRUE);
    gtk_tree_view_append_column (backuplist, column);
    column = gtk_tree_view_column_new_with_attributes("ID", renderer, 
						      "text", 3, NULL);
    gtk_tree_view_column_set_min_width(column, 100);
    gtk_tree_view_column_set_reorderable (column, TRUE);
    gtk_tree_view_column_set_sort_column_id (column, 3);
    gtk_tree_view_column_set_resizable(column, TRUE);
    gtk_tree_view_append_column (backuplist, column);

    select = gtk_tree_view_get_selection (GTK_TREE_VIEW (backuplist));
    gtk_tree_selection_set_mode (select, GTK_SELECTION_MULTIPLE);

    // The current active connection, if exists
    backupconn = g_malloc0(sizeof(backup_connection));
    backupconn->sync_pair = pair;
    backupconn->conntype = type;
    backup_load_state(backupconn);
    backup_load_entries(backupconn);
    
    if (backupconn->backupdir)
      gtk_entry_set_text(GTK_ENTRY(lookup_widget(backupwindow, "direntry")),
			 backupconn->backupdir);
    backup_show_list();
    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(lookup_widget(backupwindow, "harddeletebutton")), backupconn->harddelete);

    gtk_widget_show (backupwindow);
  }
  return(backupwindow);
}

void backup_get_selected_iter (GtkTreeModel *model, GtkTreePath *path,
			       GtkTreeIter *iter, gpointer data) {
  backup_object *entry = NULL;
  GList **entries = data;
  
  gtk_tree_model_get (model, iter, 4, &entry, -1);
  *entries = g_list_append(*entries, entry);
}

// Return a GList of selected backup_entry's. Free it using g_list_free().
GList *backup_get_selected(void) {
  GtkTreeSelection *select;
  GtkTreeIter iter;
  GtkTreeModel *model;
  GList *entries = NULL;
  sync_pair *pair = NULL;

  select = gtk_tree_view_get_selection (GTK_TREE_VIEW(lookup_widget(backupwindow, "backuplist")));
  gtk_tree_selection_selected_foreach (select, backup_get_selected_iter,
				       &entries);
  return(entries);
}


void backup_restore_selected(void) {
  int t;
  GtkListStore *backupstore = g_object_get_data(G_OBJECT(backupwindow), 
					       "backupstore");
  GList *selected = backup_get_selected();

  for (t = 0; t < g_list_length(selected); t++) {
    backup_object *entry = g_list_nth_data(selected, t);
    if (entry) {
      GtkTreeIter iter;
      int row;
      entry->type = BACKUP_TYPE_RESTORE;
      if (backup_find_model_iter(GTK_TREE_MODEL(backupstore), 
				 &iter, 4, entry)) {
	gtk_list_store_set(backupstore, &iter, 0, "To be restored", -1);
      }
    }
  }
  g_list_free(selected);
}

void backup_restore_all(void) {
  int t;
  GtkListStore *backupstore = g_object_get_data(G_OBJECT(backupwindow), 
						"backupstore");
  
  for (t = 0; t < g_list_length(backupconn->entries); t++) {
    backup_object *entry = g_list_nth_data(backupconn->entries, t);
    if (entry) {
      GtkTreeIter iter;
      int row;
      entry->type = BACKUP_TYPE_RESTORE;
      if (backup_find_model_iter(GTK_TREE_MODEL(backupstore), 
				 &iter, 4, entry)) {
	gtk_list_store_set(backupstore, &iter, 0, "To be restored", -1);
      }
    }
  }
}

void backup_window_closed(void) {
  sync_plugin_window_closed();
  backup_free_connection(backupconn);
  backupwindow = NULL;
  backupconn = NULL;
}

void backup_cancel(void) {
  gtk_widget_destroy(backupwindow);
  backup_window_closed();
}


void backup_ok(void) {
  if (backupconn->backupdir)
    g_free(backupconn->backupdir);
  backupconn->backupdir = g_strdup(gtk_entry_get_text(GTK_ENTRY(lookup_widget(backupwindow, "direntry"))));
  backupconn->harddelete = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(backupwindow, "harddeletebutton")));

  gtk_widget_destroy(backupwindow);
  if (backupconn) {
    backup_save_entries(backupconn);
    backup_save_state(backupconn);
  }
  backup_window_closed();
}

void backup_delete_ask(void) {
  int t;
  GtkListStore *backupstore = g_object_get_data(G_OBJECT(backupwindow), 
					       "backupstore");
  gboolean allok = TRUE;
  GList *selected = backup_get_selected();

  for (t = 0; t < g_list_length(selected); t++) {
    backup_object *entry = g_list_nth_data(selected, t);
    if (entry) {
      if (entry->type != BACKUP_TYPE_DELETED) {
	allok = FALSE;
      }
    }
  }
  if (!allok) {
    backup_show_msg("All selected files must be deleted in the\ndatabase on the other side before they can be removed from the backup.");
    g_list_free(selected);
    return;
  }
  if (backup_show_question("Are you sure you want to delete\nthe selected files from the backup?")) {
    // Delete
    // FIXME: Removing several rows does not work well.
    for (t = 0; t < g_list_length(selected); t++) {
      GtkTreeIter iter;
      backup_object *entry = g_list_nth_data(selected,t);
      if (entry) {
	entry->type = BACKUP_TYPE_RESTORE;
	if (backup_find_model_iter(GTK_TREE_MODEL(backupstore), 
				   &iter, 4, entry))
	  gtk_list_store_remove(backupstore, &iter);
	backup_hard_delete(backupconn, entry);
      }
    }
    // Voids cancelability...
    backup_save_entries(backupconn);
  }
  g_list_free(selected);
}

void backup_show_msg(char *msg) {
  GtkWidget *backup_message;
  backup_message = gnome_message_box_new(msg,
					 GNOME_MESSAGE_BOX_INFO,
					 GNOME_STOCK_BUTTON_OK, NULL);
  gtk_window_set_title (GTK_WINDOW (backup_message), "Backup plugin");
  gtk_window_set_modal(GTK_WINDOW(backup_message), TRUE);
  gtk_widget_show(backup_message);
}

gboolean backup_show_question(char *msg) {
  GtkWidget *backup_message;
  backup_message = gnome_message_box_new(msg,
					 GNOME_MESSAGE_BOX_QUESTION,
					 GNOME_STOCK_BUTTON_CANCEL,
					 GNOME_STOCK_BUTTON_OK, NULL);
  gtk_window_set_title (GTK_WINDOW (backup_message), "Backup plugin");
  gtk_window_set_modal(GTK_WINDOW(backup_message), TRUE);
  gtk_widget_show(backup_message);
  return(gnome_dialog_run(GNOME_DIALOG(backup_message))==1);
}

void backup_rebackup_all(void) {
  backupconn->rebackupall = TRUE;
  backup_show_msg("The full database will backed up upon next synchronization.");
}
