package eu.dnetlib.contract.conv;

import java.io.StringWriter;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import org.apache.log4j.Logger;


import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.converters.ConversionException;
import com.thoughtworks.xstream.io.xml.CompactWriter;
import com.thoughtworks.xstream.io.xml.DomDriver;

import eu.dnetlib.contract.cp.comp.IComparatorModule;
import eu.dnetlib.contract.utils.XMLUtils;

/**
 * Converts complex objects to their String representation using XStream library.
 * @author mhorst
 *
 */
public class ComplexObjectsXStreamConverter implements
		IComplexObectToStringConverter {

	protected static final Logger log = Logger.getLogger(ComplexObjectsXStreamConverter.class);
	
	/**
	 * XStream converter.
	 */
	private XStream xStream; 
	
	/**
	 * {@link IComparatorModule} modules registry.
	 * Can be used to determine of an object should be converted using XStream module.
	 */
	Map<Class<? extends Object>, IComparatorModule<? extends Object>> modulesRegistry = 
		new HashMap<Class<? extends Object>, IComparatorModule<? extends Object>>();
	
	
	/**
	 * Default constructor.
	 */
	public ComplexObjectsXStreamConverter() {
		xStream = new XStream(new DomDriver());
	}
	
	/* (non-Javadoc)
	 * @see eu.dnetlib.contract.conv.IComplexObectToStringConverter#toString(java.lang.Object)
	 */
	public String toString(Object source) {
		if (source==null)
			return null;
		try {
			if (source instanceof Object[] ||
					source instanceof Collection ||
					source instanceof Map) {
				StringWriter strWriter = new StringWriter();
				xStream.marshal(source, new CompactWriter(strWriter));
				return strWriter.toString();
			} else if (modulesRegistry.containsKey(source.getClass())) {
				StringWriter strWriter = new StringWriter();
				xStream.marshal(source, new CompactWriter(strWriter));
				return strWriter.toString();
			} else {
	//			simple object, no convertion will be performed
				return source.toString();
			}
		} catch (ConversionException e) {
			log.error("Exception occured when converting complex object to " +
					"its xml representation!", e);
			return XMLUtils.buildContractErrorElement(e.getMessage());
		}
	}

	/**
	 * Returns {@link IComparatorModule} modules registry.
	 * @return IComparatorModule modules registry
	 */
	public Map<Class<? extends Object>, IComparatorModule<? extends Object>> getModulesRegistry() {
		return modulesRegistry;
	}

	/**
	 * Sets {@link IComparatorModule} modules registry.
	 * @param modulesRegistry
	 */
	public void setModulesRegistry(Map<Class<? extends Object>, IComparatorModule<? extends Object>> modulesRegistry) {
		this.modulesRegistry = modulesRegistry;
	}
	
}
