/*
 * dialog-employee.c -- Dialog for Employee entry
 * Copyright (C) 2001 Derek Atkins
 * Author: Derek Atkins <warlord@MIT.EDU>
 */

#include "config.h"

#include <gnome.h>

#include "dialog-utils.h"
#include "global-options.h"
#include "gnc-amount-edit.h"
#include "gnc-component-manager.h"
#include "gnc-ui.h"
#include "gnc-gui-query.h"
#include "gnc-ui-util.h"
#include "gnc-engine-util.h"
#include "window-help.h"
#include "dialog-search.h"
#include "search-param.h"

#include "gncAddress.h"
#include "gncEmployee.h"
#include "gncEmployeeP.h"

#include "dialog-employee.h"

#define DIALOG_NEW_EMPLOYEE_CM_CLASS "dialog-new-employee"
#define DIALOG_EDIT_EMPLOYEE_CM_CLASS "dialog-edit-employee"

typedef enum
{
  NEW_EMPLOYEE,
  EDIT_EMPLOYEE
} EmployeeDialogType;

struct _employee_select_window {
  GNCBook *	book;
  QueryNew *	q;
};

struct _employee_window {
  GtkWidget *	dialog;

  GtkWidget *	id_entry;
  GtkWidget *	username_entry;

  GtkWidget *	name_entry;
  GtkWidget *	addr1_entry;
  GtkWidget *	addr2_entry;
  GtkWidget *	addr3_entry;
  GtkWidget *	addr4_entry;
  GtkWidget *	phone_entry;
  GtkWidget *	fax_entry;
  GtkWidget *	email_entry;

  GtkWidget *	language_entry;

  GtkWidget *	workday_amount;
  GtkWidget *	rate_amount;

  GtkWidget *	active_check;

  /* ACL? */

  EmployeeDialogType	dialog_type;
  GUID		employee_guid;
  gint		component_id;
  GNCBook *	book;
  GncEmployee *	created_employee;

};

static GncEmployee *
ew_get_employee (EmployeeWindow *ew)
{
  if (!ew)
    return NULL;

  return gncEmployeeLookup (ew->book, &ew->employee_guid);
}

static void gnc_ui_to_employee (EmployeeWindow *ew, GncEmployee *employee)
{
  GncAddress *addr;

  addr = gncEmployeeGetAddr (employee);

  gnc_suspend_gui_refresh ();

  gncEmployeeBeginEdit (employee);

  gncEmployeeSetID (employee, gtk_editable_get_chars
		    (GTK_EDITABLE (ew->id_entry), 0, -1));
  gncEmployeeSetUsername (employee, gtk_editable_get_chars
		      (GTK_EDITABLE (ew->username_entry), 0, -1));

  gncAddressSetName (addr, gtk_editable_get_chars
		     (GTK_EDITABLE (ew->name_entry), 0, -1));
  gncAddressSetAddr1 (addr, gtk_editable_get_chars
		      (GTK_EDITABLE (ew->addr1_entry), 0, -1));
  gncAddressSetAddr2 (addr, gtk_editable_get_chars
		      (GTK_EDITABLE (ew->addr2_entry), 0, -1));
  gncAddressSetAddr3 (addr, gtk_editable_get_chars
		      (GTK_EDITABLE (ew->addr3_entry), 0, -1));
  gncAddressSetAddr4 (addr, gtk_editable_get_chars
		      (GTK_EDITABLE (ew->addr4_entry), 0, -1));
  gncAddressSetPhone (addr, gtk_editable_get_chars
		      (GTK_EDITABLE (ew->phone_entry), 0, -1));
  gncAddressSetFax (addr, gtk_editable_get_chars
		    (GTK_EDITABLE (ew->fax_entry), 0, -1));
  gncAddressSetEmail (addr, gtk_editable_get_chars
		      (GTK_EDITABLE (ew->email_entry), 0, -1));

  gncEmployeeSetActive (employee, gtk_toggle_button_get_active
			(GTK_TOGGLE_BUTTON (ew->active_check)));
  gncEmployeeSetLanguage (employee, gtk_editable_get_chars
		       (GTK_EDITABLE (ew->language_entry), 0, -1));

  /* Parse and set the workday and rate amounts */
  gncEmployeeSetWorkday (employee, gnc_amount_edit_get_amount
		       (GNC_AMOUNT_EDIT (ew->workday_amount)));
  gncEmployeeSetRate (employee, gnc_amount_edit_get_amount
		       (GNC_AMOUNT_EDIT (ew->rate_amount)));

  gncEmployeeCommitEdit (employee);
  gnc_resume_gui_refresh ();
}

#if 0
static gboolean check_edit_amount (GtkWidget *dialog, GtkWidget *amount,
				   gnc_numeric *min, gnc_numeric *max,
				   const char * error_message)
{
  if (!gnc_amount_edit_evaluate (GNC_AMOUNT_EDIT (amount))) {
    if (error_message)
      gnc_error_dialog_parented (GTK_WINDOW (dialog), error_message);
    return TRUE;
  }
  /* We've got a valid-looking number; check mix/max */
  if (min || max) {
    gnc_numeric val = gnc_amount_edit_get_amount (GNC_AMOUNT_EDIT (amount));
    if ((min && gnc_numeric_compare (*min, val) > 0) ||
	(max && gnc_numeric_compare (val, *max) > 0)) {
      if (error_message)
	gnc_error_dialog_parented (GTK_WINDOW (dialog), error_message);
      return TRUE;
    }
  }
  return FALSE;
}
#endif

static gboolean check_entry_nonempty (GtkWidget *dialog, GtkWidget *entry, 
				      const char * error_message)
{
  const char *res = gtk_entry_get_text (GTK_ENTRY (entry));
  if (safe_strcmp (res, "") == 0) {
    if (error_message)
      gnc_error_dialog_parented (GTK_WINDOW (dialog), error_message);
    return TRUE;
  }
  return FALSE;
}

static void
gnc_employee_window_ok_cb (GtkWidget *widget, gpointer data)
{
  EmployeeWindow *ew = data;

  /* Check for valid id */
  if (check_entry_nonempty (ew->dialog, ew->id_entry,
			    _("The Employee must be given an ID.")))
    return;

  /* Check for valid username */
  if (check_entry_nonempty (ew->dialog, ew->username_entry,
		   _("You must enter a username.")))
    return;

  /* Check for valid username */
  if (check_entry_nonempty (ew->dialog, ew->name_entry,
		   _("You must enter the employee's name.")))
    return;

  /* Make sure we have an address */
  if (check_entry_nonempty (ew->dialog, ew->addr1_entry, NULL) &&
      check_entry_nonempty (ew->dialog, ew->addr2_entry, NULL) &&
      check_entry_nonempty (ew->dialog, ew->addr3_entry, NULL) &&
      check_entry_nonempty (ew->dialog, ew->addr4_entry, NULL)) {
    const char *msg = _("You must enter an address.");
    gnc_error_dialog_parented (GTK_WINDOW (ew->dialog), msg);
    return;
  }

  /* Now save it off */
  {
    GncEmployee *employee = ew_get_employee (ew);
    if (employee) {
      gnc_ui_to_employee (ew, employee);
    }
    ew->created_employee = employee;
    ew->employee_guid = *xaccGUIDNULL ();
  }

  gnc_close_gui_component (ew->component_id);
}

static void
gnc_employee_window_cancel_cb (GtkWidget *widget, gpointer data)
{
  EmployeeWindow *ew = data;

  gnc_close_gui_component (ew->component_id);
}

static void
gnc_employee_window_help_cb (GtkWidget *widget, gpointer data)
{
  char *help_file = "";		/* xxx */

  helpWindow(NULL, NULL, help_file);
}

static void
gnc_employee_window_destroy_cb (GtkWidget *widget, gpointer data)
{
  EmployeeWindow *ew = data;
  GncEmployee *employee = ew_get_employee (ew);

  gnc_suspend_gui_refresh ();

  if (ew->dialog_type == NEW_EMPLOYEE && employee != NULL) {
    gncEmployeeBeginEdit (employee);
    gncEmployeeDestroy (employee);
    ew->employee_guid = *xaccGUIDNULL ();
  }

  gnc_unregister_gui_component (ew->component_id);
  gnc_resume_gui_refresh ();

  g_free (ew);
}

static void
gnc_employee_name_changed_cb (GtkWidget *widget, gpointer data)
{
  EmployeeWindow *ew = data;
  char *name, *id, *fullname, *title;

  if (!ew)
    return;

  name = gtk_entry_get_text (GTK_ENTRY (ew->name_entry));
  if (!name || *name == '\0')
    name = _("<No name>");

  id = gtk_entry_get_text (GTK_ENTRY (ew->id_entry));

  fullname = g_strconcat (name, " (", id, ")", NULL);

  if (ew->dialog_type == EDIT_EMPLOYEE)
    title = g_strconcat (_("Edit Employee"), " - ", fullname, NULL);
  else
    title = g_strconcat (_("New Employee"), " - ", fullname, NULL);

  gtk_window_set_title (GTK_WINDOW (ew->dialog), title);

  g_free (fullname);
  g_free (title);
}

static void
gnc_employee_window_close_handler (gpointer user_data)
{
  EmployeeWindow *ew = user_data;

  gnome_dialog_close (GNOME_DIALOG (ew->dialog));
}

static void
gnc_employee_window_refresh_handler (GHashTable *changes, gpointer user_data)
{
  EmployeeWindow *ew = user_data;
  const EventInfo *info;
  GncEmployee *employee = ew_get_employee (ew);

  /* If there isn't a employee behind us, close down */
  if (!employee) {
    gnc_close_gui_component (ew->component_id);
    return;
  }

  /* Next, close if this is a destroy event */
  if (changes) {
    info = gnc_gui_get_entity_events (changes, &ew->employee_guid);
    if (info && (info->event_mask & GNC_EVENT_DESTROY)) {
      gnc_close_gui_component (ew->component_id);
      return;
    }
  }
}

static gboolean
find_handler (gpointer find_data, gpointer user_data)
{
  const GUID *employee_guid = find_data;
  EmployeeWindow *ew = user_data;

  return(ew && guid_equal(&ew->employee_guid, employee_guid));
}

static EmployeeWindow *
gnc_employee_new_window (GNCBook *bookp,
			 GncEmployee *employee)
{
  EmployeeWindow *ew;
  GladeXML *xml;
  GtkWidget *hbox, *edit;
  GnomeDialog *ewd;
  gnc_commodity *commodity;
  GNCPrintAmountInfo print_info;

  /*
   * Find an existing window for this employee.  If found, bring it to
   * the front.
   */
  if (employee) {
    GUID employee_guid;
    
    employee_guid = *gncEmployeeGetGUID (employee);
    ew = gnc_find_first_gui_component (DIALOG_EDIT_EMPLOYEE_CM_CLASS,
				       find_handler, &employee_guid);
    if (ew) {
      gtk_window_present (GTK_WINDOW(ew->dialog));
      return(ew);
    }
  }
  
  /*
   * No existing employee window found.  Build a new one.
   */
  ew = g_new0 (EmployeeWindow, 1);

  ew->book = bookp;

  /* Find the dialog */
  xml = gnc_glade_xml_new ("employee.glade", "Employee Dialog");
  ew->dialog = glade_xml_get_widget (xml, "Employee Dialog");
  ewd = GNOME_DIALOG (ew->dialog);

  gtk_object_set_data (GTK_OBJECT (ew->dialog), "dialog_info", ew);

  /* default to ok */
  gnome_dialog_set_default (ewd, 0);

  /* Get entry points */
  ew->id_entry = glade_xml_get_widget (xml, "id_entry");
  ew->username_entry = glade_xml_get_widget (xml, "username_entry");

  ew->name_entry = glade_xml_get_widget (xml, "name_entry");
  ew->addr1_entry = glade_xml_get_widget (xml, "addr1_entry");
  ew->addr2_entry = glade_xml_get_widget (xml, "addr2_entry");
  ew->addr3_entry = glade_xml_get_widget (xml, "addr3_entry");
  ew->addr4_entry = glade_xml_get_widget (xml, "addr4_entry");
  ew->phone_entry = glade_xml_get_widget (xml, "phone_entry");
  ew->fax_entry = glade_xml_get_widget (xml, "fax_entry");
  ew->email_entry = glade_xml_get_widget (xml, "email_entry");

  ew->language_entry = glade_xml_get_widget (xml, "language_entry");
  ew->active_check = glade_xml_get_widget (xml, "active_check");

  /* WORKDAY: Value */
  edit = gnc_amount_edit_new();
  gnc_amount_edit_set_evaluate_on_enter (GNC_AMOUNT_EDIT (edit), TRUE);
  print_info = gnc_integral_print_info ();
  print_info.max_decimal_places = 5;
  gnc_amount_edit_set_print_info (GNC_AMOUNT_EDIT (edit), print_info);
  gnc_amount_edit_set_fraction (GNC_AMOUNT_EDIT (edit), 100000);
  ew->workday_amount = edit;
  gtk_widget_show (edit);

  hbox = glade_xml_get_widget (xml, "hours_hbox");
  gtk_box_pack_start (GTK_BOX (hbox), edit, TRUE, TRUE, 0);

  /* RATE: Monetary Value */
  edit = gnc_amount_edit_new();
  commodity = gnc_default_currency ();
  print_info = gnc_commodity_print_info (commodity, FALSE);
  gnc_amount_edit_set_evaluate_on_enter (GNC_AMOUNT_EDIT (edit), TRUE);
  gnc_amount_edit_set_print_info (GNC_AMOUNT_EDIT (edit), print_info);
  gnc_amount_edit_set_fraction (GNC_AMOUNT_EDIT (edit),
                                gnc_commodity_get_fraction (commodity));
  ew->rate_amount = edit;
  gtk_widget_show (edit);

  hbox = glade_xml_get_widget (xml, "rate_hbox");
  gtk_box_pack_start (GTK_BOX (hbox), edit, TRUE, TRUE, 0);

  /* Setup Dialog for Editing */
  gnome_dialog_set_default (ewd, 0);

  /* Attach <Enter> to default button */
  gnome_dialog_editable_enters (ewd, GTK_EDITABLE (ew->id_entry));
  gnome_dialog_editable_enters (ewd, GTK_EDITABLE (ew->username_entry));

  gnome_dialog_editable_enters (ewd, GTK_EDITABLE (ew->name_entry));
  gnome_dialog_editable_enters (ewd, GTK_EDITABLE (ew->addr1_entry));
  gnome_dialog_editable_enters (ewd, GTK_EDITABLE (ew->addr2_entry));
  gnome_dialog_editable_enters (ewd, GTK_EDITABLE (ew->addr3_entry));
  gnome_dialog_editable_enters (ewd, GTK_EDITABLE (ew->addr4_entry));
  gnome_dialog_editable_enters (ewd, GTK_EDITABLE (ew->phone_entry));
  gnome_dialog_editable_enters (ewd, GTK_EDITABLE (ew->fax_entry));
  gnome_dialog_editable_enters (ewd, GTK_EDITABLE (ew->email_entry));

  /* Set focus to username */
  gtk_widget_grab_focus (ew->username_entry);

  /* Setup signals */
  gnome_dialog_button_connect
    (ewd, 0, GTK_SIGNAL_FUNC(gnc_employee_window_ok_cb), ew);
  gnome_dialog_button_connect
    (ewd, 1, GTK_SIGNAL_FUNC(gnc_employee_window_cancel_cb), ew);
  gnome_dialog_button_connect
    (ewd, 2, GTK_SIGNAL_FUNC(gnc_employee_window_help_cb), ew);

  gtk_signal_connect (GTK_OBJECT (ew->dialog), "destroy",
		      GTK_SIGNAL_FUNC(gnc_employee_window_destroy_cb), ew);

  gtk_signal_connect(GTK_OBJECT (ew->id_entry), "changed",
		     GTK_SIGNAL_FUNC(gnc_employee_name_changed_cb), ew);

  gtk_signal_connect(GTK_OBJECT (ew->username_entry), "changed",
		     GTK_SIGNAL_FUNC(gnc_employee_name_changed_cb), ew);

  /* Setup initial values */
  if (employee != NULL) {
    GncAddress *addr;

    ew->dialog_type = EDIT_EMPLOYEE;
    ew->employee_guid = *gncEmployeeGetGUID (employee);

    addr = gncEmployeeGetAddr (employee);

    gtk_entry_set_text (GTK_ENTRY (ew->id_entry), gncEmployeeGetID (employee));
    gtk_entry_set_editable (GTK_ENTRY (ew->id_entry), FALSE);

    gtk_entry_set_text (GTK_ENTRY (ew->username_entry), gncEmployeeGetUsername (employee));

    /* Setup Address */
    gtk_entry_set_text (GTK_ENTRY (ew->name_entry), gncAddressGetName (addr));
    gtk_entry_set_text (GTK_ENTRY (ew->addr1_entry), gncAddressGetAddr1 (addr));
    gtk_entry_set_text (GTK_ENTRY (ew->addr2_entry), gncAddressGetAddr2 (addr));
    gtk_entry_set_text (GTK_ENTRY (ew->addr3_entry), gncAddressGetAddr3 (addr));
    gtk_entry_set_text (GTK_ENTRY (ew->addr4_entry), gncAddressGetAddr4 (addr));
    gtk_entry_set_text (GTK_ENTRY (ew->phone_entry), gncAddressGetPhone (addr));
    gtk_entry_set_text (GTK_ENTRY (ew->fax_entry), gncAddressGetFax (addr));
    gtk_entry_set_text (GTK_ENTRY (ew->email_entry), gncAddressGetEmail (addr));

    gtk_entry_set_text (GTK_ENTRY (ew->language_entry),
			gncEmployeeGetLanguage (employee));

    /* Set toggle buttons */
    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ew->active_check),
                                gncEmployeeGetActive (employee));

    ew->component_id =
      gnc_register_gui_component (DIALOG_EDIT_EMPLOYEE_CM_CLASS,
				  gnc_employee_window_refresh_handler,
				  gnc_employee_window_close_handler,
				  ew);
  } else {
    employee = gncEmployeeCreate (bookp);
    gncEmployeeSetCommodity (employee, commodity);
    ew->employee_guid = *gncEmployeeGetGUID (employee);

    ew->dialog_type = NEW_EMPLOYEE;
    gtk_entry_set_text (GTK_ENTRY (ew->id_entry),
			g_strdup_printf ("%.6lld", gncEmployeeNextID(bookp)));
    ew->component_id =
      gnc_register_gui_component (DIALOG_NEW_EMPLOYEE_CM_CLASS,
				  gnc_employee_window_refresh_handler,
				  gnc_employee_window_close_handler,
				  ew);
  }


  /* I know that employee exists here -- either passed in or just created */
  /* Set the workday and rate values */
  gnc_amount_edit_set_amount (GNC_AMOUNT_EDIT (ew->workday_amount),
			      gncEmployeeGetWorkday (employee));
  gnc_amount_edit_set_amount (GNC_AMOUNT_EDIT (ew->rate_amount),
			      gncEmployeeGetRate (employee));

  /* XXX: Set the ACL */

  gnc_gui_component_watch_entity_type (ew->component_id,
				       GNC_EMPLOYEE_MODULE_NAME,
				       GNC_EVENT_MODIFY | GNC_EVENT_DESTROY);

  gtk_widget_show_all (ew->dialog);

  return ew;
}

EmployeeWindow *
gnc_ui_employee_new (GNCBook *bookp)
{
  EmployeeWindow *ew;

  /* Make sure required options exist */
  if (!bookp) return NULL;

  ew = gnc_employee_new_window (bookp, NULL);

  return ew;
}

EmployeeWindow *
gnc_ui_employee_edit (GncEmployee *employee)
{
  EmployeeWindow *ew;

  if (!employee) return NULL;

  ew = gnc_employee_new_window (gncEmployeeGetBook(employee), employee);

  return ew;
}

/* Functions for employee selection widgets */

static void
edit_employee_cb (gpointer *employee_p, gpointer user_data)
{
  GncEmployee *employee;

  g_return_if_fail (employee_p && user_data);

  employee = *employee_p;

  if (!employee)
    return;

  gnc_ui_employee_edit (employee);
  return;
}

static gpointer
new_employee_cb (gpointer user_data)
{
  struct _employee_select_window *sw = user_data;
  EmployeeWindow *ew;
  
  g_return_val_if_fail (user_data, NULL);

  ew = gnc_ui_employee_new (sw->book);
  return ew_get_employee (ew);
}

static void
free_employee_cb (gpointer user_data)
{
  struct _employee_select_window *sw = user_data;

  g_return_if_fail (sw);

  gncQueryDestroy (sw->q);
  g_free (sw);
}

GNCSearchWindow *
gnc_employee_search (GncEmployee *start, GNCBook *book)
{
  GNCIdType type = GNC_EMPLOYEE_MODULE_NAME;
  struct _employee_select_window *sw;
  QueryNew *q, *q2 = NULL;
  static GList *params = NULL;
  static GList *columns = NULL;
  static GNCSearchCallbackButton buttons[] = { 
    { N_("View/Edit Employee"), edit_employee_cb},
    { NULL },
  };

  g_return_val_if_fail (book, NULL);

  /* Build parameter list in reverse order*/
  if (params == NULL) {
    params = gnc_search_param_prepend (params, _("Employee ID"), NULL, type,
				       EMPLOYEE_ID, NULL);
    params = gnc_search_param_prepend (params, _("Employee Name"), NULL,
				       type, EMPLOYEE_ADDR, ADDRESS_NAME, NULL);
    params = gnc_search_param_prepend (params, _("Employee Username"), NULL,
				       type, EMPLOYEE_USERNAME, NULL);
  }

  /* Build the column list in reverse order */
  if (columns == NULL) {
    columns = gnc_search_param_prepend (columns, _("Name"), NULL, type,
					EMPLOYEE_ADDR, ADDRESS_NAME, NULL);
    columns = gnc_search_param_prepend (columns, _("Username"), NULL, type,
					EMPLOYEE_USERNAME, NULL);
    columns = gnc_search_param_prepend (columns, _("ID #"), NULL, type,
					EMPLOYEE_ID, NULL);
  }

  /* Build the queries */
  q = gncQueryCreateFor (type);
  gncQuerySetBook (q, book);

#if 0
  if (start) {
    q2 = gncQueryCopy (q);
    gncQueryAddGUIDMatch (q2, g_slist_prepend (NULL, QUERY_PARAM_GUID),
			  gncEmployeeGetGUID (start), QUERY_AND);
  }
#endif

  /* launch select dialog and return the result */
  sw = g_new0 (struct _employee_select_window, 1);
  sw->book = book;
  sw->q = q;

  return gnc_search_dialog_create (type, params, columns, q, q2,
				   buttons, NULL, new_employee_cb,
				   sw, free_employee_cb);
}

gpointer gnc_employee_edit_new_select (gpointer bookp, gpointer employee,
				       GtkWidget *toplevel)
{
  gnc_employee_search (employee, bookp); /* XXX */
  return employee;
}

gpointer gnc_employee_edit_new_edit (gpointer bookp, gpointer v,
				     GtkWidget *toplevel)
{
  GncEmployee *employee = v;

  g_return_val_if_fail (employee != NULL, NULL);

  gnc_ui_employee_edit (employee);
  return employee;
}
