package railo.runtime.converter;

import java.io.IOException;
import java.io.Writer;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import railo.runtime.PageContext;
import railo.runtime.op.Caster;
import railo.runtime.text.xml.struct.XMLStruct;
import railo.runtime.type.Array;
import railo.runtime.type.Collection;
import railo.runtime.type.SimpleValue;
import railo.runtime.type.Struct;

public class LazyConverter extends ConverterSupport {

	public static String serialize(Object o)  {
		return serialize(o,new HashSet<Object>());
	}

	@Override
	public void writeOut(PageContext pc, Object source, Writer writer) throws ConverterException, IOException {
		writer.write(serialize(source));
		writer.flush();
	}
	
	
	private static String serialize(Object o,Set<Object> done)  {
		
		if(o==null) return "null";
		Object raw=toRaw(o);
		
		if(done.contains(raw)) return "parent reference";
		done.add(raw);
		try{
			 if(o instanceof Array)return serializeArray((Array)o,done);
			 if(o instanceof Struct){
				 return serializeStruct((Struct)o,done);
			 }
			 if(o instanceof SimpleValue || o instanceof Number || o instanceof Boolean)return Caster.toString(o,null);
			 return o.toString();
		}
		finally {
			done.remove(raw);
		}
	}

	public static Object toRaw(Object o) {
		if(o instanceof XMLStruct)return ((XMLStruct)o).toNode();
		return o;
	}


	private static String serializeStruct(Struct struct, Set<Object> done) {
		StringBuffer sb=new StringBuffer("{");
		Iterator it = struct.keyIterator();
		Object key;
		boolean notFirst=false;
		while(it.hasNext()) {
			if(notFirst)sb.append(", ");
			key=it.next();
			sb.append(key);
			sb.append("={");
			if(key instanceof String)
				sb.append(serialize(struct.get((String)key,null),done));
			else
				sb.append(serialize(struct.get((Collection.Key)key,null),done));
			sb.append("}");
			notFirst=true;
		}
		
		return sb.append("}").toString();
	}

	private static String serializeArray(Array array, Set<Object> done) {
		StringBuffer sb=new StringBuffer("[");
		int len=array.size();
		for(int i=1;i<=len;i++){
			if(i>1)sb.append(", ");
			sb.append(serialize(array.get(i,null),done));
		}
		return sb.append("]").toString();
	}
}
