package com.ann.demo.utils;

import com.alibaba.fastjson.JSON;
import com.ann.demo.entity.constant.AliasName;
import com.ann.demo.entity.constant.InterfaceName;
import com.ann.demo.entity.filing.EMRData;
import com.ann.demo.entity.filing.dto.MessageDto;
import com.ann.demo.entity.interfaceEntity.*;
import com.ann.demo.entity.normalEntity.OutPara;
import org.dom4j.*;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.XMLFilterImpl;

import javax.annotation.PostConstruct;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Type;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @Description
 * @Date 2019/6/17 15:14
 * @Created by  ljx
 */
@Component
public class XMLUtils {

    static final Logger logger = LoggerFactory.getLogger(XMLUtils.class);

    private static final String DEFAULT_ENCODING = "UTF-8";

    private static final Map<String, String> map;

    static {
        map = new HashMap<String, String>();
        map.put("ns", "urn:hl7-org:v3");
    }


    // 扫描文件
    public static String scanningFilePath;
    @Value("${file.scanningFilePath}")
    private String scanningFilePathTemp;

    @PostConstruct
    public void init() {
        scanningFilePath = scanningFilePathTemp;
    }

    private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddhhmmss");
    // 病案首页独享
    private static SimpleDateFormat simpleDateFormat1 = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss");


    //--------------------------------------------向外抛出异常
    public static MessageDto xpathToBean(String xmlStr, Class tClass, String source) {
        MessageDto messageDto = null;
        Document doc = null;
        Object obj = null;
        try {
            xmlStr = xmlStr.replaceAll("&", "&amp;");
            SAXReader saxReader = new SAXReader();
            saxReader.setXMLFilter(new XMLFilterImpl() {
                @Override
                public void characters(char[] ch, int start, int length) throws SAXException {
                    String text = new String(ch, start, length);
                    if (length == 1) {
                        if ((int) ch[0] == 160) {
                            char[] escape = " ".toCharArray();
                            super.characters(escape, 0, escape.length);
                            return;
                        }
                    }
                    super.characters(ch, start, length);
                }
            });
            doc = saxReader.read(new ByteArrayInputStream(xmlStr.getBytes("UTF-8")), "UTF-8");
            if (tClass != null) {
                messageDto = getInstance(source);
                obj = tClass.newInstance();
            } else {
                // 是检查报告的接口
                String str = "/ns:ClinicalDocument/ns:component/ns:structuredBody/ns:component/ns:section/ns:entry/ns:observation/ns:code[@displayName='检查报告科室']/../ns:value/text()";
                //-----------------------存在一个错误 如果str找不到 就会向外抛出异常org.apache.cxf.interceptor.Fault: org/jaxen/JaxenException
                XPath x = doc.createXPath(str);
                x.setNamespaceURIs(map);

                Node node = x.selectSingleNode(doc);
                if (node != null) {
                    messageDto = getInstance(node.getText());
                    if (messageDto != null) {
                        obj = messageDto.getObject();
                    }
                }
            }
            if (obj != null && messageDto != null) {
                if (messageDto.getPropertiesPath() != null) {
                    // 加载配置文件
                    InputStream inputStream = new BufferedInputStream(new FileInputStream(new File(messageDto.getPropertiesPath())));
                    Properties properties = new Properties();
                    //加载格式化后的流
                    properties.load(new InputStreamReader(inputStream, DEFAULT_ENCODING));

                    Enumeration<?> enumeration = properties.propertyNames();
                    while (enumeration.hasMoreElements()) {
                        String key = (String) enumeration.nextElement();
                        String xpath = properties.getProperty(key);
                        XPath x = doc.createXPath(xpath);
                        x.setNamespaceURIs(map);
                        // 根据properties的value获取xml的value
                        String value = "";
                        Node node = x.selectSingleNode(doc);
                        if (node != null) {
                            value = node.getText();
                        }
                        // 判断属性是否存在
                        String objField = existsField(obj.getClass(), key);
                        if (objField != null) {
                            PropertyDescriptor descriptor = new PropertyDescriptor(key, obj.getClass());
                            if (("class java.util.Date").equals(objField)) {
                                if (value != null && value.length() > 0) {
                                    Date parse = simpleDateFormat.parse(value, new ParsePosition(0));
                                    descriptor.getWriteMethod().invoke(obj, parse);
                                }
                            } else {
                                descriptor.getWriteMethod().invoke(obj, value);
                            }
                        }
                        String messageField = existsField(messageDto.getClass(), key);
                        if (messageField != null) {
                            PropertyDescriptor propertyDescriptor = new PropertyDescriptor(key, messageDto.getClass());
                            // 给messageDto赋值
                            if (("class java.util.Date").equals(messageField)) {
                                if (value != null && value.length() > 0) {
                                    propertyDescriptor.getWriteMethod().invoke(messageDto, simpleDateFormat.parse(value, new ParsePosition(0)));
                                }
                            } else {
                                propertyDescriptor.getWriteMethod().invoke(messageDto, value);
                            }
                        }
                    }
                    // 将对象转成json
                    messageDto.setObject(JSON.toJSONString(obj));
                    // return JSON.toJSONString(messageDto);
                    return messageDto;
                }
            }
        } catch (DocumentException e) {
            logger.error("出错咯！错误信息:" + e);
        } catch (UnsupportedEncodingException e) {
            logger.error("出错咯！错误信息:" + e);
        } catch (FileNotFoundException e) {
            logger.error("出错咯！错误信息:" + e);
        } catch (IOException e) {
            logger.error("出错咯！错误信息:" + e);
        } catch (IllegalAccessException e) {
            logger.error("出错咯！错误信息:" + e);
        } catch (IntrospectionException e) {
            logger.error("出错咯！错误信息:" + e);
        } catch (InvocationTargetException e) {
            logger.error("出错咯！错误信息:" + e);
        } catch (InstantiationException e) {
            logger.error("出错咯！错误信息:" + e);
        }
        return null;
    }

    public static MessageDto getInstance(String source) {
        MessageDto messageDto = null;
        // 根据source判断是哪个实体类
        switch (source) {
            case InterfaceName.SCANNING_FILE:
                messageDto = new MessageDto(EMRData.class.getName(), new EMRData(), AliasName.SCANNING_FILE, scanningFilePath, InterfaceName.SCANNING_FILE);
                break;

        }
        return messageDto;
    }

    public static String existsField(Class clz, String fieldName) {
        try {
            Field declaredField = clz.getDeclaredField(fieldName);
            if (declaredField != null) {
                return declaredField.getGenericType().toString();
            }
        } catch (Exception e) {
        }
        return null;
    }

    /**
     * 生成普通xml字符串
     */
    public static String generateXmlStr(OutPara outPara) {
        try {
            Field[] fields = outPara.getClass().getDeclaredFields();
            // 创建XML
            Document document = DocumentHelper.createDocument();
            Element response = document.addElement("RESPONSE");
            for (Field field : fields) {
                field.setAccessible(true);
                response
                        .addElement(field.getName())
                        .addText(field.get(outPara).toString());
            }
            return document.getRootElement().asXML();
        } catch (IllegalAccessException e) {
            logger.error("出错咯！生成普通xml字符串错误信息:" + e);
        }
        return null;
    }

}