USING_TOOLBOX_NAMESPACE

VJSStructuredClone *VJSStructuredClone::RetainClone (XBOX::VJSValue inValue)
{	
	std::map<JS4D::ValueRef, SNode *>	alreadyCreated;
	std::list<SEntry>					toDoList;
	SNode								*root;

	if ((root = _ValueToNode(inValue, &alreadyCreated, &toDoList)) == NULL)

		return NULL;

	while (!toDoList.empty()) {

		// Property iterator will also iterate Array object indexes (they are converted into string).

		XBOX::VJSValue				value(inValue.GetContext(), toDoList.front().fValueRef);
		XBOX::VJSPropertyIterator	i(value.GetObject());
		SNode						*p, *q, *r;

		p = toDoList.front().fNode;
		xbox_assert(p->fType == eNODE_OBJECT || p->fType == eNODE_ARRAY);
		
		toDoList.pop_front();

		// Object or Array with no attributes?

		if (!i.IsValid()) 

			continue;

		// Get prototype and dump its attribute names.

		XBOX::VJSObject	prototypeObject	= value.GetObject().GetPrototype(inValue.GetContext());
		bool			hasPrototype	= prototypeObject.IsObject();

		// Iterate child(s).

		for ( ; i.IsValid(); ++i) {

			XBOX::VString	name;

			i.GetPropertyName(name);
	
			// Check attribute name: If it is part of prototype, do not clone it.

			if (hasPrototype && prototypeObject.HasProperty(name))

				continue;

			value = i.GetProperty();
			if ((r = _ValueToNode(value, &alreadyCreated, &toDoList)) == NULL) 

				break;

			else if (p->fValue.fFirstChild != NULL) 
				
				q->fNextSibling = r;
						
			else
				
				p->fValue.fFirstChild = r;

			r->fName = name;
			q = r;

		}

		if (p->fValue.fFirstChild != NULL) 

			q->fNextSibling = NULL;

		if (i.IsValid()) {

			_FreeNode(root);
			root = NULL;
			break;

		} 	

	}

	if (root != NULL) {

		VJSStructuredClone	*structuredClone;

		if ((structuredClone = new VJSStructuredClone()) != NULL)

			structuredClone->fRoot = root;

		else

			_FreeNode(root);

		return structuredClone;

	} else

		return NULL;
}
USING_TOOLBOX_NAMESPACE

VJSStructuredClone *VJSStructuredClone::RetainClone (XBOX::VJSValue inValue)
{	
	std::map<JS4D::ValueRef, SNode *>	alreadyCreated;
	std::list<SEntry>					toDoList;
	SNode								*root;

	if ((root = _ValueToNode(inValue, &alreadyCreated, &toDoList)) == NULL)

		return NULL;

	while (!toDoList.empty()) {

		// Property iterator will also iterate Array object indexes (they are converted into string).

		XBOX::VJSValue				value(inValue.GetContext(), toDoList.front().fValueRef);
		XBOX::VJSPropertyIterator	i(value.GetObject());
		SNode						*p, *q;

		p = toDoList.front().fNode;
		xbox_assert(p->fType == eNODE_OBJECT || p->fType == eNODE_ARRAY);
		
		toDoList.pop_front();

		// Object or Array with no attributes?

		if (!i.IsValid()) 

			continue;

		// Set first child.

		value = i.GetProperty();
		if ((p->fValue.fFirstChild = _ValueToNode(value, &alreadyCreated, &toDoList)) == NULL) {

			_FreeNode(root);
			root = NULL;			
			break;

		} 		
		q = p->fValue.fFirstChild;
		i.GetPropertyName(q->fName);		
		++i;

		// Iterate sibling(s).

		for ( ; i.IsValid(); ++i) {

			value = i.GetProperty();
			if ((p = _ValueToNode(value, &alreadyCreated, &toDoList)) == NULL) 

				break;

			else {

				q = q->fNextSibling = p;
				i.GetPropertyName(p->fName);

			}

		}

		q->fNextSibling = NULL;
		if (i.IsValid()) {

			_FreeNode(root);
			root = NULL;
			break;

		} 	

	}

	if (root != NULL) {

		VJSStructuredClone	*structuredClone;

		if ((structuredClone = new VJSStructuredClone()) != NULL)

			structuredClone->fRoot = root;

		else

			_FreeNode(root);

		return structuredClone;

	} else

		return NULL;
}