package com.ejie.ab04b.util;

import java.io.ByteArrayInputStream;
import java.io.StringWriter;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.XMLGregorianCalendar;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.ejie.ab04b.constantes.ConstantesNum;
import com.ejie.ab04b.exception.AB04BException;
import com.sun.org.apache.xerces.internal.jaxp.datatype.DatatypeFactoryImpl;

import weblogic.apache.xpath.XPathAPI;

/**
 * @author GFI-NORTE
 * 
 */
public final class XmlUtils {

	private static final Logger LOGGER = LoggerFactory
			.getLogger(XmlUtils.class);

	private static final String START = "<";
	private static final String END = ">";
	private static final String CLOSE = "/";
	private static final String CDATA_INICIO = "<![CDATA[";
	private static final String CDATA_FIN = "]]>";

	/**
	 * 'XmlUtils'.
	 */
	private XmlUtils() {
	}

	/**
	 * Parses the document 2 string.
	 * 
	 *  node
	 *            Document
	 *  String
	 *
	 * @param node the node
	 * @return the string
	 */
	public static String parseDocument2String(Document node) {
		XmlUtils.LOGGER.debug("INI parseDocumen2String");
		try {
			Source source = new DOMSource(node);
			StringWriter stringWriter = new StringWriter();
			Result result = new StreamResult(stringWriter);
			TransformerFactory factory = TransformerFactory.newInstance();
			Transformer transformer = factory.newTransformer();
			transformer.transform(source, result);
			String resultado = stringWriter.getBuffer().toString();
			XmlUtils.LOGGER.debug("FIN parseDocument2String");
			return resultado;
		} catch (TransformerConfigurationException e) {
			XmlUtils.LOGGER
					.error("Se ha producido un error en el metodo parseDocumen2String: "
							+ e.getMessage());
		} catch (TransformerException e) {
			XmlUtils.LOGGER
					.error("Se ha producido un error en el metodo parseDocumen2String: "
							+ e.getMessage());
		}
		return null;
	}

	/**
	 * Parses the document 2 string.
	 * 
	 *  node
	 *            Document
	 *  String
	 *
	 * @param node the node
	 * @return the string
	 */
	public static String parseDocument2String(Node node) {
		XmlUtils.LOGGER.debug("INI parseDocumen2String");
		try {
			Source source = new DOMSource(node);
			StringWriter stringWriter = new StringWriter();
			Result result = new StreamResult(stringWriter);
			TransformerFactory factory = TransformerFactory.newInstance();
			Transformer transformer = factory.newTransformer();
			transformer.transform(source, result);
			String resultado = stringWriter.getBuffer().toString();
			XmlUtils.LOGGER.debug("FIN parseDocument2String");
			return resultado;
		} catch (TransformerConfigurationException e) {
			XmlUtils.LOGGER
					.error("Se ha producido un error en el metodo parseDocumen2String: "
							+ e.getMessage());
		} catch (TransformerException e) {
			XmlUtils.LOGGER
					.error("Se ha producido un error en el metodo parseDocumen2String: "
							+ e.getMessage());
		}
		return null;
	}

	/**
	 * Obtiene un Document a partir de una cadena.
	 * 
	 *  s
	 *            la cadena
	 *  Document el document
	 *
	 * @param s the s
	 * @return the document
	 */
	public static Document string2Document(String s) {
		XmlUtils.LOGGER.debug("INI string2Document");
		Document tmpX = null;
		DocumentBuilder builder = null;

		try {
			builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
			tmpX = builder.parse(new ByteArrayInputStream(s.getBytes()));
		} catch (Exception e) {
			XmlUtils.LOGGER.error("Error al transformar el String a Document",
					e);
		}
		return tmpX;

	}

	/**
	 * Convierte una fecha de tipo Date a tipo XMLGregorianCalendar.
	 * 
	 *  date
	 *            Date
	 *  XMLGregorianCalendar
	 *
	 * @param date the date
	 * @return the XML gregorian calendar
	 */
	public static XMLGregorianCalendar createXMLGregorianCalendar(Date date) {

		GregorianCalendar gc = new GregorianCalendar();
		gc.setTime(date);

		return XmlUtils.createXMLGregorianCalendar(gc);

	}

	/**
	 * Convierte una fecha de tipo GregorianCalendar a tipo
	 * XMLGregorianCalendar.
	 * 
	 *  gc
	 *            GregorianCalendar
	 *  XMLGregorianCalendar
	 *
	 * @param gc the gc
	 * @return the XML gregorian calendar
	 */
	public static XMLGregorianCalendar createXMLGregorianCalendar(
			GregorianCalendar gc) {

		XMLGregorianCalendar xmlGc = null;

		try {

			xmlGc = DatatypeFactoryImpl.newInstance().newXMLGregorianCalendar();
		} catch (DatatypeConfigurationException e) {
			XmlUtils.LOGGER.debug("createXMLGregorianCalendar: ERROR: {}",
					e.toString());
		} catch (Exception e) {
			XmlUtils.LOGGER.debug(
					"createXMLGregorianCalendar: ERROR: THROWABLE {}",
					e.toString());
		}

		if (gc != null && xmlGc != null) {

			xmlGc.setDay(gc.get(Calendar.DAY_OF_MONTH));
			xmlGc.setMonth(gc.get(Calendar.MONTH) + 1);
			xmlGc.setYear(gc.get(Calendar.YEAR));
			xmlGc.setHour(gc.get(Calendar.HOUR_OF_DAY));
			xmlGc.setMinute(gc.get(Calendar.MINUTE));
			xmlGc.setSecond(gc.get(Calendar.SECOND));
		}

		return xmlGc;

	}

	/**
	 * Start tag.
	 * 
	 *  tag
	 *            String
	 *  String
	 *
	 * @param tag the tag
	 * @return the string
	 */
	public static String startTag(String tag) {
		return (new StringBuffer(XmlUtils.START)).append(tag)
				.append(XmlUtils.END).toString();
	}

	/**
	 * End tag.
	 * 
	 *  tag
	 *            String
	 *  String
	 *
	 * @param tag the tag
	 * @return the string
	 */
	public static String endTag(String tag) {
		return (new StringBuffer(XmlUtils.START)).append(XmlUtils.CLOSE)
				.append(tag).append(XmlUtils.END).toString();
	}

	/**
	 * Start CDATA.
	 * 
	 *  String
	 *
	 * @return the string
	 */
	public static String startCDATA() {
		return (new StringBuffer(XmlUtils.CDATA_INICIO)).toString();
	}

	/**
	 * End CDATA.
	 * 
	 *  String
	 *
	 * @return the string
	 */
	public static String endCDATA() {
		return (new StringBuffer(XmlUtils.CDATA_FIN)).toString();
	}

	/**
	 * Creates the XML tag.
	 * 
	 *  tag
	 *            String
	 *  value
	 *            String
	 *  String
	 *
	 * @param tag the tag
	 * @param value the value
	 * @return the string
	 */
	public static String createXMLTag(String tag, String value) {
		return XmlUtils.createXMLTag(tag, value, true);
	}

	/**
	 * Creates the XML tag.
	 * 
	 *  tag
	 *            String
	 *  value
	 *            String
	 *  obligatorio
	 *            boolean
	 *  String
	 *
	 * @param tag the tag
	 * @param value the value
	 * @param obligatorio the obligatorio
	 * @return the string
	 */
	public static String createXMLTag(String tag, String value,
			boolean obligatorio) {

		StringBuilder buffer = new StringBuilder();
		if (value == null) {
			if (obligatorio) {
				buffer.append(XmlUtils.emptyTag(tag));
			}
		} else {
			buffer.append(XmlUtils.startTag(tag))
					.append(XmlUtils.formatValorXMLTag(value))
					.append(XmlUtils.endTag(tag));
		}
		return buffer.toString();
	}

	/**
	 * Empty tag.
	 * 
	 *  tag
	 *            String
	 *  String
	 *
	 * @param tag the tag
	 * @return the string
	 */
	public static String emptyTag(String tag) {
		return (new StringBuffer(XmlUtils.START)).append(tag)
				.append(XmlUtils.CLOSE).append(XmlUtils.END).toString();
	}

	/**
	 * Format valor XML tag.
	 * 
	 *  value
	 *            String
	 *  String
	 *
	 * @param value the value
	 * @return the string
	 */
	public static String formatValorXMLTag(String value) {
		return null == value ? "" : value;
	}

	/**
	 * Quita la definicion del XML si existe.
	 * 
	 *  strTexto
	 *            texto
	 *  String texto
	 *
	 * @param strTexto the str texto
	 * @return the string
	 */
	public static String quitarDefinicionDocumentoXML(String strTexto) {
		if (strTexto == null || strTexto.trim().length() == 0) {
			return strTexto;
		}
		String strTexto2 = strTexto;
		int intQuitar = strTexto2.indexOf("?>");
		if (intQuitar > 0) {
			strTexto2 = strTexto2.substring(intQuitar + ConstantesNum.NUM_2,
					strTexto2.length());
		}
		return strTexto2;
	}

	/**
	 * Obtener valor nodos X path.
	 * 
	 *  documentoCS
	 *            Document
	 *  xpath
	 *            String
	 *  String[]
	 *
	 * @param documentoCS the documento CS
	 * @param xpath the xpath
	 * @return the string[]
	 * @throws AB04BException the AB 04 B exception
	 */
	public static String[] obtenerValorNodosXPath(Document documentoCS,
			String xpath) throws AB04BException {
		try {
			String[] pathsFunciones = null;

			try {

				NodeList parametros = XPathAPI.selectNodeList(documentoCS,
						xpath);
				pathsFunciones = new String[parametros.getLength()];

				String aux;

				for (int i = 0; i < parametros.getLength(); i++) {
					Node paramPath = ((Node) parametros.item(i));

					if (paramPath != null) {
						aux = paramPath.getNodeValue();

					} else {
						aux = "";
					}

					pathsFunciones[i] = aux;
				}
			} catch (Exception e) {
				throw e;
			}
			return pathsFunciones;
		} catch (Exception e) {
			throw new AB04BException(e, e.getMessage());
		}
	}

}
