//*****************************************************************************************
// Truevision - a 3d modeler for gnome and povray
//
// objectlist.h
//
// Vincent LE PRINCE <vincentleprince@users.sourceforge.net>
// Copyright (C) 2000-2005 Vincent LE PRINCE
// This file is part of the TRUEVISION Package

//   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., 675 Mass Ave, Cambridge, MA 02139, USA.  */ 
//*******************************************************************************************
#ifndef TV_OBJLIST_H
#define TV_OBJLIST_H
using namespace std;
#include <vector>
#include "main.h"
#include "object3d.h"
#include "glview.h"
#include "camera.h"
#include "objectlayer.h"


//************************************************************
// Constants
//************************************************************
#define OBJLIST_DEF ObjectList *objlist = (ObjectList*)(app_ref->obj3dlist);

// Object manipulation buttons count
#define OBJ_BUTTONS 10

// Layer manipulation buttons count
#define LAY_BUTTONS 6


//************************************************************
// 3D objects definition structure
//
// Object defiintion for creation tree
//************************************************************
struct obj3ddef {
	const char *name;
	Object3DType type;
	const char *icon;
	const char *description;
	//bool from_library;
	//const char *path;
	//const char *filename;
	//bool from_plugin;
};
typedef obj3ddef Object3DDef;
#define OBJ3D_INLINE_DEF( name, type, icon, description ) { N_(name), type, icon, N_(description) }




//************************************************************
// Class Object List
//
// Manage a layer list
// plus a global list of all objects
// plus a list of linkable objects names ( references )
// plus a list of available lights for opengl lightning preview
//************************************************************
class ObjectList : public app_object {
	#define SENDER ((ObjectList*)data)
	friend void sign_layer_select( GtkTreeSelection *selection, gpointer data ) { SENDER->select_layer( selection ); }	
	friend void sign_select_lbuttons_clicked( GtkWidget *wid, gpointer data ) { SENDER->layers_buttons_clicked(wid); }	
	friend gboolean sign_layer_view_clicked( GtkWidget *wid, GdkEventButton *ev, gpointer data ) { SENDER->layer_view_clicked(ev); return FALSE; }
	
	friend void sign_object_select( GtkTreeSelection *selection, gpointer data ) { SENDER->select_object( selection ); }
	friend void sign_select_buttons_clicked( GtkWidget *wid, gpointer data ) { SENDER->select_buttons_clicked(wid); }	
	friend gboolean sign_object_view_clicked( GtkWidget *wid, GdkEventButton *ev, gpointer data ) { SENDER->object_view_clicked(ev); return FALSE; }
	friend void sign_object_view_double_clicked( GtkTreeView *View, GtkTreePath *path, GtkTreeViewColumn *col, gpointer data) { SENDER->object_view_double_clicked();  }

	friend void sign_create_button_clicked( GtkWidget *wid, gpointer data ) { SENDER->create_button_clicked(); }	
	friend void sign_create_tree_select( GtkTreeSelection *selection, gpointer data ) { SENDER->create_tree_select(selection); }		
	friend void sign_create_tree_click( GtkTreeView *View, GtkTreePath *path, GtkTreeViewColumn *col, gpointer data ) { SENDER->create_tree_click(  ); }		
	
	friend void sign_object_drag(GtkWidget *widget, GdkDragContext *dc, GtkSelectionData *selection_data, guint info, guint t, gpointer data  ) { SENDER->object_drag( dc, selection_data ); }			
	friend void sign_object_drop_on_layer( GtkWidget *widget, GdkDragContext *dc, gint x, gint y, GtkSelectionData *selection_data, guint info, guint t, gpointer data ) { SENDER->object_drop_on_layer( dc, x, y, selection_data, info );  }
	friend void sign_object_motion_on_layer( GtkWidget *widget, GdkDragContext *dc, gint x, gint y, guint t, gpointer data ) { SENDER->object_motion_on_layer( dc, x, y );  }	
	friend void sign_object_drop_on_tree( GtkWidget *widget, GdkDragContext *dc, gint x, gint y, GtkSelectionData *selection_data, guint info, guint t, gpointer data ) { SENDER->object_drop_on_tree( dc, x, y, selection_data, info );  }	
	friend void sign_object_motion_on_tree( GtkWidget *widget, GdkDragContext *dc, gint x, gint y, guint t, gpointer data ) { SENDER->object_motion_on_tree( dc, x, y );  }	
	
	friend void sign_objlist_load_object( GtkWidget *wid, gpointer data ) { SENDER->load_object(); }		
	friend void sign_objlist_save_object( GtkWidget *wid, gpointer data ) { SENDER->save_object(); }		

	friend void sign_objlist_cut_object( GtkWidget *wid, gpointer data ) { SENDER->cut_current_object(); }		
	friend void sign_objlist_copy_object( GtkWidget *wid, gpointer data ) { SENDER->copy_current_object(); }		
	friend void sign_objlist_paste_object( GtkWidget *wid, gpointer data ) { SENDER->paste_current_object(); }		
	
	friend void sign_help_on_obj( GtkWidget *wid, gpointer data ) { SENDER->help_on_current_object(); }
	#undef SENDER


	private:
		app_objs *app_ref;
		vector<ObjectLayer*> Layers;
		ObjectLayer *selected_layer;
		vector<Object3D*> object_liste;
		Camera *MainCamera;
		GtkWidget *filebox;
		unsigned int current_pick_name;
		char **obj_name_list;
		int obj_name_list_size;
		ObjParam_objref *current_ref;
		GtkWidget *help_on_obj_wid;

		Object3D *drag_focus;
		int drag_layer_focus;

		// Edition de l'objet courrant
		Object3D* current;
		Object3D *cut_or_copied;
		bool is_cut;
		ObjParam* current_param;
		void refresh_edit();
		GtkWidget *edit_widget, *edit_box;
	
		// Layers selection tree
		GtkListStore *layer_list_store;
		GtkWidget *layer_list_view;
		GtkTreeSelection *layer_list_selection;
		GtkTreeViewColumn *layer_list_column2, *layer_list_column3, *layer_list_column4;
		void select_layer( GtkTreeSelection *selection );
		void select_layer_in_list( int pos ) { gtk_tree_selection_select_iter( layer_list_selection, Layers[pos]->get_node_iter() ); }
		void layer_view_clicked( GdkEventButton *ev );
		
		// Layers manipulation buttons
		GtkWidget *select_lbuttons[LAY_BUTTONS];
		GtkTooltips *select_ltooltips[LAY_BUTTONS];		
 		void layers_buttons_clicked( GtkWidget *wid );
		
		// Objects selection tree
		GtkTreeStore *object_tree_store;
		GtkWidget *object_tree_view, *select_widget;
		GtkTreeSelection *object_tree_selection;
		GtkTreeViewColumn *object_tree_column1, *object_tree_column2;
		void select_object( GtkTreeSelection *selection );
		void object_view_clicked( GdkEventButton *ev );
		void object_view_double_clicked();
		
		// Objects manipulation buttons
		GtkWidget *select_buttons[OBJ_BUTTONS];
		GtkTooltips *select_tooltips[OBJ_BUTTONS];
		void select_buttons_clicked( GtkWidget *wid );
		
		void cut_current_object() { select_buttons_clicked( select_buttons[6] ); }
		void copy_current_object() { select_buttons_clicked( select_buttons[7] ); }
		void paste_current_object() { select_buttons_clicked( select_buttons[8] ); }

		// Create Tree
		GtkWidget *create_tree;
		GtkTreeStore *create_tree_store;
		GtkTreeSelection *create_tree_selection;
		Object3DDef *current_objdef;
		void add_subtree( const char *name, const char *icon, Object3DDef *defs, const int def_num );
		void create_tree_select( GtkTreeSelection *selection );
		void create_button_clicked();
		void create_tree_click(  );

		// Lampes
		bool *light_list;
		GLint light_num;
		
		// Drag & Drop
		void object_drag( GdkDragContext *dc, GtkSelectionData *selection_data );
		void object_drop_on_layer( GdkDragContext *dc, gint x, gint y, GtkSelectionData *selection_data, guint info );
		void object_motion_on_layer( GdkDragContext *dc, gint x, gint y );
		void object_drop_on_tree( GdkDragContext *dc, gint x, gint y, GtkSelectionData *selection_data, guint info );
		void object_motion_on_tree( GdkDragContext *dc, gint x, gint y );
		
		// Save & load objects
		char *default_path;
		void store_default_path( char *path );
		

	public:
		ObjectList( app_objs *app_ref );
		~ObjectList() { delete light_list; }
		void pref_changed();

		void output_to_povray( ofstream & file );
		void unselect_object();
		
		// Object list management
		int get_size() { return object_liste.size(); }
		void add_object( Object3D *obj );
		void remove_object( Object3D *obj );
		Object3D *get_object( int num ) { return object_liste[num]; }
		
		// Object reference list management
		void update_ref_list();
		int get_index_by_pointer( Object3D *obj );
		Object3D *get_pointer_by_index( int index );
		Object3D *get_pointer_by_name( char *str );

		// Objects & layers name management
		bool test_name_exist( char *name );
		char *create_name( char *name );
		bool layer_name_exist( char *name, ObjectLayer *layer );

		// OpenGL preview display
		void display( glview *view );
		void invalidate_lists();

		// Boite de selection
		void set_edit_widget( GtkWidget *wid ) { edit_widget = wid; refresh_edit(); }
		void set_select_widget( GtkWidget *wid );
		void set_create_widget( GtkWidget *wid );
		gint get_layer_index( ObjectLayer *layer );

		// Parametre courrant
		ObjParam* get_current_param() { return current_param; }
		void set_current_param( ObjParam* param );
		void clear_current_param() { current_param = NULL; }
		void display_current_param( glview *view ) { if ( current_param != NULL ) current_param->display( view ); }
		void flush() { if ( current != NULL ) current->flush(); }

		// Manipulation de l'objet courant
		Object3D* get_current() { return current; }
		void clear_current_object() { current = NULL; }
		
		// Layer Manipulation
		ObjectLayer *get_current_layer() { return selected_layer; }
		void remove_layer( ObjectLayer *layer );
		void insert_layer( ObjectLayer *layer, int position );
		void move_layer( ObjectLayer *layer, int sens );

		// Interaction avec l'objet courant
		void mouse_interact_drag( struct drag_info *drag ) { if ( current != NULL ) current->mouse_drag( drag ); }

		// Lampes
		int light_request();
		void light_release( int light_id ) { if ( light_id != -1 ) light_list[light_id] = false; }
		void light_set_properties( int light_id, float *location, float *color );
		void light_set_properties( int light_id, float *location, float *direction, float cutoff, float *color );
		void light_enable( int light_id );
		void light_disable( int light_id );
		void light_disable_all();
		
		
		void save( ofstream & file );
		bool load( ifstream & file, char * tag );
		Object3D *create_object( char *tag );
		void clear();
		void new_scene();
		
		void init_pick_names();
		unsigned int get_pick_name() { return current_pick_name++; }
		void select_picked( int name );
		
		Object3D *get_camera() { return MainCamera; }
		void set_camera( Object3D *cam ) { MainCamera = (Camera*)cam; }
		
		void load_object();
		void save_object();
		
		char **get_obj_name_list() { return obj_name_list; }
		int get_obj_name_list_size() { return obj_name_list_size; }
		void set_current_ref( ObjParam_objref *ref ) { current_ref = ref; }
		
		void set_help_on_wid( GtkWidget *wid ) { help_on_obj_wid = wid; }
		void help_on_current_object() { if ( current != NULL ) current->help_on_object(); }
};


#endif
