/*
 * The UDS Collection
 * Copyright (C) 2000, 2001  Julian v. Bock
 *
 * 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
 *
 *	(See file COPYING for more information)
 */

#ifndef _uds_action_hh
#define _uds_action_hh


namespace uds
{

template < class Ret >
class Action_base
{
public:
	virtual
	~Action_base() = 0;
	
	/** clones the object
		\return new object */
	virtual Action_base*
	Clone() const = 0;
	
	virtual Ret
	operator () () = 0;
};

template < class Ret >
inline
Action_base< Ret >::~Action_base() {}

/** function / function object wrapper
	\author Julian v. Bock */
template < class Ret, class Op, class Tp >
class Action_t : public Action_base< Ret >
{
public:
	/** \param o operation to be performed
		\param v value */
	Action_t( Op o, Tp v ) : op( o ), value( v ) {}
	
	/** clones the object
		\return new object */
	virtual Action_t*
	Clone() const { return new Action_t( *this ); }
	
	Ret
	operator () () { return static_cast< Ret >( op( value ) ); }
	
private:
	/// operation to be performed
	Op	op;
	/// value that is pased to the action
	Tp	value;
};

/** function / function object wrapper
	\author Julian v. Bock */
template < class Ret, class Op >
class Action_t< Ret, Op, void > : public Action_base< Ret >
{
public:
	/** \param o operation to be performed */
	Action_t( Op o ) : op( o ) {}
	
	/** clones the object
		\return new object */
	virtual Action_t*
	Clone() const { return new Action_t( *this ); }
	
	Ret
	operator () () { return static_cast< Ret >( op() ); }
	
private:
	/// operation to be performed
	Op op;
};

template < class Ret >
class Action
{
public:
	template < class Op, class Tp >
	Action( Op o, Tp v ) : dab( new Action_t< Ret, Op, Tp >( o, v ) ) {}
	
	template < class Op >
	Action( Op o ) : dab( new Action_t< Ret, Op, void >( o ) ) {}
	
	Action( const Action& rhs )
		: dab( rhs.dab ? rhs.dab->Clone() : 0 ) {}
	
	~Action() { delete dab; }
	
	Ret
	operator () () { return ( *dab )(); }
	
private:
	/// wrapped Action_t
	Action_base< Ret >* dab;
};

typedef Action< void > AnyAction;

class FinalAction
{
public:
	template < class Op, class Tp >
	FinalAction( Op o, Tp v ) : dab( new Action_t< void, Op, Tp >( o, v ) ) {}
	
	template < class Op >
	FinalAction( Op o ) : dab( new Action_t< void, Op, void >( o ) ) {}
	
	FinalAction( const FinalAction& rhs )
		: dab( rhs.dab ? rhs.dab->Clone() : 0 ) {}
	
	~FinalAction() { ( *dab )(); delete dab; }
	
private:
	/// wrapped Action_t
	Action_base< void >* dab;
};


/** sets a variable to a new value, and restores the value when the object is
	destroyed
	\author Julian v. Bock */
template < class Tp, class Ptr = Tp* >
class VRemember
{
public:
	/** default constructor */
	VRemember() : var( 0 ) {}
	
	/** \param r variable that is changed */
	VRemember( Tp& r ) { init( r ); }
	
	/** \param r variable that is changed
		\param n new value */
	VRemember( Tp& r, Tp n ) { init( r ); r = n; }
	
	/** destructor */
	~VRemember() { if ( var ) *var = orig; }
	
	/** initializes the object
		\param r variable that is changed */
	void
	init( Tp& r ) { var = &r; orig = r; }
	
	/** \return the original value */
	Tp&
	orig_value() { return orig; }
	
private:
	/// variable that is changed
	Ptr	var;
	/// original value
	Tp	orig;
};

}

#endif // _uds_action_hh
