package gov.va.med.esr.xml;

import gov.va.med.esr.io.FileUtility;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.StringWriter;

import org.exolab.castor.mapping.Mapping;
import org.exolab.castor.mapping.MappingException;
import org.exolab.castor.xml.MarshalException;
import org.exolab.castor.xml.Marshaller;
import org.exolab.castor.xml.Unmarshaller;
import org.exolab.castor.xml.ValidationException;
import org.springframework.core.io.ClassPathResource;
import org.xml.sax.InputSource;

public class CastorUtility {
	private static String mappingUrlPlaceHolder = "@mapping.url@";
	
	@SuppressWarnings({ "unchecked"})
	public static <T> T unmarshall(File xml, String castorMappingPath, Class<T> klass) throws IOException, MappingException, MarshalException, ValidationException{
		Unmarshaller unmarshaller = new Unmarshaller(klass);
		if(castorMappingPath != null){
			File mappingFile = CastorUtility.replaceMappingURL(castorMappingPath);
			Mapping mapping = createMapping(mappingFile);
			unmarshaller.setMapping(mapping);
		}
		return (T) unmarshaller.unmarshal(new FileReader(xml));
	}
	public static String marshall(String castorMappingPath, Object target, String[][] namespaces, String schemaLocation) throws IOException, MappingException, MarshalException, ValidationException, InstantiationException, IllegalAccessException {
		File mappingFile = CastorUtility.replaceMappingURL(castorMappingPath);
		Mapping mapping = createMapping(mappingFile);
		StringWriter writer = new StringWriter();
		Marshaller marshaller = new Marshaller(writer);
		marshaller.setMapping(mapping);
		for(String[] namespace: namespaces){
			if(namespace[0] != null && namespace[1] != null){
				marshaller.setNamespaceMapping(namespace[0], namespace[1]);
			}
		}
		if(schemaLocation != null) marshaller.setSchemaLocation(schemaLocation);
		marshaller.marshal(target);
		return writer.getBuffer().toString();
	}
	private static Mapping createMapping(File mappingFile) throws FileNotFoundException {
		Mapping mapping = new Mapping();
		mapping.loadMapping(new InputSource(new FileInputStream(mappingFile)));
		return mapping;
	}
	public static File replaceMappingURL(String mappingFileRelativePath) throws IOException {
		File mappingFile = (new ClassPathResource(mappingFileRelativePath)).getFile();
		String[] lines = FileUtility.readFile(mappingFile);
		File tempMappingFile = new File(mappingFile.getAbsolutePath().substring(0, mappingFile.getAbsolutePath().length()-3)+"temp.xml");
		String line = null;
		for(int i=0; i < lines.length; i++){
			line = lines[i];
			if(line.contains(mappingUrlPlaceHolder)){
				lines[i] = line.replaceFirst(mappingUrlPlaceHolder, "http://castor.org/mapping.dtd");
				break;
			}
		}
		
		 FileUtility.writeFile(tempMappingFile, FileUtility.mergeLines(lines));
		 return tempMappingFile;
	}
	public static String removeFormatting(String xml) {
		xml = xml.replaceAll("\n", "");
		xml = xml.replaceAll("\\s+", " ");
		xml = xml.replaceAll(">\\s+<", "><");
		return xml;
	}
}
