package com.ajb.common.utils.string;

import java.io.StringReader;
import java.io.StringWriter;
import java.util.Collection;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlAnyElement;
import javax.xml.namespace.QName;

import org.dom4j.Document;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;

//import org.apache.commons.lang.StringUtils;

/**
 * 使用Jaxb2.0实现XML<->Java Object的Binder.
 * 
 * 特别支持Root对象是List的情形.
 * 
 * @author
 */
public class XmlUtil {
	// 多线程安全的Context.
	private JAXBContext jaxbContext;

	/**
	 * @param types
	 *            所有需要序列化的Root对象的类型.
	 */
	public XmlUtil(Class<?>... types) {
		try {
			jaxbContext = JAXBContext.newInstance(types);
		} catch (JAXBException e) {
//			throw new RuntimeException(e);
			e.printStackTrace();
		}
	}

	/**
	 * Java Object->Xml.
	 */
	public String toXml(Object root, String encoding) {
		try {
			StringWriter writer = new StringWriter();
			createMarshaller(encoding).marshal(root, writer);
			return writer.toString();
		} catch (JAXBException e) {
//			throw new RuntimeException(e);
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * Java Object->Xml, 特别支持对Root Element是Collection的情形.
	 */
	@SuppressWarnings("rawtypes")
	public String toXml(Collection root, String rootName, String encoding) {
		try {
			CollectionWrapper wrapper = new CollectionWrapper();
			wrapper.collection = root;

			JAXBElement<CollectionWrapper> wrapperElement = new JAXBElement<CollectionWrapper>(
					new QName(rootName), CollectionWrapper.class, wrapper);

			StringWriter writer = new StringWriter();
			createMarshaller(encoding).marshal(wrapperElement, writer);

			return writer.toString();
		} catch (JAXBException e) {
//			throw new RuntimeException(e);
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * Xml->Java Object.
	 */
	@SuppressWarnings("unchecked")
	public <T> T fromXml(String xml) {
		if(xml == null || "".equals(xml.trim())){
			return null;
		}
		try {
			StringReader reader = new StringReader(xml);
			return (T) createUnmarshaller().unmarshal(reader);
		} catch (JAXBException e) {
//			throw new RuntimeException(e);
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * Xml->Java Object, 支持大小写敏感或不敏感.
	 */
	@SuppressWarnings("unchecked")
	public <T> T fromXml(String xml, boolean caseSensitive) {
		try {
			String fromXml = xml;
			if (!caseSensitive){
				fromXml = xml.toLowerCase();
			}
			StringReader reader = new StringReader(fromXml);
			return (T) createUnmarshaller().unmarshal(reader);
		} catch (JAXBException e) {
//			throw new RuntimeException(e);
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * 创建Marshaller, 设定encoding(可为Null).
	 */
	public Marshaller createMarshaller(String encoding) {
		try {
			Marshaller marshaller = jaxbContext.createMarshaller();

			marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);

//			if (StringUtils.isNotBlank(encoding)) {
			if(encoding != null && !"".equals(encoding.trim())){
				marshaller.setProperty(Marshaller.JAXB_ENCODING, encoding);
			}
			return marshaller;
		} catch (JAXBException e) {
//			throw new RuntimeException(e);
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * 创建UnMarshaller.
	 */
	public Unmarshaller createUnmarshaller() {
		try {
			return jaxbContext.createUnmarshaller();
		} catch (JAXBException e) {
//			throw new RuntimeException(e);
			return null;
		}
	}

	/**
	 * 封装Root Element 是 Collection的情况.
	 */
	public static class CollectionWrapper {
//		@SuppressWarnings("unchecked")
		@SuppressWarnings("rawtypes")
		@XmlAnyElement
		protected Collection collection;
	}
	public static String getNodeValue(String xml,String nodeName){
		String nodeValue = null;
		if(xml != null && xml.length() > 0){
			String head = "<"+nodeName+">";
			String tail = "</"+nodeName+">";
			if(xml.contains(head) && xml.contains(tail)){
				int beginIndex = xml.indexOf(head)+head.length();
				int endIndex = xml.indexOf(tail);
				nodeValue = xml.substring(beginIndex, endIndex);
				if(nodeValue != null && nodeValue.length() >0){
					if(nodeValue.startsWith("<![CDATA[") && nodeValue.endsWith("]]>")){
						nodeValue = nodeValue.substring(9, nodeValue.length()-3);
					}
				}
			}
		}
		return nodeValue;
	}
	public static String format(String str) {
		if(str == null || "".equals(str.trim())){
			return null;
		}
		String formatXml = str;
		try{
		    SAXReader reader = new SAXReader();
		    // System.out.println(reader);
		    // 注释：创建一个串的字符输入流
		    StringReader in = new StringReader(str);
		    Document doc = reader.read(in);
		    // System.out.println(doc.getRootElement());
		    // 注释：创建输出格式
		    OutputFormat formater = OutputFormat.createPrettyPrint();
		    //formater=OutputFormat.createCompactFormat();
		    // 注释：设置xml的输出编码
		    formater.setEncoding("utf-8");
		    // 注释：创建输出(目标)
		    StringWriter out = new StringWriter();
		    // 注释：创建输出流
		    XMLWriter writer = new XMLWriter(out, formater);
		    // 注释：输出格式化的串到目标中，执行后。格式化后的串保存在out中。
		    writer.write(doc);
		  
		    writer.close();
//		    System.out.println(out.toString());
		    // 注释：返回我们格式化后的结果
		    formatXml = out.toString();
		}catch(Exception e){
			e.printStackTrace();
		}
		return formatXml;
	}
	  
	public static void main(String[] args){
		String xml = ""
				+"<xml><return_code><![CDATA[SUCCESS]]></return_code>"
				+"<return_msg><![CDATA[OK]]></return_msg>"
				+"<appid><![CDATA[wx350e0551f15c891d]]></appid>"
				+"<mch_id><![CDATA[1467966602]]></mch_id>"
				+"<nonce_str><![CDATA[sIKggVGaBFGavGlA]]></nonce_str>"
				+"<sign><![CDATA[845C8A7FF9A0D456DB2E7C8D68B1CAD3]]></sign>"
				+"<result_code><![CDATA[SUCCESS]]></result_code>"
				+"<prepay_id><![CDATA[wx20170509102930c05e819bdf0584738530]]></prepay_id>"
				+"<trade_type><![CDATA[NATIVE]]></trade_type>"
				+"<code_url><![CDATA[weixin://wxpay/bizpayurl?pr=FrUICJf]]></code_url>"
				+"</xml>";
		String nodeName = "result_code";// "return_code";
		String nodeValue = null;
		if(xml != null && xml.length() > 0){
			String head = "<"+nodeName+">";
			String tail = "</"+nodeName+">";
			if(xml.contains(head) && xml.contains(tail)){
				int beginIndex = xml.indexOf(head)+head.length();
				int endIndex = xml.indexOf(tail);
				nodeValue = xml.substring(beginIndex, endIndex);
				if(nodeValue != null && nodeValue.length() >0){
					if(nodeValue.startsWith("<![CDATA[") && nodeValue.endsWith("]]>")){
						nodeValue = nodeValue.substring(9, nodeValue.length()-3);
					}
				}
			}
		}
		System.out.println(nodeValue);
	}
}

