//*****************************************************************************************
// Truevision - a 3d modeler for gnome and povray
//
// undo.h
//
// Vincent LE PRINCE <vincentleprince@users.sourceforge.net>
// Copyright (C) 2000-2001 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 UNDOREDO_H
#define UNDOREDO_H
using namespace std;
#include <iostream>
#include "include/main.h"
#include "include/object3d.h"
#include "include/material.h"
#include "include/objectlayer.h"
#include "include/objparam.h"
#include <vector>

#define UNDO_DEF UndoRedoManager *undoman = (UndoRedoManager*)(app_ref->undoman);

//**********************************************
// Constants & declarations
//**********************************************
// Action types : used to define undo item
// From this depends what the undo function gonna do when called with
// the item
enum UndoType {
	TV_UNDO_NULL,
	TV_UNDO_OBJ_CREATE,
	TV_UNDO_OBJ_DELETE,
	TV_UNDO_OBJ_MOVE,
	TV_UNDO_LAYER_CREATE,
	TV_UNDO_LAYER_DELETE,
	TV_UNDO_LAYER_MOVE,
	TV_UNDO_MAT_CREATE,
	TV_UNDO_MAT_DELETE,
	TV_UNDO_PARAM_CHANGED
	};
typedef UndoType UndoAction;

// Declaration
class UndoRedoManager;


//**********************************************************
// Class Undo Item
// each undo item describes an action that may be undone
// They are stored by the UndoRedo Manager in two lists
// one for undo and the other for redo
//**********************************************************
class UndoItem {
	friend class UndoRedoManager;

	private:
		UndoAction action;
		Object3D *created;
		Object3D *deleted;
		Object3D *parent_object;
		ObjectLayer *layer;
		int position;
		Material *material;
		ObjParam *param;
		ObjParam *param_copy;
				
	public:
		UndoItem( UndoAction act, Object3D *object, ObjectLayer *dest );
		UndoItem( UndoAction act, ObjectLayer *lay, int sens );
		UndoItem( UndoAction act, Material *material, int position );
		UndoItem( UndoAction act, ObjParam *param, ObjParam *param_copy );
		~UndoItem();
		
		void set_action( UndoAction act ) { action = act; }
		
};



//******************************************************************
// Undo redo manager class
//
// Manage two lists : one for undo items the other for redo
// + toolbar icons for undo & redo and their sensitivity
//******************************************************************
class UndoRedoManager: private app_object {
	// Callbacks
	#define SENDER ((UndoRedoManager*)data)
	// From toolbar buttons
	friend void sign_undoman_undo( GtkWidget *wid, gpointer data ) { SENDER->undo(); }	
	friend void sign_undoman_redo( GtkWidget *wid, gpointer data ) { SENDER->redo(); }	
	#undef SENDER

	private:
		app_objs *app_ref;

		// the lists		
		vector<UndoItem*> UndoList;
		vector<UndoItem*> RedoList;
		
		// Toolbar buttons widgets
		GtkWidget *tbw_undo, *tbw_redo, *mew_undo, *mew_redo;
		
		// Internals
		void set_widgets_sensitivity();
		void purge_redo_list();
		void limit_undo_level();

	public:
		UndoRedoManager( app_objs *app_ref );
		~UndoRedoManager() { }
		
		// Called from the toolbar to set buttons widgets
		void set_undo_tb_widgets( GtkWidget *w1, GtkWidget *w2 )  { tbw_undo = w1; tbw_redo = w2; }
		void set_undo_menu_widgets( GtkWidget *w1, GtkWidget *w2 )  { mew_undo = w1; mew_redo = w2; }
				
		// Interface
		void init();        // To clear manager when loading a new scene
		void push( UndoAction act, Object3D *obj, ObjectLayer *src );       // To add a new action to undo list
		void push( UndoAction act, ObjectLayer *lay, int sens = -1 );    // The same for layers
		void push( UndoAction act, Material *mat, int postion = -1 );    // The same for materials
		void push( UndoAction act, ObjParam *param, ObjParam *param_copy );                       // The same for Object paramaters
		void undo( bool redo = false );           // Undo last action
		void redo() { undo( true ); }                // Redo last undo
};
#endif
