#pragma once

#include <vector>
#include <fltk/Widget.h>
/**
Commandable is the base class for objects which can receive commands. It's 
useful for faster connecting FLTK events
<BossType> - Use your implementors type here

Usage:
<code>
class myclass : public commandable <myclass> {
public:
	[..]
	void connect_buttons (){
		// Connecting Widgets
		bind (button1, &myclass::so_something);
		bind (button2, &myclass::do_with_parameter, 2);
		
		// Connecting Menu Items
		fltk::Item * item = new fltk::Item (callback_execute_command, create_command (&myclass::do_something));
		item = new fltk::Item (callback_execute_command, create_command (&myclass::do_something, 2));
	}
	[]

	void do_something ();
	void do_with_parameter (int i);
};
</code>
*/
template <class BossType>
class commandable {
public:
	/**
	Base class for commands
	*/
	struct command_base {
		command_base (BossType * my_boss){
			boss = my_boss;
			boss->register_command (this);
		}

		virtual void exec () {}
		BossType * boss;
	};
		
	
	commandable (){
	}
	
	/// Destructor, deletes all commands
	virtual ~commandable (){
		// Deleting commands
		for (typename std::vector<command_base*>::iterator i=m_commands.begin(); i!=m_commands.end(); i++){
		delete *i;
		}
	}
	

	/** 
	A templated command with one parameter
	*/
	template <class Param0Type> 
	struct command_1p : public command_base {
		typedef void (BossType::*func_type) (Param0Type);

		command_1p (BossType * my_boss, func_type f, Param0Type my_p0) 
			: command_base (my_boss), p0(my_p0), func (f) {}
		
		virtual void exec (){ 
			(this->boss->*func) (p0); 
		}

		Param0Type p0;
		func_type func;
	};
	
	/** A command taking no parameter */
	struct command_0p : public command_base {
		typedef void (BossType::*func_type) ();
		command_0p (BossType * my_boss, func_type f) 
			: command_base (my_boss), func (f){}
		
		virtual void exec (){
			(this->boss->*func)();
		}
		func_type func;
	};

	/** MSVC++ doesn't search constructors automatically with different template arguments
	So you can use this function to create a command with one parameter nice
	*/
	template <class Param0Type>
	command_base * create_command (typename command_1p<Param0Type>::func_type func, Param0Type p0){
		return new command_1p <Param0Type> ( (BossType*)this, func, p0);
	}
	
	/// Command creator for commands taking no arguments
	command_base * create_command (typename command_0p::func_type func){
		return new command_0p ( (BossType*)this, func);
	}
	
	/// Register a new command to the mesh_viewer (will be deleted on it's destructor)
	void register_command (command_base * cmd){
		m_commands.push_back (cmd);
	}
	
	/// Even more sophisticated FTLK Callback binder (0 Arguments)
	void bind (fltk::Widget * button, typename command_0p::func_type func){
		button->callback (callback_execute_command, create_command (func));
	}
	
	/// Callback binder with 1 argument
	template <class Param0Type>
	void bind (fltk::Widget * button, typename command_1p<Param0Type>::func_type func, Param0Type p0){
		button->callback (callback_execute_command, create_command (func, p0));
	}
	
	/// FLTK Command Executing a Command
	static void callback_execute_command (fltk::Widget *, void * data){
		((command_base *) data)->exec ();
	}
	
private:
	/// All us known Commands
	std::vector <command_base * > m_commands;
};

