(**************************************************************************)
(*                   Cameleon                                             *)
(*                                                                        *)
(*      Copyright (C) 2002 Institut National de Recherche en Informatique et   *)
(*      en Automatique. All rights reserved.                              *)
(*                                                                        *)
(*      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  *)
(*      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., 59 Temple Place, Suite 330, Boston, MA          *)
(*      02111-1307  USA                                                   *)
(*                                                                        *)
(*      Contact: Maxence.Guesdon@inria.fr                                *)
(**************************************************************************)

(** Gui. *)

open Dbf_types.Current

module M = Dbf_messages
module C = Configwin
module Mi = Dbf_misc

let copy_col_dbms (obj,d) =
  (obj, { d with col_key = d.col_key })

let copy_column c =
  { c with col_dbms = List.map copy_col_dbms c.col_dbms }

let copy_table t = 
  { t with
    ta_columns = List.map copy_column t.ta_columns ;
  }

(** Return true if the table was modified (button ok pressed).*)
let edit_table t =
  let p_name = C.string ~f: (fun s -> t.ta_name <- s) M.name t.ta_name in
  let p_comment = C.text ~expand: true ~f: (fun s -> t.ta_comment <- s) M.comment t.ta_comment in
  (C.simple_get t.ta_name [p_name ; p_comment]) = C.Return_ok

class gui (data : Dbf_data.data) =
  object (self)
    inherit Dbf_gui_base.gui (List.map (fun d -> d#name) data#dbms) ()

    val mutable columns = ([] : Dbf_types.Current.column list)
    val mutable tables = ([] : Dbf_types.Current.table list)
    val mutable selected_table = None
    val mutable selected_column = None

    method save = data#save

    method insert_table t =
      ignore (wlist_tables#append [t.ta_name])

    method insert_column c =
      ignore (wlist_cols#append 
		(["" ; "" ; c.col_name ; c.col_type_ml] @
		 (List.map 
		    (fun d -> 
		      let (v,_,_) = 
			try (List.assoc d#dbms c.col_dbms).col_type_sql
			with Not_found -> "", None, None
		      in
		      v
		    )
		    data#dbms
		 )
		)
	     );
      if c.col_index then
	wlist_cols#set_cell ~pixmap: (Dbf_icons.gdk_pix Dbf_icons.icon_index)
	  (wlist_cols#rows - 1) 0;
      if c.col_nullable then
	wlist_cols#set_cell ~pixmap: (Dbf_icons.gdk_pix Dbf_icons.icon_nullable)
	  (wlist_cols#rows - 1) 1

    method update_tables l =
      tables <- (Dbf_misc.sort_tables_list l);
      selected_table <- None ;
      wlist_tables#freeze ();
      wlist_tables#clear ();
      List.iter self#insert_table tables;
      GToolbox.autosize_clist wlist_tables;
      wlist_tables#thaw ()
      
    method update_columns l =
      columns <- Dbf_misc.sort_columns_list l;
      selected_column <- None;
      wlist_cols#freeze ();
      wlist_cols#clear ();
      List.iter self#insert_column columns;
      GToolbox.autosize_clist wlist_cols;
      wlist_cols#thaw ()

    method update_info =
      wlist_cols#clear ();
      match selected_table with
	None -> ()
      |	Some t ->
	  self#update_columns t.ta_columns

    method update = 
      self#update_tables data#tables;

    method table_selected t =
      selected_table <- Some t;
      self#update_info

    method table_unselected =
      selected_table <- None;
      self#update_info

    method column_selected c =
      selected_column <- Some c

    method column_unselected =
      selected_column <- None

    method add_table =
      let t = { ta_name = "" ; ta_comment = "" ;
		ta_columns = [] ;
		ta_atts = [] ; ta_indexes = [] }
      in
      if edit_table t then
	(
	 try
	   data#add_table t;
	   self#update
	 with
	   Failure s ->
	     GToolbox.message_box M.error s
	)

    method copy_selected_table =
      match selected_table with
	None -> ()
      |	Some t ->
	  let t2 = copy_table t in
	  t2.ta_name <- Dbf_messages.table_copy t.ta_name;
	  (
	   try
	     data#add_table t2;
	     self#update
	   with
	     Failure s ->
	       GToolbox.message_box M.error s
	  )

    method edit_selected_table =
      match selected_table with
	None -> ()
      |	Some t ->
	  if edit_table t then self#update

    method remove_selected_table =
      match selected_table with
	None -> ()
      |	Some t ->
	  let rep = GToolbox.question_box M.mnRemove
	      [M.yes ; M.no] (M.q_remove_table t.ta_name) 
	  in
	  if rep = 1 then
	    (
	     data#del_table t;
	     self#update
	    )

    method add_column =
      match selected_table with
	None -> ()
      |	Some t ->
	  let c = {
	    col_name = "" ;
	    col_comment = "" ;
	    col_type_ml = "" ;
	    col_nullable = true ;
	    col_index = false ;
	    col_dbms = []
	  }	
	  in
	  if Dbf_gui_col.edit_column data c then
	    (
	     try
	       data#add_column t c;
	       self#update_columns t.ta_columns
	     with
	       Failure s ->
		 GToolbox.message_box M.error s
	    )

    method edit_selected_column =
      match selected_table with
	None -> ()
      |	Some t ->
	  match selected_column with
	    None -> ()
	  |	Some c ->
	      if Dbf_gui_col.edit_column data c then
		self#update_columns t.ta_columns

    method remove_selected_column =
      match selected_table with
	None -> ()
      |	Some t ->
	  match selected_column with
	    None -> ()
	  |	Some c ->
	      let rep = GToolbox.question_box M.mnRemove
		  [M.yes ; M.no] (M.q_remove_column c.col_name) 
	      in
	      if rep = 1 then
		(
		 data#del_column t c;
		 self#update_columns t.ta_columns
		)

    method init_window (w : GWindow.window) =
      w#add_accel_group accelgroup

    initializer
      let check_double_click f event =
	(
         match event with 
           None -> ()
         | Some ev -> 
	     let t = GdkEvent.get_type ev in
             match t with
               `TWO_BUTTON_PRESS -> f ()
             | _ -> ()
        )
      in
      let f_select_table ~row ~column ~event =
        try 
	  self#table_selected (List.nth tables row);
	  check_double_click (fun () -> self#edit_selected_table) event
        with Failure _ -> self#table_unselected
      in
      let f_unselect_table ~row ~column ~event = 
	self#table_unselected;
	check_double_click (fun () -> self#edit_selected_table) event
      in
      ignore (wlist_tables#connect#select_row f_select_table);
      ignore (wlist_tables#connect#unselect_row f_unselect_table);

      let f_select_column ~row ~column ~event =
        try
	  self#column_selected (List.nth columns row) ;
	  check_double_click (fun () -> self#edit_selected_column) event
        with Failure _ -> self#column_unselected
      in
      let f_unselect_column ~row ~column ~event = 
	self#column_unselected;
	check_double_click (fun () -> self#edit_selected_column) event
      in
      ignore (wlist_cols#connect#select_row f_select_column);
      ignore (wlist_cols#connect#unselect_row f_unselect_column);

      ignore (itemQuit#connect#activate box#destroy);
      ignore (itemSave#connect#activate (fun () -> self#save));
      ignore (itemAbout#connect#activate 
		(fun () -> GToolbox.message_box M.mnAbout M.about));

      ignore (itemAddTable#connect#activate (fun () -> self#add_table));
      ignore (itemEditTable#connect#activate (fun () -> self#edit_selected_table));
      ignore (itemRemoveTable#connect#activate (fun () -> self#remove_selected_table));
      ignore (itemCopyTable#connect#activate (fun () -> self#copy_selected_table));

      ignore (itemAddColumn#connect#activate (fun () -> self#add_column));
      ignore (itemEditColumn#connect#activate (fun () -> self#edit_selected_column));
      ignore (itemRemoveColumn#connect#activate (fun () -> self#remove_selected_column));

      wlist_cols#set_column ~title_active: false ~resizeable: false
	~min_width: 16 ~max_width: 16 0;
      wlist_cols#set_column ~title_active: false ~resizeable: false
	~min_width: 16 ~max_width: 16 1;

      self#update
  end
