package com.jzdsh.auto.app;

import com.alibaba.druid.filter.stat.StatFilter;
import com.alibaba.druid.wall.WallFilter;
import com.jfinal.config.*;
import com.jfinal.json.MixedJsonFactory;
import com.jfinal.kit.Prop;
import com.jfinal.kit.PropKit;
import com.jfinal.plugin.activerecord.ActiveRecordPlugin;
import com.jfinal.plugin.druid.DruidPlugin;
import com.jfinal.plugin.ehcache.EhCachePlugin;
import com.jfinal.render.Render;
import com.jfinal.render.ViewType;
import com.jfinal.server.undertow.UndertowServer;
import com.jfinal.template.Engine;
import com.jzdsh.auto.app.common.DruidKit;
import com.jzdsh.auto.app.handler.UrlSeoHandler;
import com.jzdsh.auto.app.interceptor.LoginSessionInterceptor;
import com.jzdsh.auto.model._MappingKit;
import lombok.extern.log4j.Log4j2;

import java.sql.Connection;

@Log4j2
public class JFConfig extends JFinalConfig{
    /**
     * 使用 jfinal-undertow 时此处仅保留声明，不能有加载代码
     */
    private static Prop p;

    /**
     * 启动入口，运行此 main 方法可以启动项目，此 main 方法
     * 可以放置在任意的 Class 类定义中，不一定要放于此
     */
    public static void main(String[] args) {
        UndertowServer.start(JFConfig.class);
    }

    /**
     * PropKit.useFirstFound(...) 使用参数中从左到右最先被找到的配置文件
     * 从左到右依次去找配置，找到则立即加载并立即返回，后续配置将被忽略
     */
    static void loadConfig() {
        if (p == null) {
            p = PropKit.useFirstFound("config.txt", "config-dev.txt");
        }
    }

    @Override
    public void configConstant(Constants me) {
        loadConfig();

        me.setDevMode(p.getBoolean("devMode", false));
        me.setJsonFactory(MixedJsonFactory.me());

        // 支持 Controller、Interceptor、Validator 之中使用 @Inject 注入业务层，并且自动实现 AOP
        me.setInjectDependency(true);

        // 是否对超类中的属性进行注入
        me.setInjectSuperClass(true);
    }

    /**
     * 路由拆分到 FrontRoutes 与 AdminRoutes 之中配置的好处：
     * 1：可分别配置不同的 baseViewPath 与 Interceptor
     * 2：避免多人协同开发时，频繁修改此文件带来的版本冲突
     * 3：避免本文件中内容过多，拆分后可读性增强
     * 4：便于分模块管理路由
     */
    @Override
    public void configRoute(Routes me) {
        me.add(new FrontRoutes());
        me.add(new AdminRoutes());
    }

    /**
     * 配置模板引擎，通常情况只需配置共享的模板函数
     */
    @Override
    public void configEngine(Engine me) {
        me.setDevMode(p.getBoolean("engineDevMode", false));

        // 配置用于主菜单的 URL，导航到 https://jfinal.com
        //me.addSharedObject("SSL", p.get("SSL"));

        me.addSharedFunction("/_view/_admin/common/__admin_layout.html");
        me.addSharedFunction("/_view/_admin/common/_admin_paginate.html");
        me.addSharedFunction("/_view/_admin/common/_menu.html");
    }

    /**
     * 抽取成独立的方法，便于 _Generator 中重用该方法，减少代码冗余
     */
    public static DruidPlugin getDruidPlugin() {
        loadConfig();
        return new DruidPlugin(p.get("db.url"), p.get("db.username").trim(), p.get("db.password").trim());
    }
    WallFilter wallFilter;

    @Override
    public void configPlugin(Plugins me) {
        DruidPlugin druidPlugin = getDruidPlugin();
        // 加强数据库安全
        wallFilter = new WallFilter();
        wallFilter.setDbType("mysql");
        druidPlugin.addFilter(wallFilter);
        // 添加 StatFilter 才会有统计数据
        druidPlugin.addFilter(new StatFilter());
        me.add(druidPlugin);

        ActiveRecordPlugin arp = new ActiveRecordPlugin(druidPlugin);
        arp.setTransactionLevel(Connection.TRANSACTION_READ_COMMITTED);
        _MappingKit.mapping(arp);
        // 强制指定复合主键的次序，避免不同的开发环境生成在 _MappingKit 中的复合主键次序不相同
        arp.setPrimaryKey("document", "mainMenu,subMenu");
        me.add(arp);
        arp.setShowSql(p.getBoolean("devMode", false));



        arp.getEngine().setToClassPathSourceFactory();
        arp.addSqlTemplate("/sql/_all_sqls.sql");

        me.add(new EhCachePlugin());
        //me.add(new Cron4jPlugin(p));
    }

    @Override
    public void configInterceptor(Interceptors me) {

        //me.add(new LoginSessionInterceptor());
    }

    @Override
    public void configHandler(Handlers me) {
        // druid 统计页面功能
        me.add(DruidKit.getDruidStatViewHandler());
        // index、detail 两类 action 的 url seo
        me.add(new UrlSeoHandler());
    }

    /**
     * 本方法会在 jfinal 启动过程完成之后被回调，详见 jfinal 手册
     */
    @Override
    public void onStart() {
        // 调用不带参的 renderJson() 时，排除对 loginAccount、remind 的 json 转换
/*        JsonRender.addExcludedAttrs(
                LoginService.loginAccountCacheName,
                LoginSessionInterceptor.remindKey,
                FriendInterceptor.followNum, FriendInterceptor.fansNum, FriendInterceptor.friendRelation
        );*/

        // 让 druid 允许在 sql 中使用 union
        // https://github.com/alibaba/druid/wiki/%E9%85%8D%E7%BD%AE-wallfilter
        wallFilter.getConfig().setSelectUnionCheck(false);
    }
}
