package xyz.wbsite.dbtool.javafx.manger;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import xyz.wbsite.dbtool.javafx.annotation.Property;
import xyz.wbsite.dbtool.javafx.po.DataBase;
import xyz.wbsite.dbtool.javafx.po.FieldType;
import xyz.wbsite.dbtool.javafx.po.Field;
import xyz.wbsite.dbtool.javafx.po.Module;
import xyz.wbsite.dbtool.javafx.po.Project;
import xyz.wbsite.dbtool.javafx.po.Table;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class XmlManager {

    public Project inflate(File xmlFile) {
        Project project = new Project();

        if (xmlFile == null) {
            return project;
        } else if (!xmlFile.exists()) {
            System.err.println("文件不存在!");
        } else {
            //开始解析
            DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
            FileInputStream inputStream = null;
            try {
                inputStream = new FileInputStream(xmlFile);
                Document document = documentBuilderFactory.newDocumentBuilder().parse(inputStream);

                Element dbElement = document.getDocumentElement();

                if ("project".endsWith(dbElement.getNodeName())) {
                    System.out.println("加载模型[" + xmlFile.getName() + "]");

                    java.lang.reflect.Field[] declaredFields = project.getClass().getDeclaredFields();

                    for (java.lang.reflect.Field declaredField : declaredFields) {
                        boolean annotationPresent = declaredField.isAnnotationPresent(Property.class);
                        if (annotationPresent) {
                            Property annotation = declaredField.getAnnotation(Property.class);
                            String value = annotation.value();

                            NodeList nodeName = dbElement.getElementsByTagName(value);
                            if (nodeName.getLength() == 1) {
                                String textContent = nodeName.item(0).getTextContent();

                                declaredField.setAccessible(true);
                                if (declaredField.getType() == String.class) {
                                    declaredField.set(project, textContent);
                                } else if (declaredField.getType() == DataBase.class) {
                                    DataBase dataBase = null;
                                    try {
                                        dataBase = DataBase.valueOf(textContent);
                                    } catch (IllegalArgumentException e) {
                                        dataBase = DataBase.MySQL;
                                    }
                                    declaredField.set(project, dataBase);
                                } else if (declaredField.getType() == Boolean.class || declaredField.getType() == boolean.class) {
                                    declaredField.setBoolean(project, getBoolean(textContent));
                                }
//                                System.out.println("读取" + value + "=" + textContent);
                            }
                        }
                    }

                    NodeList modules = dbElement.getElementsByTagName("module");
                    if (modules.getLength() > 0) {

                        for (int i = 0; i < modules.getLength(); i++) {
                            Module module = new Module();
                            Element moduleElement = (Element) modules.item(i);

                            NodeList moduleName = moduleElement.getElementsByTagName("moduleName");
                            if (moduleName.getLength() == 1) {
                                module.setModuleName(moduleName.item(0).getTextContent());
                            }

                            NodeList moduleComment = moduleElement.getElementsByTagName("moduleComment");
                            if (moduleComment.getLength() == 1) {
                                module.setModuleComment(moduleComment.item(0).getTextContent());
                            }

                            NodeList modulePrefix = moduleElement.getElementsByTagName("modulePrefix");
                            if (modulePrefix.getLength() == 1) {
                                module.setModulePrefix(modulePrefix.item(0).getTextContent());
                            }

                            NodeList tables = moduleElement.getElementsByTagName("table");
                            if (tables.getLength() > 0) {
                                for (int j = 0; j < tables.getLength(); j++) {
                                    Element tableElement = (Element) tables.item(j);
                                    Table table = new Table();

                                    NodeList fields = tableElement.getElementsByTagName("field");
                                    if (fields.getLength() > 0) {
                                        for (int k = 0; k < fields.getLength(); k++) {
                                            Element fieldElement = (Element) fields.item(k);
                                            Field field = new Field();
                                            field.setFieldName(fieldElement.getAttribute("fieldName"));
                                            field.setFieldType(FieldType.parse(fieldElement.getAttribute("fieldType")));
                                            field.setFieldLength(Integer.parseInt(fieldElement.getAttribute("fieldLength")));
                                            field.setFieldComment(fieldElement.getAttribute("fieldComment"));
                                            field.setDefaultValue(fieldElement.getAttribute("defaultValue"));
                                            field.setIsSystem(getBoolean(fieldElement.getAttribute("IsSystem")));
                                            field.setIsMust(getBoolean(fieldElement.getAttribute("isMust")));
                                            field.setIsPrimaryKey(getBoolean(fieldElement.getAttribute("isPrimaryKey")));
                                            field.setIsQuery(getBoolean(fieldElement.getAttribute("isQuery")));
                                            field.setIsSearch(getBoolean(fieldElement.getAttribute("isSearch")));
                                            table.putField(field);
                                        }
                                    }
                                    table.setdBhandle(module);
                                    table.setTableName(tableElement.getAttribute("tableName"));
                                    table.setTableComment(tableElement.getAttribute("tableComment"));
                                    table.setCreate(getBoolean(tableElement.getAttribute("create")));
                                    table.setDelete(getBoolean(tableElement.getAttribute("delete")));
                                    table.setUpdate(getBoolean(tableElement.getAttribute("update")));
                                    table.setFind(getBoolean(tableElement.getAttribute("find")));
                                    table.setGet(getBoolean(tableElement.getAttribute("get")));
                                    table.setSearch(getBoolean(tableElement.getAttribute("search")));
                                    table.setHtml(getBoolean(tableElement.getAttribute("html")));
                                    table.setSys(getBoolean(tableElement.getAttribute("sys")));

                                    module.putTable(table);
                                }
                            }
                            project.putModule(module);
                        }
                    }
                    System.out.println("模型初始化成功...");
                    return project;
                }
            } catch (Exception e) {
                System.out.println("文件：'" + xmlFile.getName() + "'解析失败!请检查语法是否正确!");
                e.printStackTrace();
            } finally {
                if (inputStream != null) {
                    try {
                        inputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        return project;
    }

    public boolean saveAs(File path, Project project) {
        DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder;
        //生成DOM模型
        try {
            builder = dbFactory.newDocumentBuilder();
            Document doc = builder.newDocument();

            Element rootProject = doc.createElement("project");
            doc.appendChild(rootProject);

            java.lang.reflect.Field[] declaredFields = project.getClass().getDeclaredFields();

            for (java.lang.reflect.Field declaredField : declaredFields) {
                try {
                    boolean annotationPresent = declaredField.isAnnotationPresent(Property.class);
                    if (annotationPresent) {
                        Property annotation = declaredField.getAnnotation(Property.class);
                        String value = annotation.value();
                        Element element = doc.createElement(value);
                        declaredField.setAccessible(true);
                        Object valuer = declaredField.get(project);
                        element.setTextContent(String.valueOf(valuer));
                        rootProject.appendChild(element);
//                        System.out.println("写入" + value + "=" + String.valueOf(valuer));
                    }
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }

            Element modules = doc.createElement("modules");
            rootProject.appendChild(modules);

            //region Description
            for (Module md : project.getModules()) {
                Element module = doc.createElement("module");

                Element moduleName = doc.createElement("moduleName");
                Element moduleComment = doc.createElement("moduleComment");
                Element modulePrefix = doc.createElement("modulePrefix");
                Element hasSysFields = doc.createElement("hasSysFields");
                moduleName.setTextContent(md.getModuleName());
                moduleComment.setTextContent(md.getModuleComment());
                modulePrefix.setTextContent(md.getModulePrefix());
                module.appendChild(moduleComment);
                module.appendChild(modulePrefix);
                module.appendChild(moduleName);
                module.appendChild(hasSysFields);

                Element tables = doc.createElement("tables");
                module.appendChild(tables);
                for (Table t : md.getTables()) {
                    Element table = doc.createElement("table");
                    table.setAttribute("tableName", t.getTableName());
                    table.setAttribute("tableComment", t.getTableComment());
                    table.setAttribute("create", Boolean.toString(t.getCreate()));
                    table.setAttribute("delete", Boolean.toString(t.getDelete()));
                    table.setAttribute("update", Boolean.toString(t.getUpdate()));
                    table.setAttribute("find", Boolean.toString(t.getFind()));
                    table.setAttribute("get", Boolean.toString(t.getGet()));
                    table.setAttribute("search", Boolean.toString(t.getSearch()));
                    table.setAttribute("html", Boolean.toString(t.getHtml()));
                    table.setAttribute("sys", Boolean.toString(t.getSys()));

                    Element fields = doc.createElement("fields");

                    table.appendChild(fields);

                    for (Field f : t.getFields()) {
                        Element field = doc.createElement("field");
                        field.setAttribute("fieldName", f.getFieldName());
                        if (f.getFieldType() != null) {
                            field.setAttribute("fieldType", f.getFieldType().name());
                        }
                        if (f.getFieldLength() != null) {
                            field.setAttribute("fieldLength", f.getFieldLength().toString());
                        }
                        field.setAttribute("fieldComment", f.getFieldComment());
                        field.setAttribute("defaultValue", f.getDefaultValue());
                        if (f.getIsMust() != null) {
                            field.setAttribute("isMust", f.getIsMust().toString());
                        }
                        field.setAttribute("isQuery", f.getIsQuery().toString());
                        field.setAttribute("isSearch", f.getIsSearch().toString());
                        if (f.getIsPrimaryKey() != null) {
                            field.setAttribute("isPrimaryKey", f.getIsPrimaryKey().toString());
                        }
                        if (f.getIsSystem() != null) {
                            field.setAttribute("IsSystem", f.getIsSystem().toString());
                        }
                        fields.appendChild(field);
                    }
                    tables.appendChild(table);
                }
                modules.appendChild(module);
            }
            //endregion

            //输出文件
            FileOutputStream stream = null;
            try {
                Transformer t = TransformerFactory.newInstance().newTransformer();

                //设置换行和缩进
                t.setOutputProperty(OutputKeys.INDENT, "yes");
                t.setOutputProperty(OutputKeys.METHOD, "xml");

                if (!path.exists()) {
                    path.mkdirs();
                }
                File file = new File(path, project.getProjectName() + ".xml");
                if (!file.exists()) {
                    file.createNewFile();
                }
                stream = new FileOutputStream(file);
                t.transform(new DOMSource(doc), new StreamResult(stream));
                System.out.println("[" + file.getName() + "]保存成功!");
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            } finally {
                if (stream != null) {
                    try {
                        stream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
            e.printStackTrace();
            return false;
        }
        return true;
    }

    private boolean getBoolean(String str) {
        if (str != null && str.matches("true|1")) {
            return true;
        }
        return false;
    }
}
