package com.cm.common.plugin.service.dynamic.config.impl;

import com.cm.common.base.AbstractService;
import com.cm.common.config.properties.FileProperties;
import com.cm.common.constants.ISystemConstant;
import com.cm.common.exception.RemoveException;
import com.cm.common.exception.SaveException;
import com.cm.common.exception.SearchException;
import com.cm.common.exception.UpdateException;
import com.cm.common.plugin.dao.dynamic.config.IDynamicConfigTableDao;
import com.cm.common.plugin.enums.dynamic.FieldTypeEnum;
import com.cm.common.plugin.pojo.dtos.database.table.TableDTO;
import com.cm.common.plugin.pojo.dtos.dynamic.config.DynamicConfigTableDTO;
import com.cm.common.plugin.pojo.dtos.dynamic.config.form.DynamicConfigFormDTO;
import com.cm.common.plugin.pojo.vos.dynamic.DynamicFormFieldVO;
import com.cm.common.plugin.pojo.vos.dynamic.DynamicFormVO;
import com.cm.common.plugin.pojo.vos.dynamic.config.DynamicConfigTableVO;
import com.cm.common.plugin.pojo.vos.dynamic.config.EmptyProjectVO;
import com.cm.common.plugin.service.dynamic.IDynamicFormService;
import com.cm.common.plugin.service.dynamic.IDynamicTableService;
import com.cm.common.plugin.service.dynamic.config.IDynamicConfigTableService;
import com.cm.common.plugin.service.dynamic.config.form.IDynamicConfigFormService;
import com.cm.common.pojo.ListPage;
import com.cm.common.result.SuccessResult;
import com.cm.common.result.SuccessResultList;
import com.cm.common.utils.*;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * When you feel like quitting. Think about why you started
 * 当你想要放弃的时候，想想当初你为何开始
 *
 * @ClassName: DynamicConfigTableServiceImpl
 * @Description: 动态配置-表
 * @Author: WangGeng
 * @Date: 2019/12/7 6:11 下午
 * @Version: 1.0
 **/
@Service
public class DynamicConfigTableServiceImpl extends AbstractService implements IDynamicConfigTableService {

    @Autowired
    private IDynamicConfigTableDao dynamicConfigTableDao;
    @Autowired
    private IDynamicConfigFormService dynamicConfigFormService;
    @Autowired
    private IDynamicTableService dynamicTableService;
    @Autowired
    private IDynamicFormService dynamicFormService;
    @Autowired
    private FileProperties fileProperties;
    @Autowired
    private FreeMarkerConfigurer freeMarkerConfigurer;

    @Override
    public SuccessResult saveTable(DynamicConfigTableVO dynamicConfigTableVO) throws Exception {
        Map<String, Object> params = HashMapUtil.beanToMap(dynamicConfigTableVO);
        params.put("id", UUIDUtil.getUUID());
        params.put("isCreate", 0);
        setSaveInfo(params);
        dynamicConfigTableDao.saveTable(params);
        return new SuccessResult();
    }

    @Override
    public SuccessResult saveDynamicTable(String id) throws SearchException, SaveException {
        Map<String, Object> params = getHashMap(1);
        params.put("id", id);
        LOG.debug("获取动态表信息");
        DynamicConfigTableDTO dynamicConfigTableDTO = dynamicConfigTableDao.getTableById(params);
        TableDTO tableDTO = dynamicTableService.getTableByTableName(dynamicConfigTableDTO.getTableName());
        if (tableDTO != null) {
            throw new SaveException("该动态表已经存在");
        }
        params.clear();
        params.put("tableName", dynamicConfigTableDTO.getTableName());
        List<DynamicConfigFormDTO> dynamicConfigFormDTOList = dynamicConfigFormService.listForm(params);
        DynamicFormVO dynamicFormVO = getDynamicFormVO(dynamicConfigTableDTO.getTableName(), dynamicConfigFormDTOList);
        dynamicFormService.saveDynamicForm(dynamicFormVO);
        LOG.debug("更新状态");
        params.clear();
        params.put("id", id);
        params.put("isCreate", 1);
        setUpdateInfo(params);
        dynamicConfigTableDao.updateTable(params);
        return new SuccessResult();
    }

    @Override
    public SuccessResult removeTable(String ids) throws RemoveException {
        Map<String, Object> params = getHashMap(3);
        params.put("ids", Arrays.asList(ids.split("_")));
        setUpdateInfo(params);
        dynamicConfigTableDao.removeTable(params);
        return new SuccessResult();
    }

    @Override
    public SuccessResult updateTable(String id, DynamicConfigTableVO dynamicConfigTableVO) throws Exception {
        Map<String, Object> params = HashMapUtil.beanToMap(dynamicConfigTableVO);
        params.put("id", id);
        DynamicConfigTableDTO dynamicConfigTableDTO = dynamicConfigTableDao.getTableById(params);
        setUpdateInfo(params);
        dynamicConfigTableDao.updateTable(params);
        // 修改表单中的表名
        dynamicConfigFormService.updateFormTableName(dynamicConfigTableVO.getTableName(), dynamicConfigTableDTO.getTableName());
        return new SuccessResult();
    }

    @Override
    public SuccessResult updateDynamicTable(String id) throws Exception {
        Map<String, Object> params = getHashMap(1);
        params.put("id", id);
        LOG.debug("获取动态表信息");
        DynamicConfigTableDTO dynamicConfigTableDTO = dynamicConfigTableDao.getTableById(params);
        TableDTO tableDTO = dynamicTableService.getTableByTableName(dynamicConfigTableDTO.getTableName());
        if (tableDTO == null) {
            throw new UpdateException("表不存在，修改失败");
        }
        params.clear();
        params.put("tableName", dynamicConfigTableDTO.getTableName());
        List<DynamicConfigFormDTO> dynamicConfigFormDTOList = dynamicConfigFormService.listForm(params);
        DynamicFormVO dynamicFormVO = getDynamicFormVO(dynamicConfigTableDTO.getTableName(), dynamicConfigFormDTOList);
        dynamicFormService.updateDynamicForm(dynamicFormVO);
        return new SuccessResult();
    }

    @Override
    public DynamicConfigTableDTO getTableById(String id) throws SearchException {
        Map<String, Object> params = super.getHashMap(1);
        params.put("id", id);
        return dynamicConfigTableDao.getTableById(params);
    }

    @Override
    public List<DynamicConfigTableDTO> listTable(Map<String, Object> params) throws SearchException {
        return dynamicConfigTableDao.listTable(params);
    }

    @Override
    public SuccessResultList<List<DynamicConfigTableDTO>> listPageTable(ListPage page) throws SearchException {
        PageHelper.startPage(page.getPage(), page.getRows());
        List<DynamicConfigTableDTO> dynamicConfigTableDTOList = dynamicConfigTableDao.listTable(page.getParams());
        PageInfo<DynamicConfigTableDTO> pageInfo = new PageInfo<>(dynamicConfigTableDTOList);
        return new SuccessResultList<>(dynamicConfigTableDTOList, pageInfo.getPageNum(), pageInfo.getTotal());
    }

    @Override
    public void getStaticCode(String id, String basePackage, String context, HttpServletResponse response) throws Exception {
        Map<String, Object> params = getHashMap(1);
        params.put("id", id);
        // 1 获取动态表信息
        DynamicConfigTableDTO dynamicConfigTableDTO = dynamicConfigTableDao.getTableById(params);
        // 2 获取动态表字段
        params.clear();
        params.put("tableName", dynamicConfigTableDTO.getTableName());
        List<DynamicConfigFormDTO> dynamicConfigFormDTOList = dynamicConfigFormService.listForm(params);
        // 3 处理模板所需要的内容
        // 3.1 基础信息
        Map<String, Object> templateMap = getHashMap(16);
        templateMap.put("basePackage", basePackage);
        templateMap.put("context", context);
        templateMap.put("tablePrefix", "gen_");
        templateMap.put("tableName", dynamicConfigTableDTO.getTableName());
        templateMap.put("underLineTableName", WStringUtil.lowerUpper2UnderLine(dynamicConfigTableDTO.getTableName()));
        templateMap.put("lowerTableName", dynamicConfigTableDTO.getTableName().toLowerCase());
        templateMap.put("firstLowerTableName", WStringUtil.firstToLower(dynamicConfigTableDTO.getTableName()));
        templateMap.put("firstUpperTableName", WStringUtil.firstToUpper(dynamicConfigTableDTO.getTableName()));
        templateMap.put("tableExplain", dynamicConfigTableDTO.getTableExplain());
        templateMap.put("author", "WenG");
        templateMap.put("date", DateTime.now().toString("yyyy-MM-dd HH:mm"));
        templateMap.put("version", "1.0");
        // 3.2 字段信息
        List<Map<String, Object>> fieldList = new ArrayList<>(dynamicConfigFormDTOList.size());
        templateMap.put("fieldList", fieldList);
        // 联表索引
        int dictionaryIndex = 0;
        int joinTableIndex = 0;
        for (DynamicConfigFormDTO dynamicConfigFormDTO : dynamicConfigFormDTOList) {
            Map<String, Object> field = dynamicConfigFormDTOToMap(dynamicConfigFormDTO);
            if (StringUtils.equals(FieldTypeEnum.RADIO.getValue(), dynamicConfigFormDTO.getFieldType())
                    || StringUtils.equals(FieldTypeEnum.CHECKBOX.getValue(), dynamicConfigFormDTO.getFieldType())
                    || StringUtils.equals(FieldTypeEnum.SELECT.getValue(), dynamicConfigFormDTO.getFieldType())) {
                if (StringUtils.equals(FieldTypeEnum.CHECKBOX.getValue(), dynamicConfigFormDTO.getFieldType())) {
                    templateMap.put("isCheckboxExist", "exist");
                }
                field.put("dictionaryIndex", ++dictionaryIndex);
            } else if (StringUtils.equals(FieldTypeEnum.INNER_JOIN.getValue(), dynamicConfigFormDTO.getFieldType())
                    || StringUtils.equals(FieldTypeEnum.LEFT_JOIN.getValue(), dynamicConfigFormDTO.getFieldType())
                    || StringUtils.equals(FieldTypeEnum.RIGHT_JOIN.getValue(), dynamicConfigFormDTO.getFieldType())) {
                field.put("joinTable", dynamicConfigFormDTO.getJoinTable());
                field.put("firstUpperJoinTable", WStringUtil.firstToUpper(dynamicConfigFormDTO.getJoinTable()));
                field.put("lowerJoinTable", dynamicConfigFormDTO.getJoinTable().toLowerCase());
                field.put("underLineJoinTable", WStringUtil.lowerUpper2UnderLine(dynamicConfigFormDTO.getJoinTable()));
                field.put("joinTableField", dynamicConfigFormDTO.getJoinTableField());
                field.put("underLineJoinTableField", WStringUtil.lowerUpper2UnderLine(dynamicConfigFormDTO.getJoinTableField()));
                field.put("joinTableListShow", dynamicConfigFormDTO.getJoinTableListShow());
                field.put("joinTableFormShow", dynamicConfigFormDTO.getJoinTableFormShow());
                field.put("joinTableIndex", ++joinTableIndex);

                List<Map<String, Object>> listJoinTableField = new ArrayList<>();
                field.put("listJoinTableField", listJoinTableField);
                params.clear();
                params.put("tableName", dynamicConfigFormDTO.getJoinTable());
                params.put("fieldNameList", Arrays.asList(dynamicConfigFormDTO.getJoinTableListShow().split(",")));
                List<DynamicConfigFormDTO> joinDynamicConfigFormDTOList = dynamicConfigFormService.listForm(params);
                for (DynamicConfigFormDTO joinDynamicConfigFormDTO : joinDynamicConfigFormDTOList) {
                    Map<String, Object> joinTableFieldMap = dynamicConfigFormDTOToMap(joinDynamicConfigFormDTO);
                    listJoinTableField.add(joinTableFieldMap);
                }
            }
            fieldList.add(field);
        }
        String baseCodeFolder = String.format("%s/gencodes/%s/%s", fileProperties.getUploadPath(), dynamicConfigTableDTO.getTableName().toLowerCase(), String.valueOf(System.currentTimeMillis()));
        String templatePath = "codetemplate/default";

        try {
            generatorDefaultCode(templateMap, baseCodeFolder, templatePath);
            String zipCodeFile = baseCodeFolder + ".zip";
            ZipUtil.zip(baseCodeFolder, zipCodeFile);
            RequestUtil.downLoad(response, zipCodeFile);
        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
            throw new SearchException("生成代码失败");
        }
    }

    @Override
    public void getEmptyProject(EmptyProjectVO emptyProjectVO, HttpServletResponse response) throws Exception {
        Map<String, Object> params = HashMapUtil.beanToMap(emptyProjectVO);
        params.put("lowerSystemName", emptyProjectVO.getSystemName().toLowerCase());
        params.put("firstUpperSystemName", WStringUtil.firstToUpper(emptyProjectVO.getSystemName()));
        params.put("gmtCreate", DateUtil.getDay());

        String baseCodeFolder = String.format("%s/emptyproject/%s/system-%s", fileProperties.getUploadPath(), String.valueOf(System.currentTimeMillis()), params.get("lowerSystemName").toString());
        String templatePath = String.format("codetemplate/base");

        try {
            dynamicEmptyProject(params, baseCodeFolder, templatePath, response);

            String zipCodeFile = baseCodeFolder + ".zip";
            ZipUtil.zip(baseCodeFolder, zipCodeFile);
            RequestUtil.downLoad(response, zipCodeFile);
        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
            throw new SearchException("生成代码失败");
        }
    }

    @Override
    public void getAssetsZip(HttpServletResponse response) {
        response.setCharacterEncoding(ISystemConstant.CHARSET_UTF8);
        response.setHeader("Content-Disposition", "attachment;filename=assets.zip");
        response.setContentType("application/octet-stream");
        ClassPathResource classPathResource = new ClassPathResource("assets.zip");
        InputStream inputStream = null;
        try {
            inputStream = classPathResource.getInputStream();
            IOUtils.copy(inputStream, response.getOutputStream());
            response.flushBuffer();
        } catch (IOException e) {
            LOG.error(e.getMessage(), e);
        } finally {
            IOUtils.closeQuietly(inputStream);
        }
    }

    /**
     * 生成空项目
     *
     * @param params
     * @param response
     */
    private void dynamicEmptyProject(Map<String, Object> params, String baseCodeFolder, String templatePath, HttpServletResponse response) throws IOException {
        freeMarkerConfigurer.getConfiguration().setClassForTemplateLoading(DynamicConfigTableServiceImpl.class, "/templates");
        LOG.debug("生成pom.xml");
        generatorEmptyProjectPomXML(params, baseCodeFolder, templatePath);
        LOG.debug("生成banner.txt");
        generatorEmptyProjectBannerTxt(params, baseCodeFolder, templatePath);
        LOG.debug("生成application.yml");
        generatorEmptyProjectApplicationYml(params, baseCodeFolder, templatePath);
        LOG.debug("生成Application.java");
        generatorEmptyProjectApplicationJava(params, baseCodeFolder, templatePath);
        LOG.debug("生成AuthClientSecurityConfig.java");
        generatorEmptyProjectAuthClientSecurityConfigJava(params, baseCodeFolder, templatePath);
        LOG.debug("生成index.html");
        generatorEmptyProjectIndexHtml(params, baseCodeFolder, templatePath);
        LOG.debug("生成index.html");
        generatorEmptyProjectDefaultHtml(params, baseCodeFolder, templatePath);
        LOG.debug("生成403.html");
        generatorEmptyProject403Html(params, baseCodeFolder, templatePath);
        LOG.debug("生成404.html");
        generatorEmptyProject404Html(params, baseCodeFolder, templatePath);
        LOG.debug("生成500.html");
        generatorEmptyProject500Html(params, baseCodeFolder, templatePath);
        LOG.debug("生成mybatis-config.xml");
        generatorEmptyProjectMybatisConfigXml(params, baseCodeFolder, templatePath);
    }

    /**
     * 生成空项目pom.xml
     *
     * @param params
     * @param baseCodeFolder
     * @param templatePath
     * @throws IOException
     */
    private void generatorEmptyProjectPomXML(Map<String, Object> params, String baseCodeFolder, String templatePath) throws IOException {
        String codePath = baseCodeFolder;
        FolderUtil.createFolder(codePath);
        Template template = freeMarkerConfigurer.getConfiguration().getTemplate(String.format("%s/pom.ftl", templatePath));
        Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(String.format("%s/pom.xml", codePath)), ISystemConstant.CHARSET_UTF8));
        generatorCode(params, writer, template);
    }

    /**
     * 生成空项目banner.txt
     *
     * @param params
     * @param baseCodeFolder
     * @param templatePath
     * @throws IOException
     */
    private void generatorEmptyProjectBannerTxt(Map<String, Object> params, String baseCodeFolder, String templatePath) throws IOException {
        String codePath = String.format("%s/src/main/resources", baseCodeFolder);
        FolderUtil.createFolder(codePath);
        Template template = freeMarkerConfigurer.getConfiguration().getTemplate(String.format("%s/banner.ftl", templatePath));
        Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(String.format("%s/banner.txt", codePath)), ISystemConstant.CHARSET_UTF8));
        generatorCode(params, writer, template);
    }

    /**
     * 生成空项目application.yml
     *
     * @param params
     * @param baseCodeFolder
     * @param templatePath
     * @throws IOException
     */
    private void generatorEmptyProjectApplicationYml(Map<String, Object> params, String baseCodeFolder, String templatePath) throws IOException {
        String codePath = String.format("%s/src/main/resources", baseCodeFolder);
        FolderUtil.createFolder(codePath);
        Template template = freeMarkerConfigurer.getConfiguration().getTemplate(String.format("%s/application.ftl", templatePath));
        Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(String.format("%s/application.yml", codePath)), ISystemConstant.CHARSET_UTF8));
        generatorCode(params, writer, template);
    }

    /**
     * 生成空项目Application.java
     *
     * @param params
     * @param baseCodeFolder
     * @param templatePath
     * @throws IOException
     */
    private void generatorEmptyProjectApplicationJava(Map<String, Object> params, String baseCodeFolder, String templatePath) throws IOException {
        String codePath = String.format("%s/src/main/java/com/cm/%s", baseCodeFolder, params.get("lowerSystemName").toString());
        FolderUtil.createFolder(codePath);
        Template template = freeMarkerConfigurer.getConfiguration().getTemplate(String.format("%s/src/Application.ftl", templatePath));
        Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(String.format("%s/%sApplication.java", codePath, params.get("firstUpperSystemName").toString())), ISystemConstant.CHARSET_UTF8));
        generatorCode(params, writer, template);
    }

    /**
     * 生成空项目AuthClientSecurityConfig.java
     *
     * @param params
     * @param baseCodeFolder
     * @param templatePath
     * @throws IOException
     */
    private void generatorEmptyProjectAuthClientSecurityConfigJava(Map<String, Object> params, String baseCodeFolder, String templatePath) throws IOException {
        String codePath = String.format("%s/src/main/java/com/cm/%s/config", baseCodeFolder, params.get("lowerSystemName").toString());
        FolderUtil.createFolder(codePath);
        Template template = freeMarkerConfigurer.getConfiguration().getTemplate(String.format("%s/src/AuthClientSecurityConfig.ftl", templatePath));
        Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(String.format("%s/AuthClientSecurityConfig.java", codePath)), ISystemConstant.CHARSET_UTF8));
        generatorCode(params, writer, template);
    }

    /**
     * 生成空项目index.html
     *
     * @param params
     * @param baseCodeFolder
     * @param templatePath
     * @throws IOException
     */
    private void generatorEmptyProjectIndexHtml(Map<String, Object> params, String baseCodeFolder, String templatePath) throws IOException {
        String codePath = String.format("%s/src/main/resources/templates", baseCodeFolder);
        FolderUtil.createFolder(codePath);
        Template template = freeMarkerConfigurer.getConfiguration().getTemplate(String.format("%s/route/index.ftl", templatePath));
        Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(String.format("%s/index.html", codePath)), ISystemConstant.CHARSET_UTF8));
        generatorCode(params, writer, template);
    }

    /**
     * 生成空项目default.html
     *
     * @param params
     * @param baseCodeFolder
     * @param templatePath
     * @throws IOException
     */
    private void generatorEmptyProjectDefaultHtml(Map<String, Object> params, String baseCodeFolder, String templatePath) throws IOException {
        String codePath = String.format("%s/src/main/resources/static", baseCodeFolder);
        FolderUtil.createFolder(codePath);
        Template template = freeMarkerConfigurer.getConfiguration().getTemplate(String.format("%s/route/default.ftl", templatePath));
        Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(String.format("%s/default.html", codePath)), ISystemConstant.CHARSET_UTF8));
        generatorCode(params, writer, template);
    }

    /**
     * 生成空项目403.html
     *
     * @param params
     * @param baseCodeFolder
     * @param templatePath
     * @throws IOException
     */
    private void generatorEmptyProject403Html(Map<String, Object> params, String baseCodeFolder, String templatePath) throws IOException {
        String codePath = String.format("%s/src/main/resources/static/error", baseCodeFolder);
        FolderUtil.createFolder(codePath);
        Template template = freeMarkerConfigurer.getConfiguration().getTemplate(String.format("%s/error/403.ftl", templatePath));
        Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(String.format("%s/403.html", codePath)), ISystemConstant.CHARSET_UTF8));
        generatorCode(params, writer, template);
    }

    /**
     * 生成空项目404.html
     *
     * @param params
     * @param baseCodeFolder
     * @param templatePath
     * @throws IOException
     */
    private void generatorEmptyProject404Html(Map<String, Object> params, String baseCodeFolder, String templatePath) throws IOException {
        String codePath = String.format("%s/src/main/resources/static/error", baseCodeFolder);
        FolderUtil.createFolder(codePath);
        Template template = freeMarkerConfigurer.getConfiguration().getTemplate(String.format("%s/error/404.ftl", templatePath));
        Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(String.format("%s/404.html", codePath)), ISystemConstant.CHARSET_UTF8));
        generatorCode(params, writer, template);
    }

    /**
     * 生成空项目500.html
     *
     * @param params
     * @param baseCodeFolder
     * @param templatePath
     * @throws IOException
     */
    private void generatorEmptyProject500Html(Map<String, Object> params, String baseCodeFolder, String templatePath) throws IOException {
        String codePath = String.format("%s/src/main/resources/static/error", baseCodeFolder);
        FolderUtil.createFolder(codePath);
        Template template = freeMarkerConfigurer.getConfiguration().getTemplate(String.format("%s/error/500.ftl", templatePath));
        Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(String.format("%s/500.html", codePath)), ISystemConstant.CHARSET_UTF8));
        generatorCode(params, writer, template);
    }

    /**
     * 生成空项目mybatis-config.xml
     *
     * @param params
     * @param baseCodeFolder
     * @param templatePath
     * @throws IOException
     */
    private void generatorEmptyProjectMybatisConfigXml(Map<String, Object> params, String baseCodeFolder, String templatePath) throws IOException {
        String codePath = String.format("%s/src/main/resources/mybatis", baseCodeFolder);
        FolderUtil.createFolder(codePath);
        Template template = freeMarkerConfigurer.getConfiguration().getTemplate(String.format("%s/mapper/mybatis-config.ftl", templatePath));
        Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(String.format("%s/mybatis-config.xml", codePath)), ISystemConstant.CHARSET_UTF8));
        generatorCode(params, writer, template);
    }

    /**
     * 动态表单转hashMap
     *
     * @param dynamicConfigFormDTO
     * @return
     */
    private Map<String, Object> dynamicConfigFormDTOToMap(DynamicConfigFormDTO dynamicConfigFormDTO) throws Exception {
        Map<String, Object> field = HashMapUtil.beanToMap(dynamicConfigFormDTO);
        field.put("fieldWidth", dynamicConfigFormDTO.getListShowWidth());
        field.put("underLineFieldName", WStringUtil.lowerUpper2UnderLine(dynamicConfigFormDTO.getFieldName()));
        field.put("firstLowerFieldName", WStringUtil.firstToLower(dynamicConfigFormDTO.getFieldName()));
        field.put("firstUpperFieldName", WStringUtil.firstToUpper(dynamicConfigFormDTO.getFieldName()));
        return field;
    }

    /**
     * 生成默认代码
     *
     * @param params
     * @param baseCodeFolder
     * @param templatePath
     * @throws IOException
     */
    private void generatorDefaultCode(Map<String, Object> params, String baseCodeFolder, String templatePath) throws IOException {
        // 设置资源
        freeMarkerConfigurer.getConfiguration().setClassForTemplateLoading(DynamicConfigTableServiceImpl.class, "/templates");
        LOG.debug("生成ApiController");
        generatorApiController(params, baseCodeFolder, templatePath);
        LOG.debug("生成AppController");
        generatorAppController(params, baseCodeFolder, templatePath);
        LOG.debug("生成ResourceController");
        generatorResourceController(params, baseCodeFolder, templatePath);
        LOG.debug("生成service");
        generatorService(params, baseCodeFolder, templatePath);
        LOG.debug("生成serviceImpl");
        generatorServiceImpl(params, baseCodeFolder, templatePath);
        LOG.debug("生成dao");
        generatorDao(params, baseCodeFolder, templatePath);
        LOG.debug("生成mapper");
        generatorMapper(params, baseCodeFolder, templatePath);
        LOG.debug("生成SQL");
        generatorSQL(params, baseCodeFolder, templatePath);
        LOG.debug("生成dto");
        generatorDto(params, baseCodeFolder, templatePath);
        LOG.debug("生成vo");
        generatorVo(params, baseCodeFolder, templatePath);
        LOG.debug("生成list.html");
        generatorList(params, baseCodeFolder, templatePath);
        LOG.debug("生成save.html");
        generatorSave(params, baseCodeFolder, templatePath);
        LOG.debug("生成update.html");
        generatorUpdate(params, baseCodeFolder, templatePath);
    }

    /**
     * 生成 APIController.java
     *
     * @param params
     * @param baseCodeFolder
     * @param templatePath
     * @throws SearchException
     * @throws IOException
     */
    private void generatorApiController(Map<String, Object> params, String baseCodeFolder, String templatePath) throws SearchException, IOException {
        String codePath = String.format("%s/controller/apis/%s", baseCodeFolder, params.get("lowerTableName").toString());
        FolderUtil.createFolder(codePath);
        Template template = freeMarkerConfigurer.getConfiguration().getTemplate(String.format("%s/controller/apis/ApiController.ftl", templatePath));
        Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(String.format("%s/%sController.java", codePath, params.get("firstUpperTableName").toString())), ISystemConstant.CHARSET_UTF8));
        generatorCode(params, writer, template);
    }

    /**
     * 生成 AppController.java
     *
     * @param params
     * @param baseCodeFolder
     * @param templatePath
     * @throws SearchException
     * @throws IOException
     */
    private void generatorAppController(Map<String, Object> params, String baseCodeFolder, String templatePath) throws SearchException, IOException {
        String codePath = String.format("%s/controller/app/apis/%s", baseCodeFolder, params.get("lowerTableName").toString());
        FolderUtil.createFolder(codePath);
        Template template = freeMarkerConfigurer.getConfiguration().getTemplate(String.format("%s/controller/app/apis/AppController.ftl", templatePath));
        Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(String.format("%s/%sAppController.java", codePath, params.get("firstUpperTableName").toString())), ISystemConstant.CHARSET_UTF8));
        generatorCode(params, writer, template);
    }

    /**
     * 生成 ResourceController.java
     *
     * @param params
     * @param baseCodeFolder
     * @param templatePath
     * @throws SearchException
     * @throws IOException
     */
    private void generatorResourceController(Map<String, Object> params, String baseCodeFolder, String templatePath) throws SearchException, IOException {
        String codePath = String.format("%s/controller/resources/%s", baseCodeFolder, params.get("lowerTableName").toString());
        FolderUtil.createFolder(codePath);
        Template template = freeMarkerConfigurer.getConfiguration().getTemplate(String.format("%s/controller/resources/ResourceController.ftl", templatePath));
        Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(String.format("%s/%sResourceController.java", codePath, params.get("firstUpperTableName").toString())), ISystemConstant.CHARSET_UTF8));
        generatorCode(params, writer, template);
    }

    /**
     * 生成 Service.java
     *
     * @param params
     * @param baseCodeFolder
     * @param templatePath
     * @throws SearchException
     * @throws IOException
     */
    private void generatorService(Map<String, Object> params, String baseCodeFolder, String templatePath) throws SearchException, IOException {
        String codePath = String.format("%s/service/%s", baseCodeFolder, params.get("lowerTableName").toString());
        FolderUtil.createFolder(codePath);
        Template template = freeMarkerConfigurer.getConfiguration().getTemplate(String.format("%s/service/IService.ftl", templatePath));
        Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(String.format("%s/I%sService.java", codePath, params.get("firstUpperTableName").toString())), ISystemConstant.CHARSET_UTF8));
        generatorCode(params, writer, template);
    }

    /**
     * 生成 ServiceImpl.java
     *
     * @param params
     * @param baseCodeFolder
     * @param templatePath
     * @throws SearchException
     * @throws IOException
     */
    private void generatorServiceImpl(Map<String, Object> params, String baseCodeFolder, String templatePath) throws SearchException, IOException {
        String codePath = String.format("%s/service/%s/impl", baseCodeFolder, params.get("lowerTableName").toString());
        FolderUtil.createFolder(codePath);
        Template template = freeMarkerConfigurer.getConfiguration().getTemplate(String.format("%s/service/ServiceImpl.ftl", templatePath));
        Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(String.format("%s/%sServiceImpl.java", codePath, params.get("firstUpperTableName").toString())), ISystemConstant.CHARSET_UTF8));
        generatorCode(params, writer, template);
    }

    /**
     * 生成 Dao.java
     *
     * @param params
     * @param baseCodeFolder
     * @param templatePath
     * @throws SearchException
     * @throws IOException
     */
    private void generatorDao(Map<String, Object> params, String baseCodeFolder, String templatePath) throws SearchException, IOException {
        String codePath = String.format("%s/dao/%s", baseCodeFolder, params.get("lowerTableName").toString());
        FolderUtil.createFolder(codePath);
        Template template = freeMarkerConfigurer.getConfiguration().getTemplate(String.format("%s/dao/IDao.ftl", templatePath));
        Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(String.format("%s/I%sDao.java", codePath, params.get("firstUpperTableName").toString())), ISystemConstant.CHARSET_UTF8));
        generatorCode(params, writer, template);
    }

    /**
     * 生成 mapper.xml
     *
     * @param params
     * @param baseCodeFolder
     * @param templatePath
     * @throws SearchException
     * @throws IOException
     */
    private void generatorMapper(Map<String, Object> params, String baseCodeFolder, String templatePath) throws SearchException, IOException {
        String codePath = String.format("%s/mapper/%s", baseCodeFolder, params.get("lowerTableName").toString());
        FolderUtil.createFolder(codePath);
        Template template = freeMarkerConfigurer.getConfiguration().getTemplate(String.format("%s/mapper/mapper.ftl", templatePath));
        Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(String.format("%s/%s-mapper.xml", codePath, params.get("lowerTableName").toString())), ISystemConstant.CHARSET_UTF8));
        generatorCode(params, writer, template);
    }

    /**
     * 生成 sql
     *
     * @param params
     * @param baseCodeFolder
     * @param templatePath
     * @throws SearchException
     * @throws IOException
     */
    private void generatorSQL(Map<String, Object> params, String baseCodeFolder, String templatePath) throws SearchException, IOException {
        String codePath = String.format("%s/sql", baseCodeFolder);
        FolderUtil.createFolder(codePath);
        Template template = freeMarkerConfigurer.getConfiguration().getTemplate(String.format("%s/sql/sql.ftl", templatePath));
        Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(String.format("%s/%s.sql", codePath, params.get("lowerTableName").toString())), ISystemConstant.CHARSET_UTF8));
        generatorCode(params, writer, template);
    }

    /**
     * 生成 DTO.java
     *
     * @param params
     * @param baseCodeFolder
     * @param templatePath
     * @throws SearchException
     * @throws IOException
     */
    private void generatorDto(Map<String, Object> params, String baseCodeFolder, String templatePath) throws SearchException, IOException {
        String codePath = String.format("%s/pojo/dtos/%s", baseCodeFolder, params.get("lowerTableName").toString());
        FolderUtil.createFolder(codePath);
        Template template = freeMarkerConfigurer.getConfiguration().getTemplate(String.format("%s/pojo/dto.ftl", templatePath));
        Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(String.format("%s/%sDTO.java", codePath, params.get("firstUpperTableName").toString())), ISystemConstant.CHARSET_UTF8));
        generatorCode(params, writer, template);
    }

    /**
     * 生成 VO.java
     *
     * @param params
     * @param baseCodeFolder
     * @param templatePath
     * @throws SearchException
     * @throws IOException
     */
    private void generatorVo(Map<String, Object> params, String baseCodeFolder, String templatePath) throws SearchException, IOException {
        String codePath = String.format("%s/pojo/vos/%s", baseCodeFolder, params.get("lowerTableName").toString());
        FolderUtil.createFolder(codePath);
        Template template = freeMarkerConfigurer.getConfiguration().getTemplate(String.format("%s/pojo/vo.ftl", templatePath));
        Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(String.format("%s/%sVO.java", codePath, params.get("firstUpperTableName").toString())), ISystemConstant.CHARSET_UTF8));
        generatorCode(params, writer, template);
    }

    /**
     * 生成 list.html
     *
     * @param params
     * @param baseCodeFolder
     * @param templatePath
     * @throws SearchException
     * @throws IOException
     */
    private void generatorList(Map<String, Object> params, String baseCodeFolder, String templatePath) throws SearchException, IOException {
        String codePath = String.format("%s/route/%s", baseCodeFolder, params.get("lowerTableName").toString());
        FolderUtil.createFolder(codePath);
        Template template = freeMarkerConfigurer.getConfiguration().getTemplate(String.format("%s/route/list.ftl", templatePath));
        Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(String.format("%s/list-%s.html", codePath, params.get("lowerTableName").toString())), ISystemConstant.CHARSET_UTF8));
        generatorCode(params, writer, template);
    }

    /**
     * 生成 save.html
     *
     * @param params
     * @param baseCodeFolder
     * @param templatePath
     * @throws SearchException
     * @throws IOException
     */
    private void generatorSave(Map<String, Object> params, String baseCodeFolder, String templatePath) throws SearchException, IOException {
        String codePath = String.format("%s/route/%s", baseCodeFolder, params.get("lowerTableName").toString());
        FolderUtil.createFolder(codePath);
        Template template = freeMarkerConfigurer.getConfiguration().getTemplate(String.format("%s/route/save.ftl", templatePath));
        Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(String.format("%s/save-%s.html", codePath, params.get("lowerTableName").toString())), ISystemConstant.CHARSET_UTF8));
        generatorCode(params, writer, template);
    }

    /**
     * 生成 update.html
     *
     * @param params
     * @param baseCodeFolder
     * @param templatePath
     * @throws SearchException
     * @throws IOException
     */
    private void generatorUpdate(Map<String, Object> params, String baseCodeFolder, String templatePath) throws SearchException, IOException {
        String codePath = String.format("%s/route/%s", baseCodeFolder, params.get("lowerTableName").toString());
        FolderUtil.createFolder(codePath);
        Template template = freeMarkerConfigurer.getConfiguration().getTemplate(String.format("%s/route/update.ftl", templatePath));
        Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(String.format("%s/update-%s.html", codePath, params.get("lowerTableName").toString())), ISystemConstant.CHARSET_UTF8));
        generatorCode(params, writer, template);
    }

    /**
     * 生成代码
     *
     * @param params
     * @param writer
     * @param template
     */
    private void generatorCode(Map<String, Object> params, Writer writer, Template template) {
        try {
            template.process(params, writer);
        } catch (IOException | TemplateException e) {
            LOG.error(e.getMessage(), e);
            throw new SearchException("生成代码失败");
        } finally {
            if (writer != null) {
                try {
                    writer.close();
                } catch (IOException e1) {
                    LOG.error(e1.getMessage(), e1);
                }
            }
        }
    }

    /**
     * 获取建表对象
     *
     * @param tableName
     * @param dynamicConfigFormDTOList
     * @return
     */
    private DynamicFormVO getDynamicFormVO(String tableName, List<DynamicConfigFormDTO> dynamicConfigFormDTOList) {
        List<DynamicFormFieldVO> dynamicFormFieldVOList = new ArrayList<>(0);
        DynamicFormVO dynamicFormVO = new DynamicFormVO();
        dynamicFormVO.setTableName(tableName);
        dynamicFormVO.setDynamicFormFields(dynamicFormFieldVOList);
        for (DynamicConfigFormDTO dynamicConfigFormDTO : dynamicConfigFormDTOList) {
            DynamicFormFieldVO dynamicFormFieldVO = new DynamicFormFieldVO();
            dynamicFormFieldVO.setFieldName(dynamicConfigFormDTO.getFieldName());
            dynamicFormFieldVO.setFieldDefault(dynamicConfigFormDTO.getFieldDefault());
            dynamicFormFieldVO.setFieldExplain(dynamicConfigFormDTO.getFieldExplain());
            dynamicFormFieldVO.setFieldType(dynamicConfigFormDTO.getFieldType());
            dynamicFormFieldVOList.add(dynamicFormFieldVO);
        }
        return dynamicFormVO;
    }
}
