package cn.edu.whu.boot.xml.xmlreader;

import cn.edu.whu.boot.xml.xmlreader.bean.Config;
import cn.edu.whu.boot.xml.xmlreader.bean.Layer;
import cn.edu.whu.boot.xml.xmlreader.bean.Meta;
import cn.edu.whu.boot.xml.xmlreader.bean.Table;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.ParameterizedType;
import java.util.*;

/**
 * @author Li Bozhao
 */
public class XmlTemplateReader {

    //path的相对路径格式src/res/books.xml
    public static Config read(String path) {
        // 解析books.xml文件
        // 创建SAXReader的对象reader
        Config config = new Config();
        SAXReader reader = new SAXReader();
        try {
            // 通过reader对象的read方法加载books.xml文件,获取docuemnt对象。
            Document document = reader.read(new File(path));
            // 通过document对象获取根节点config
            Element root = document.getRootElement();
            // 通过element对象的elementIterator方法获取迭代器
            Iterator<Element> it = root.elementIterator();
            // 遍历迭代器，获取根节点中的信息
            while (it.hasNext()) {
                Element element = it.next();
                if(config.getMeta()==null && element.getName().equals("meta")){
                    solveMeta(element, config);
                }else if(config.getTables()==null && element.getName().equals("tables")){
                    solveTables(element, config);
                }
//                List<Attribute> bookAttrs = book.attributes();
//                for (Attribute attr : bookAttrs) {
//                    System.out.println("属性名：" + attr.getName() + "--属性值："
//                            + attr.getValue());
//                }
//                Iterator itt = book.elementIterator();
//                while (itt.hasNext()) {
//                    Element bookChild = (Element) itt.next();
//                    System.out.println("节点名：" + bookChild.getName() + "--节点值：" + bookChild.getStringValue());
//                }
            }
        } catch (DocumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return config;
    }
    private static void solveMeta(Element metaElement, Config config){
        Meta meta = new Meta();
        Iterator<Element> it = metaElement.elementIterator();
        while(it.hasNext()){
            Element element = it.next();
            switch (element.getName()){
                case "drawtool":
//                    meta.setDrawTool(solveList(element,"type","name"));
                    meta.setDrawTool(solveListWithGroup(element));
                    break;
                case "position":
//                    meta.setPosition(solveList(element,"type","name"));
                    meta.setPosition(solveList(element));
                    break;
                case "basemap":
                    meta.setBaseMap(solveListClass(element,null, Layer.class));
                    break;
                case "operationlayers":
                    meta.setOperationLayers(solveListClass(element,null, Layer.class));
                    break;
            }
        }
        config.setMeta(meta);
    }
    private static void solveTables(Element tablesElement, Config config){
        Map<String,Table> tables = solveMapClass(tablesElement,"key",null, Table.class);
        config.setTables(tables);
    }
    // 通用工具类
    // 通用工具类
    private static List<String> solveList(Element element){
        List<String> result = new ArrayList<>();
        Iterator<Element> it = element.elementIterator();
        while(it.hasNext()){
            Element sub = it.next();
            if(sub.getName().equals("type")){
                Attribute attr = sub.attribute("name");
                if(attr!=null)
                    result.add(attr.getValue());
            }
        }
        return result;
    }
    private static Map<String, List<String>> solveListWithGroup(Element element){
        Map<String, List<String>> result = new HashMap<>();
        List<String> defaultList = new ArrayList<>();
        Iterator<Element> it = element.elementIterator();
        while(it.hasNext()){
            Element sub = it.next();
            if(sub.getName().equals("type")){
                Attribute attr = sub.attribute("name");
                if(attr!=null)
                    defaultList.add(attr.getValue());
            }else if(sub.getName().equals("group")){
                Attribute attr = sub.attribute("key");
                String key = attr.getValue();
                List<String> list = solveList(sub);
                result.put(key, list);
            }
        }
        result.put("default", defaultList);
        return result;
    }
//    private static List<String> solveList(Element element, String label,String attribute){
//        List<String> result = new ArrayList<>();
//        Iterator<Element> it = element.elementIterator();
//        while(it.hasNext()){
//            Element sub = it.next();
//            if(sub.getName().equals(label)){
//                Attribute attr = sub.attribute(attribute);
//                if(attr!=null)
//                    result.add(attr.getValue());
//            }
//        }
//        return result;
//    }
    private static <T> List<T> solveListClass(Element element,String label, Class<T> clazz) {
        List<T> result = new ArrayList<>();
        Iterator<Element> it = element.elementIterator();
        while(it.hasNext()){
            Element sub = it.next();
            if(label!=null && !sub.getName().equals(label))
                continue;
            T item = solveClass(sub,clazz);
            if(item!=null)
                result.add(item);
        }
        return result;
    }
    private static <T> Map<String,T> solveMapClass(Element element,String key,String label, Class<T> clazz){
        if(key==null)
            key = "key";
        Map<String,T> result = new HashMap<>();
        Iterator<Element> it = element.elementIterator();
        while(it.hasNext()){
            Element sub = it.next();
            if(label!=null && !sub.getName().equals(label))
                continue;
            T item = solveClass(sub,key,clazz);
            if(item==null)
                continue;
            Object value = null;
            try {
                value = clazz.getMethod("get" + upperFirstLetter(key)).invoke(item);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
            if(value!=null)
                result.put(value.toString(), item);
        }
        return result;
    }
    private static <T> T solveClass(Element element,Class<T> clazz) {
        return solveClass(element,null, clazz);
    }
    private static <T> T solveClass(Element element,String key, Class<T> clazz) {
        T result = null;
        try {
            result = clazz.newInstance();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
        if(result==null)
            return null;
        List<Attribute> attributes = element.attributes();
        for(Attribute attribute:attributes){
            addValue(attribute,result,clazz);
        }
        //获取关联的子元素并赋值
        List<Element> elements = element.elements();
        Set<String> set = new HashSet<>();
        for(Element child:elements){
            set.add(child.getName());
        }
        //这里就是List和Map
        for(String label:set){
            String fieldName = label+"s";
            Field field = null;
            try {
                field = clazz.getDeclaredField(fieldName);
                if(field==null)
                    continue;
                Object item = null;
                if(field.getType() == List.class){
                    ParameterizedType pt = (ParameterizedType) field.getGenericType() ;
                    Class clz = (Class) pt.getActualTypeArguments()[0];//这里可以记录relationTable类
                    item = solveListClass(element,label,clz);

                }else if (field.getType() == Map.class){
                    ParameterizedType pt = (ParameterizedType) field.getGenericType() ;
                    Class clz = (Class) pt.getActualTypeArguments()[1];
                    item = solveMapClass(element,key,label,clz);

                }
                if(item!=null) {
                    try {
                        clazz.getMethod("set" + upperFirstLetter(fieldName),field.getType()).invoke(result,item);
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    } catch (InvocationTargetException e) {
                        e.printStackTrace();
                    } catch (NoSuchMethodException e) {
                        e.printStackTrace();
                    }
                }
            } catch (NoSuchFieldException e) {
                // 忽略不存在的字段
                continue;
            }
        }

        return result;
    }
    private static <T> void addValue(Attribute attribute,T data, Class<T> clazz){
        String fieldName = attribute.getName();
        String value = attribute.getValue();
        Field field = null;
        try {
            field = clazz.getDeclaredField(fieldName);
            if(field==null)
                return;
            Object v;
            switch (field.getType().getSimpleName()){
                case "Integer":
                case "int":
                    v = Integer.parseInt(value);
                    break;
                case "String":
                    v = value;
                    break;
                case "Double":
                case "double":
                    v = Double.parseDouble(value);
                    break;
                case "Float":
                case "float":
                    v = Float.parseFloat(value);
                    break;
                case "Boolean":
                case "boolean":
                    v = Boolean.parseBoolean(value);
                    break;
                case "byte[]":
                    v = value.getBytes();
                    break;
                case "Long":
                case "long":
                    v = Long.parseLong(value);
                    break;
                case "Short":
                case "short":
                    v = Short.parseShort(value);
                    break;
                default:
                    v = value;
                    break;
            }
            try {
                clazz.getMethod("set" + upperFirstLetter(fieldName),field.getType()).invoke(data,v);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
        } catch (NoSuchFieldException e) {
            // 忽略不存在的字段
            return;
        }
    }
    private static String upperFirstLetter(String columnName) {
        StringBuilder builder = new StringBuilder(columnName);
        String firstLetter = columnName.substring(0, 1).toUpperCase();
        builder.replace(0, 1, firstLetter);
        return builder.toString();
    }
}

