#ifndef K3DUI_DOCUMENT_WINDOW_H
#define K3DUI_DOCUMENT_WINDOW_H

// K-3D
// Copyright (c) 1995-2004, Timothy M. Shead
//
// Contact: tshead@k-3d.com
//
// 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

/** \file
		\brief Declares the document_window class, which encapsulates an open K-3D document's UI
		\author Tim Shead (tshead@k-3d.com)
*/

#include "k3ddialog.h"

#include <k3dsdk/data.h>
#include <k3dsdk/iobject_collection.h>
#include <k3dsdk/property_collection.h>
#include <k3dsdk/result.h>

namespace k3d
{

// Forward declarations
class idependencies;
class iplugin_factory;
namespace dag_control { class control; }

/////////////////////////////////////////////////////////////////////////////
// document_window

/// Implements a document's user interface
class document_window :
	public k3dDialog,
	public property_collection
{
	typedef k3dDialog base;

public:
	document_window(idocument& Document);
	~document_window();

	// icommand_node implementation
	bool execute_command(const std::string& Command, const std::string& Arguments);

private:
	/// Called by the signal system to see if it's OK to close the owning document
	bool safe_to_close_document();

	/// Called by the signal system when the document is closed
	void on_document_closed();
	/// Called by the signal system when the document title changes
	void on_document_title_changed();

	/// Called by the signal system whenever the undo / redo stack contents change
	void on_undo_stack_changed();
	/// Called by the signal system whenever the undo / redo stack is marked as saved
	void on_undo_mark_saved();

	/// Called by the signal system whenever new objects are added to the document
	void on_add_objects(const iobject_collection::objects_t& Objects);

	/// Overridden from sdpGtkObjectContainer to handle events
	void OnEvent(sdpGtkEvent* Event);

	/// Called to see if its OK to delete the frame
	void OnDelete(sdpGtkEvent* Event);
	/// Called when the user wants to create a new document view
	void on_file_new_hierarchy_window();
	/// Called when the user wants to create a new DAG view
	void on_file_new_dag_window();
	/// Called when the user wants to create a new viewport
	void on_file_new_viewport();
	/// Called when the user wants to import geometry into the document
	void on_file_import();
	/// Called when the user wants to export geometry from the document
	void on_file_export();
	/// Called when the user wants to save the document (returns true iff the document was successfully saved)
	bool on_file_save();
	/// Called when the user wants to save the document to a new file (returns true iff the document was successfully saved)
	bool on_file_save_as();
	/// Called when the user wants to close the document
	void on_file_close();
	/// Called when the user wants to undo an action
	void on_edit_undo();
	/// Called when the user wants to redo an undone action
	void on_edit_redo();
	/// Called when the user wants to play a script within this document
	void on_tools_play_script();
	/// Called when the user hits the "rewind" button
	void on_rewind();
	/// Called when the user hits the "continuous reverse play" button
	void on_reverse_loop_play();
	/// Called when the user hits the "reverse play" button
	void on_reverse_play();
	/// Called when the user hits the "stop" button
	void on_stop();
	/// Called when the user hits the "play" button
	void on_play();
	/// Called when the user hits the "continuous play" button
	void on_loop_play();
	/// Called when the user hits the "fast forward" button
	void on_fast_forward();
	/// Called when the user moves the animation scrollbar
	void OnAnimationScrollbar();
	/// Called when the user selects a new animation frame
	void OnAnimationFrame();
	/// Called when the user clicks in the undo stack to perform multiple undos/redos
	void OnUndoStack(sdpGtkEvent* Event);

	/// Returns the frame title
	std::string Title();
	/// Updates the frame titlebar to display the frame title
	void UpdateTitlebar();

	void UpdateControls();

	/// Updates the undo/redo menu commands as needed
	void UpdateUndoStack();
	/// Updates the animation playback controls as needed
	void on_playback_mode_changed();
	/// Updates the animation frame controls as needed
	void update_time();

	/// Prompts the user to see if it's safe to close the document
	bool SafeToClose();

	/// Stores a reference to the owning document
	idocument& m_document;

	/// Stores the DAG control
	dag_control::control* m_dag_control;
	/// Stores the animation timer handler id
	unsigned int m_animation_timer;
	/// Used to ignore every other timer signal (so the display can keep up)
	bool m_ignore_animation_timer;
	/// Called by the animation interval timer
	static int raw_animation_timer(gpointer Data);
	/// Called by the animation interval timer
	int animation_timer();

	SigC::Connection m_time_connection;

	/// Enumerates animation playback modes
	typedef enum
	{
		REWIND,
		LOOP_REVERSE_PLAY,
		REVERSE_PLAY,
		STOP,
		PLAY,
		LOOP_PLAY,
		FAST_FORWARD
	} playback_t;

	friend std::ostream& operator<<(std::ostream& Stream, const playback_t& RHS)
	{
		switch(RHS)
			{
				case REWIND:
					Stream << "rewind";
					break;
				case LOOP_REVERSE_PLAY:
					Stream << "loop_reverse_play";
					break;
				case REVERSE_PLAY:
					Stream << "reverse_play";
					break;
				case STOP:
					Stream << "stop";
					break;
				case PLAY:
					Stream << "play";
					break;
				case LOOP_PLAY:
					Stream << "loop_play";
					break;
				case FAST_FORWARD:
					Stream << "fast_forward";
					break;
				default:
					assert_warning(0);
					break;
			}

		return Stream;
	}

	friend std::istream& operator>>(std::istream& Stream, playback_t& RHS)
	{
		std::string temp;
		Stream >> temp;

		if(temp == "rewind")
			RHS = REWIND;
		else if(temp == "loop_reverse_play")
			RHS = LOOP_REVERSE_PLAY;
		else if(temp == "reverse_play")
			RHS = REVERSE_PLAY;
		else if(temp == "stop")
			RHS = STOP;
		else if(temp == "play")
			RHS = PLAY;
		else if(temp == "loop_play")
			RHS = LOOP_PLAY;
		else if(temp == "fast_forward")
			RHS = FAST_FORWARD;

		return Stream;
	}

	property::string_proxy<k3d_data(playback_t, immutable_name, change_signal, no_undo, local_storage, no_constraint)> m_playback_mode;

	/// Called when the user clicks in the list of available plugin types
	void OnPluginsClicked(sdpGtkEvent* Event);
	/// Called by the user to create an instance of a K-3D plugin object
	void OnCreatePlugin();
	/// Called when the user completes a drag-and-drop operation
	void OnDragDataGet(sdpGtkEvent* Event);
	/// Provides a storage buffer for data being transmitted via drag-and-drop
	std::string m_DNDBuffer;
	void InitializeTrees();
	/// Returns the plugins tree
	sdpGtkCList PluginsList() { return CList("plugins"); }


	k3d_data(bool, k3d::no_name, k3d::change_signal, k3d::no_undo, k3d::local_storage, k3d::no_constraint) m_rewind;
	k3d_data(bool, k3d::no_name, k3d::change_signal, k3d::no_undo, k3d::local_storage, k3d::no_constraint) m_reverse_loop_play;
	k3d_data(bool, k3d::no_name, k3d::change_signal, k3d::no_undo, k3d::local_storage, k3d::no_constraint) m_reverse_play;
	k3d_data(bool, k3d::no_name, k3d::change_signal, k3d::no_undo, k3d::local_storage, k3d::no_constraint) m_stop;
	k3d_data(bool, k3d::no_name, k3d::change_signal, k3d::no_undo, k3d::local_storage, k3d::no_constraint) m_play;
	k3d_data(bool, k3d::no_name, k3d::change_signal, k3d::no_undo, k3d::local_storage, k3d::no_constraint) m_loop_play;
	k3d_data(bool, k3d::no_name, k3d::change_signal, k3d::no_undo, k3d::local_storage, k3d::no_constraint) m_fast_forward;
	bool m_ignore_playback_change;
};

} // namespace k3d

#endif // !K3DUI_DOCUMENT_WINDOW_H


