// CharacterProxy.h - rebindable DisplayObject reference, for Gnash
//
//   Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Free Software
//   Foundation, Inc
// 
// 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 3 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

#ifndef GNASH_CHARACTER_PROXY_H
#define GNASH_CHARACTER_PROXY_H

#include <string>

// Forward declarations
namespace gnash {
	class DisplayObject;
}

namespace gnash {

/// A proxy for DisplayObject pointers.
//
/// The proxy will store a pointer to a DisplayObject until the 
/// DisplayObject is destroyed, in which case it will only store the original
/// target path of it and always use that for rebinding when needed.
///
class CharacterProxy {

	mutable DisplayObject* _ptr;

	mutable std::string _tgt;

	static DisplayObject* findDisplayObjectByTarget(const std::string& target);

	/// If we still have a sprite pointer check if it was destroyed
	/// in which case we drop the pointer and only keep the target.
	void checkDangling() const;

public:

	/// Construct a CharacterProxy pointing to the given sprite
	CharacterProxy(DisplayObject* sp)
		:
		_ptr(sp)
	{
		checkDangling();
	}

	/// Construct a copy of the given CharacterProxy 
	//
	/// @param sp
	///	The CharacterProxy to make a copy of.
	///	NOTE: if the given proxy is dangling, this proxy
	///	      will also be dangling. If you want to 
	///	      create a non-dangling proxy you can
	///           use the constructor taking a DisplayObject
	///	      as in CharacterProxy newProxy(oldProxy.get())
	///
	CharacterProxy(const CharacterProxy& sp)
	{
		sp.checkDangling();
		_ptr=sp._ptr;
		if ( ! _ptr ) _tgt=sp._tgt;
	}

	/// Make this proxy a copy of the given one
	//
	/// @param sp
	///	The CharacterProxy to make a copy of.
	///	NOTE: if the given proxy is dangling, this proxy
	///	      will also be dangling. If you want to 
	///	      create a non-dangling proxy you can
	///           use the constructor taking a DisplayObject
	///	      as in CharacterProxy newProxy(oldProxy.get())
	///
	CharacterProxy& operator=(const CharacterProxy& sp)
	{
		sp.checkDangling();
		_ptr=sp._ptr;
		if ( ! _ptr ) _tgt=sp._tgt;
		return *this;
	}

	/// Get the pointed sprite, either original or rebound
	//
	/// @return the currently bound sprite, NULL if none
	///
	DisplayObject* get(bool skipRebinding=false) const
	{
		if ( skipRebinding ) return _ptr;

        // set _ptr to NULL and _tgt to original target if destroyed
		checkDangling(); 
		if ( _ptr ) return _ptr;
		else return findDisplayObjectByTarget(_tgt);
	}

	/// Get the sprite target, either current (if not dangling) or
    /// bound one.
	std::string getTarget() const;

	/// Return true if this sprite is dangling
	//
	/// Dangling means that it doesn't have a pointer to the original
	/// sprite anymore, not that it doesn't point to anything.
	/// To know if it points to something or not use get(), which will
	/// return NULL if it doesn't point to anyhing.
	///
	bool isDangling() const
	{
		checkDangling();
		return !_ptr;
	}

	/// \brief
	/// Two sprite_proxies are equal if they point to the
	/// same sprite
	///
	bool operator==(const CharacterProxy& sp) const
	{
		return get() == sp.get();
	}

	/// Set the original sprite (if any) as reachable
	//
	/// NOTE: if this value is dangling, we won't keep anything
	///       alive.
	///
	void setReachable() const;
};

} // end namespace gnash

#endif // GNASH_CHARACTER_PROXY_H

