package eu.dnetlib.enabling.inspector;

import java.io.StringReader;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;

import com.google.common.collect.Maps;

import eu.dnetlib.miscutils.datetime.DateUtils;
import eu.dnetlib.miscutils.dom4j.XPathHelper;

/**
 * Utility class that provides the "touch" functionality
 * 
 * @author claudio
 *
 */
public class TouchUtils {

	/**
	 * logger
	 */
	private static final Log log = LogFactory.getLog(TouchUtils.class);
	
	/**
	 * Updates the date value of the given xpath
	 * 
	 * @param file
	 * @param xpath
	 * @return
	 * @throws DocumentException
	 */
	public String updateProfile(String file, String xpath) throws DocumentException {
		SAXReader reader = new SAXReader();

		log.debug("updating XPath: " + xpath);
		Document document = reader.read(new StringReader(file));

		Node node = document.selectSingleNode(xpath);

		if (node == null || (node.getNodeType() != Node.ELEMENT_NODE && node.getNodeType() != Node.ATTRIBUTE_NODE))
			throw new DocumentException("Invalid xpath: " + xpath + ": " + node);

		if (verifyIsDate(node.getText()))
			node.setText(DateUtils.now_ISO8601());

		return document.asXML();
	}

	/**
	 * 
	 * @param text
	 *            is the value to check
	 * @return true if text is a well formatted timestamp
	 */
	protected boolean verifyIsDate(String text) {
		try {
			new DateUtils().parse(text);
			return true;
		} catch (IllegalStateException e) {
			return false;
		}
	}

	/**
	 * Adds "<span id='xpath'>item</span>" where: - item is an element or an attribute name - xpath is the corresponding
	 * xpath
	 * 
	 * @param file
	 * @return the "spanized" xml file
	 */
	protected String spanize(String file) {
		SAXReader reader = new SAXReader();
		try {
			Document document = reader.read(new StringReader(file));
			traverse(document.getRootElement(), "/*");
			
			//TODO find a solution to this crime (damn dom4j!)
			return document.asXML().replace("&apos;", "'");
		} catch (DocumentException e) {
			log.warn(e);
			return e.getMessage();
		}
	}

	private void traverse(Element element, String xpathFather) {
		int i = 1;

		for (Element node : XPathHelper.selectElements(element, "./*")) {
			String xpath = xpathFather + "/*[" + (i++) + "]";

			Map<Attribute, String> attributeXPaths = Maps.newHashMap();

			@SuppressWarnings("unchecked")
			List<Attribute> attributes = (List<Attribute>) node.attributes();
			for (Attribute attribute : attributes)
				attributeXPaths.put(attribute, xpath + "/@" + attribute.getName());

			node.attributes().clear();
			for (Entry<Attribute, String> entry : attributeXPaths.entrySet()) {
				Attribute attribute = entry.getKey();
				String modifiedName = "_|span id='" + entry.getValue() + "'|_" + attribute.getName() + "_|/span|_";

				node.addAttribute(modifiedName, attribute.getValue());
			}
			if (node.isTextOnly())
				node.setName("_|span id='" + xpath + "'|_" + node.getName() + "_|/span|_");
			traverse(node, xpath);
		}
	}

	/**
	 * 
	 * @param file
	 * @return
	 */
	public String escape(String file) {
		return file.replace("_|", "<").replace("|_", ">");
	}
	
}
