package lu.tudor.santec.gecamed.core.gui.widgets.autocompletion;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;

import javax.xml.XMLConstants;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;

import lu.tudor.santec.gecamed.core.ejb.entity.beans.Autocompletion;

import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;

public class AutoCompletionIOManager
{
	/* ======================================== */
	// 		CONSTANTS
	/* ======================================== */
	
	private static final String ELEMENT_ROOT 		= "autocompletions";
	private static final String ELEMENT_CONTEXT 	= "context";
	private static final String ELEMENT_COMPLETION 	= "completion";
	private static final String ELEMENT_INPUT 		= "inputText";
	private static final String ELEMENT_REPLACEMENT = "replacementText";
	private static final String ATTRIBUTE_NAME 		= "name";
	
	private static final String XSD_FILE 			= "autocompletion.xsd";
	
	
	/* ======================================== */
	// 		MEMBERS
	/* ======================================== */
	
	/** the logger Object for this class */
	private static Logger logger = Logger.getLogger(AutoCompletionIOManager.class.getName());
	
	
	
	/* ======================================== */
	// 		EXPORT
	/* ======================================== */
	
	public static boolean exportCompletions (List<Autocompletion> completions, File file) 
	{
		if (file == null || !file.exists())
		{
			logger.log(Level.WARN, "File NOT valid. Export canceled!");
			return false;
		}
		
		Document 		 doc;
		FileOutputStream fos = null;
		XMLOutputter 	 outputter;
		try
		{
			doc 		= writeXML(completions);
			fos 		= new FileOutputStream(file);
			outputter 	= new XMLOutputter(Format.getPrettyFormat());
			outputter.output(doc, fos);
			
			return true;
		}
		catch (IOException e)
		{
			logger.log(Level.ERROR, e.getMessage(), e);
			return false;
		}
		finally 
		{
			try 
			{
				if (fos != null)
					fos.close();
			}
			catch (Exception e) 
			{
				logger.log(Level.ERROR, e.getMessage(), e);
			}
		}
	}
	
	
	private static Document writeXML(List<Autocompletion> completions)
	{
		HashMap<String, Element> contextElements = new HashMap<String, Element>();
		Element root = new Element(ELEMENT_ROOT);
		Element context;
		Element completion;
		Element input;
		Element replacement;
		
		for (Autocompletion ac : completions)
		{
			completion 	= new Element(ELEMENT_COMPLETION);
			input 		= new Element(ELEMENT_INPUT);
			replacement = new Element(ELEMENT_REPLACEMENT);
			context 	= contextElements.get(ac.getContext());
			if (context == null)
			{
				context = new Element(ELEMENT_CONTEXT);
				context.setAttribute(ATTRIBUTE_NAME, ac.getContext());
				root.addContent(context);
				contextElements.put(ac.getContext(), context);
			}
			
			input.setText(ac.getInputText());
			replacement.setText(ac.getReplacementText());
			completion.addContent(input);
			completion.addContent(replacement);
			context.addContent(completion);
		}
		
		return new Document(root);
	}
	
	
	
	/* ======================================== */
	// 		IMPORT
	/* ======================================== */
	
	public static HashMap<String, List<Autocompletion>> importCompletions (File file)
	{
		return importCompletions(file, null);
	}
	
	public static HashMap<String, List<Autocompletion>> importCompletions (File file, Integer userId)
	{
		if (file == null || !file.exists())
		{
			logger.log(Level.WARN, "File NOT valid. Export canceled!");
			return null;
		}
		
		try
		{
			SAXBuilder 	builder = new SAXBuilder();
			Document 	doc 	= builder.build(file);
			
			URL 		xsdUrl 	= AutoCompletionIOManager.class.getResource(XSD_FILE);
			Schema 		schema 	= SchemaFactory.newInstance(
					XMLConstants.W3C_XML_SCHEMA_NS_URI).newSchema(xsdUrl);
			
			try 
			{
				schema.newValidator().validate(new StreamSource(file));
			} 
			catch (Exception e)
			{
				logger.log(Level.WARN, "Validating the XSD-file failed because of the following reason: ", e);
				return null;
			}
			
			return readXML(doc, userId);
		}
		catch (Exception e)
		{
			logger.log(Level.ERROR, e.getMessage(), e);
			return null;
		}
	}
	
	
	private static HashMap<String, List<Autocompletion>> readXML (Document doc, Integer userId)
	{
		HashMap<String, List<Autocompletion>> contexts = new HashMap<String, List<Autocompletion>>();
		List<Autocompletion> completions;
		Autocompletion ac;
		String context;
		
		List<?> contextElements;
		List<?> completionElements;
		Element root = doc.getRootElement();
		Element input;
		Element replacement;
		
		contextElements = root.getChildren(ELEMENT_CONTEXT);
		for (Object contextElement : contextElements)
		{
			completions = new LinkedList<Autocompletion>();
			context 	= ((Element)contextElement).getAttributeValue(ATTRIBUTE_NAME);
			
			completionElements = ((Element)contextElement).getChildren(ELEMENT_COMPLETION);
			for (Object completion : completionElements)
			{
				input 		= ((Element)completion).getChild(ELEMENT_INPUT);
				replacement = ((Element)completion).getChild(ELEMENT_REPLACEMENT);
				
				ac = new Autocompletion();
				ac.setContext(context);
				if (input != null)
					ac.setInputText(input.getText());
				ac.setReplacementText(replacement.getText());
				ac.setUserId(userId);
				
				completions.add(ac);
			}
			if (contexts.get(context) == null)
				 contexts.put(context, completions);
			else contexts.get(context).addAll(completions);
		}
		
		return contexts;
	}
}
