package cc.smtweb.system.bpm.util;

import cc.smtweb.framework.core.common.SwConsts;
import cc.smtweb.framework.core.common.SwMap;
import cc.smtweb.framework.core.db.DbEngine;
import cc.smtweb.framework.core.exception.SwException;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateMethodModelEx;
import freemarker.template.TemplateModelException;
import org.apache.commons.io.IOUtils;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;

/**
 * Created by Akmm at 2022/6/8 15:36
 * 模板生成代码
 */
public class CodeGenerator {
    private final static String KEY_MODEL = "model";
    private final static String TEMPLATE_JAVA_BEAN = "java_bean";
    private final static String TEMPLATE_JAVA_CACHE = "java_cache";
    private final static String TEMPLATE_JAVA_SERVICE = "java_service";
    private final static String TEMPLATE_JS_EVENT = "js_event";
    private static CodeGenerator instance = null;

    private Configuration modelConfiguration = null;
    private Configuration codeConfiguration = null;

    private final String encode = org.apache.commons.codec.CharEncoding.UTF_8;
    //模板文件所在目录
//    private String templatesDir;

    //模板信息
    private SwMap mapTemplate;

    protected CodeGenerator() {
//        templatesDir = this.getClass().getResource("/static/template").getPath();
        mapTemplate = YamlUtil.readValue(this.getClass().getResourceAsStream("/static/template/" + SwConsts.modelPath + "/index.yaml"), SwMap.class);
        modelConfiguration = buildConfig("/static/template/" + SwConsts.modelPath);
        codeConfiguration = buildConfig("/static/template/");
    }

    private Configuration buildConfig(String path) {
        Configuration config = new Configuration(Configuration.VERSION_2_3_31);
        config.setClassForTemplateLoading(this.getClass(), path);
//            configuration.setDirectoryForTemplateLoading(new File(templatesDir));
        config.setClassicCompatible(true);
        config.setDefaultEncoding(encode);
        config.setOutputEncoding(encode);
        return config;
    }

    //页面设计的模板信息
    public List<Map<String, Object>> getModelTemplates() {
        return (List<Map<String, Object>>) mapTemplate.get(KEY_MODEL);
    }

    private void initModel(Map<String, Object> model) {
        model.put("newId", new PKGenerator());
    }

    public void generate(Configuration config, Map<String, Object> model, String templateName, Writer writer) {
        try {
            initModel(model);
            Template template = config.getTemplate(templateName, encode);
            template.setOutputEncoding(encode);
            template.process(model, writer);
            writer.close();
        } catch (Exception e) {
            e.printStackTrace();
            throw new SwException(e);
        }
    }


    public void generate(Configuration config, Map<String, Object> model, String templateName, String fileName) {
        File file = new File(fileName);
        if (file.exists()) file.delete();
        FileOutputStream out = null;
        try {
            file.createNewFile();
            out = new FileOutputStream(fileName);

            initModel(model);
            Template template = config.getTemplate(templateName + ".ftl", StandardCharsets.UTF_8.toString());
            template.setOutputEncoding(encode);
            template.process(model, new OutputStreamWriter(out, encode));
            out.flush();
        } catch (Exception e) {
            throw new SwException("生成代码失败！", e);
        } finally {
            IOUtils.closeQuietly(out);
        }
    }

    public String generatePage(Map<String, Object> model, String templateName) {
        StringWriter out = new StringWriter();
        generate(modelConfiguration, model, templateName + ".ftl", out);
        return out.getBuffer().toString();
    }

    public void generateBean(Map<String, Object> model, String fileName) {
        generate(codeConfiguration, model, TEMPLATE_JAVA_BEAN, fileName);
    }

    public void generateCache(Map<String, Object> model, String fileName) {
        generate(codeConfiguration, model, TEMPLATE_JAVA_CACHE, fileName);
    }

    public void generateService(Map<String, Object> model, String fileName) {
        generate(codeConfiguration, model, TEMPLATE_JAVA_SERVICE, fileName);
    }

    public void generateJsEvent(Map<String, Object> model, String fileName) {
        generate(codeConfiguration, model, TEMPLATE_JS_EVENT, fileName);
    }


    /**
     * 获取单实例
     *
     * @return
     */
    public static CodeGenerator getInstance() {
        if (instance == null) {
            synchronized (CodeGenerator.class) {
                instance = new CodeGenerator();
            }
        }
        return instance;
    }

    static class PKGenerator implements TemplateMethodModelEx {
        @Override
        public Object exec(List list) throws TemplateModelException {
            return String.valueOf(DbEngine.getInstance().nextId());
//            return DbEngine.getInstance().nextId();
        }
    }
}
