package railo.runtime.functions.other;


import java.util.HashSet;
import java.util.Iterator;
import java.util.Map.Entry;

import railo.runtime.Component;
import railo.runtime.PageContext;
import railo.runtime.converter.LazyConverter;
import railo.runtime.type.Collection;
import railo.runtime.type.Collection.Key;

public class ObjectEquals {
	public static boolean call(PageContext pc , Object left, Object right) {
		return _equals(new HashSet<Object>(), left, right);
	}
	
	private static boolean _equals(HashSet<Object> done,Object left, Object right) {
		// null
		if(left==null) {
			return right==null;
		}
		if(left==right) return true;
		
		Object rawLeft = LazyConverter.toRaw(left);
		Object rawRight = LazyConverter.toRaw(right);
		
		if(done.contains(rawLeft)) return done.contains(rawRight);
		done.add(rawLeft);
		done.add(rawRight);
		try{
		
			// Components
			if(left instanceof Component){
				if(!(right instanceof Component)) return false;
				return _equals(done,(Component)left, (Component)right);
			}
			
			// Collection
			if(left instanceof Collection){
				if(!(right instanceof Collection)) return false;
				return _equals(done,(Collection)left, (Collection)right);
			}
			
			// other
			return left.equals(right);
		}
		finally {
			done.remove(rawLeft);
			done.remove(rawRight);
		}
	}
	
	private static boolean _equals(HashSet<Object> done,Collection left, Collection right) {
		if(left.size()!=right.size()) return false;
		Iterator<Entry<Key, Object>> it = left.entryIterator();
		Entry<Key, Object> e;
		Object l,r;
		while(it.hasNext()){
			e = it.next();
			l=e.getValue();
			r=right.get(e.getKey(),null);
			if(r==null || !_equals(done,l, r)) return false;
		}
		return true;
	}
	
	private static boolean _equals(HashSet<Object> done,Component left, Component right) {
		if(left==null || right==null) return false;
		
		/*ComponentImpl lefti=(ComponentImpl) left;
		ComponentImpl righti=(ComponentImpl) right;
		print.e(lefti.getName()+"="+lefti._getName());
		print.e(righti.getName()+"="+righti._getName());*/
		
		
		if(!left.getPageSource().equals(right.getPageSource())) return false;
		
		if(!_equals(done,left.getComponentScope(),right.getComponentScope())) return false;
		if(!_equals(done,(Collection)left,(Collection)right)) return false;

		return true;
	}
}

@@ -228,16 +228,50 @@
 verter;%0A
+import railo.runtime.op.Operator;%0A
 import r
@@ -300,16 +300,16 @@
 ection;%0A
-
 import r
@@ -341,16 +341,47 @@
 ion.Key;
+%0Aimport railo.runtime.type.UDF;
 %0A%0Apublic
@@ -477,32 +477,96 @@
 ght) %7B%0A%09%09return 
+Operator.equalsComplexEL(left, right, false, false);%0A%09%09//return 
 _equals(new Hash
@@ -1326,24 +1326,118 @@
 );%0A%09%09%09%7D%0A%09%09%09%0A
+%09%09%09if(left instanceof UDF) %7B%0A%09%09%09%09if(!(right instanceof UDF)) return false;%0A%09%09%09%09%0A%09%09%09%09%0A%09%09%09%7D%0A%09%09%09%0A
 %09%09%09// other%0A
@@ -2277,19 +2277,16 @@
 );*/%0A%09%09%0A
-%09%09%0A
 %09%09if(!le
@@ -2348,24 +2348,24 @@
 n false;%0A%09%09%0A
-
 %09%09if(!_equal
@@ -2438,16 +2438,19 @@
  false;%0A
+%09%09%0A
 %09%09if(!_e

remove redunant functionality for object comparision