package com.yihu.hos.services;

import com.yihu.hos.common.classLoader.DynamicClassLoader;
import com.yihu.hos.common.constants.BrokerConstant;
import com.yihu.hos.core.constants.CoreConstant;
import com.yihu.hos.core.datatype.ClassFileUtil;
import com.yihu.hos.core.datatype.StringUtil;
import com.yihu.hos.models.SystemCamelContext;
import com.yihu.hos.models.SystemClassMapping;
import com.yihu.hos.web.framework.model.Result;
import org.apache.camel.builder.RouteBuilder;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Service;

import java.io.File;
import java.net.MalformedURLException;
import java.util.Map;

/**
 * Created by lingfeng on 2016/8/4.
 */
@Service("ESBCamelService")
public class ESBCamelService {
    public static final String BEAN_ID = "ESBCamelService";
    private static Logger logger = LogManager.getLogger(ESBCamelService.class);
    /**
     * 当外界组件通知一个新的processor处理器被定义时，该事件被触发。
     * @param serviceFlow 本次processor处理器变化，所涉及的业务系统唯一标识。
     * @param packageName processor处理器定义涉及的class包名
     * @param className processor处理器定义涉及的class类名
     * @param path processor处理器定义涉及的class对应路径
     */
    public Result onProcessorAdded(String serviceFlow, String packageName, String className, String path) {
        try {
            if(StringUtil.isEmpty(serviceFlow) || StringUtil.isEmpty(packageName)
                    || StringUtil.isEmpty(className) || StringUtil.isEmpty(path)) {
                logger.error("必要的入参数据不正确，请检查！");
                return Result.error("必要的入参数据不正确，请检查！");
            }
            this.createClassfile(serviceFlow, packageName, className, path, BrokerConstant.PROCESSOR);
            return Result.success("新增处理器成功！");
        } catch (Exception e) {
            logger.error(e);
            return Result.error("新增处理器失败！");
        }
    }

    /**
     * 当外界组件通知一个已有的processor处理器data部分发生变化时，该事件被触发。
     */
    public Result onProcessorDataChanged(String serviceFlow , String packageName , String className , String path) {
        try {
            if(StringUtil.isEmpty(serviceFlow) || StringUtil.isEmpty(packageName)
                    || StringUtil.isEmpty(className) || StringUtil.isEmpty(path)) {
                logger.error("必要的入参数据不正确，请检查！");
                return Result.error("必要的入参数据不正确，请检查！");
            }
            this.updateClassfile(serviceFlow, packageName, className, path, BrokerConstant.PROCESSOR);

            SystemCamelContext.getDefaultCamelContext().stopRoute(serviceFlow);
            SystemCamelContext.getDefaultCamelContext().removeRoute(serviceFlow);

            DynamicClassLoader classLoader = new DynamicClassLoader(DynamicClassLoader.class.getClassLoader());
            Class<RouteBuilder> routeBuilderClass = (Class<RouteBuilder>) classLoader.loadClass(ClassLoader.getSystemResource(CoreConstant.EMPTY).getPath(), SystemClassMapping.getSystemClassNameMapping().get(serviceFlow + BrokerConstant.ROUTE));
            classLoader.loadClass(ClassLoader.getSystemResource(CoreConstant.EMPTY).getPath(), SystemClassMapping.getSystemClassNameMapping().get(serviceFlow + BrokerConstant.PROCESSOR));

            if (routeBuilderClass != null) {
                RouteBuilder routeBuilder = routeBuilderClass.newInstance();
                SystemCamelContext.getDefaultCamelContext().addRoutes(routeBuilder);
            }
            return Result.success("修改处理器成功！");
        } catch (Exception e) {
            logger.error(e);
            return Result.error("修改路由失败！");
        }
    }

    /**
     * 当外界组件通知一个新的RouteDefine路由被定义时，该事件被触发
     */
    public Result onRouteDefineAdded(String serviceFlow , String packageName , String className , String path) {
        try {
            if(StringUtil.isEmpty(serviceFlow) || StringUtil.isEmpty(packageName)
                    || StringUtil.isEmpty(className) || StringUtil.isEmpty(path)) {
                logger.error("必要的入参数据不正确，请检查！");
                return Result.error("必要的入参数据不正确，请检查！");
            }
            File systemClassRootPath = new File(ClassLoader.getSystemResource("").getPath() + "/" + serviceFlow);
            if (!systemClassRootPath.exists()) {
                systemClassRootPath.mkdirs();
            }
            // 第1、2两步处理过程，都是在这里完成
            this.createClassfile(serviceFlow, packageName, className, path, BrokerConstant.ROUTE);

            // 3、===============加载到CamelContext中
            ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader();
            Class<RouteBuilder> routeBuilderClass = (Class<RouteBuilder>) currentClassLoader.loadClass(SystemClassMapping.getSystemClassNameMapping().get(serviceFlow + BrokerConstant.ROUTE));
            if(routeBuilderClass != null) {
                RouteBuilder routeBuilder = routeBuilderClass.newInstance();
                SystemCamelContext.getDefaultCamelContext().addRoutes(routeBuilder);
            }
            return Result.success("新增路由成功！");
        } catch (Exception e) {
            logger.error(e);
            return Result.error("新增路由失败！");
        }
    }

    /**
     * 当外界组件通知一个已有的RouteDefine路由定义被改变时，主要就是路由定义内容被改变时，该事件被触发。
     */
    public Result onRouteDefineChanged(String serviceFlow, String packageName, String className, String path) {
        try {
            if (StringUtil.isEmpty(serviceFlow) || StringUtil.isEmpty(packageName)
                    || StringUtil.isEmpty(className) || StringUtil.isEmpty(path)) {
                logger.error("必要的入参数据不正确，请检查！");
                return Result.error("必要的入参数据不正确，请检查！");
            }
            SystemCamelContext.getDefaultCamelContext().stopRoute(serviceFlow);
            SystemCamelContext.getDefaultCamelContext().removeRoute(serviceFlow);
            this.updateClassfile(serviceFlow, packageName, className, path, BrokerConstant.ROUTE);
            // 3、===============加载到CamelContext中
            DynamicClassLoader classLoader = new DynamicClassLoader(DynamicClassLoader.class.getClassLoader());
            Class<RouteBuilder> routeBuilderClass = (Class<RouteBuilder>) classLoader.loadClass(ClassLoader.getSystemResource(CoreConstant.EMPTY).getPath(), SystemClassMapping.getSystemClassNameMapping().get(serviceFlow + BrokerConstant.ROUTE));
            if (routeBuilderClass != null) {
                RouteBuilder routeBuilder = routeBuilderClass.newInstance();
                SystemCamelContext.getDefaultCamelContext().addRoutes(routeBuilder);
            }
            return Result.success("修改路由成功！");
        } catch (Exception e) {
            return Result.error("修改路由失败！");
        }
    }

    /**
     * 当外界组件通知一个已有的RouteDefine路由定义被删除时，该事件被触发。
     */
    public Result onRouteDefineDelete(String serviceFlow, String packageName, String className) {
        try {
            if(StringUtil.isEmpty(serviceFlow) || StringUtil.isEmpty(packageName)
                    || StringUtil.isEmpty(className)) {
                logger.error("必要的入参数据不正确，请检查！");
                return Result.error("必要的入参数据不正确，请检查！");
            }

            SystemCamelContext.getDefaultCamelContext().stopRoute(serviceFlow);
            SystemCamelContext.getDefaultCamelContext().removeRoute(serviceFlow);
            this.deleteClassfile(serviceFlow, packageName, className, BrokerConstant.PROCESSOR);
            return Result.success("删除路由成功！");
        } catch (Exception e) {
            return Result.error("删除路由失败！");
        }
    }

    /**
     * 启动路由时，该事件被触发。
     */
    public Result onRouteDefineStart(String serviceFlow) {
        try {
            if(StringUtil.isEmpty(serviceFlow)) {
                logger.error("必要的入参数据不正确，请检查！");
                return Result.error("必要的入参数据不正确，请检查！");
            }

            SystemCamelContext.getDefaultCamelContext().startRoute(serviceFlow);
            return Result.success("启动路由成功！");
        } catch (Exception e) {
            return Result.error("启动路由失败！");
        }
    }

    /**
     * 停止路由时，该事件被触发。
     */
    public Result onRouteDefineStop(String serviceFlow) {
        try {
            if(StringUtil.isEmpty(serviceFlow)) {
                logger.error("必要的入参数据不正确，请检查！");
                return Result.error("必要的入参数据不正确，请检查！");
            }

            SystemCamelContext.getDefaultCamelContext().stopRoute(serviceFlow);
            return Result.success("停止路由成功！");
        } catch (Exception e) {
            return Result.error("停止路由失败！");
        }
    }




    private void createClassfile(String serviceFlow, String packageName, String className, String path, String type) throws MalformedURLException {
        // 1、============
        File systemClassFlowPath = new File(ClassLoader.getSystemResource(CoreConstant.EMPTY).getPath() + "/" + serviceFlow);
        // 记录到工具类中，以便其它线程需要时进行取用
        SystemClassMapping.getSystemClassNameMapping().put(serviceFlow + type, serviceFlow + CoreConstant.DOT + packageName + CoreConstant.DOT + className);

        // 2、============开始写入class文件
        ClassFileUtil.createClassfile(systemClassFlowPath.toURI().toURL(), packageName, className, path);
        // 完成
        logger.info("===================" + packageName + CoreConstant.DOT + className + ".class 生成过程结束");
    }

    private void updateClassfile(String serviceFlow, String packageName, String className, String path, String type) {
        // 1、============
        Map<String, String> systemClassNameMapping = SystemClassMapping.getSystemClassNameMapping();
        String systemClassName = systemClassNameMapping.get(serviceFlow + type);
        if(StringUtil.isEmpty(systemClassName)) {
            return;
        }
        String classPath = ClassLoader.getSystemResource("").getPath() + "/" + serviceFlow + "/" + packageName + "/" + className + ".class";
        // 2、============开始写入class文件
        ClassFileUtil.updateClassfile(classPath, path);
        // 完成
        logger.info("===================" + packageName + CoreConstant.DOT + className + ".class 修改过程结束");
    }

    private void deleteClassfile(String serviceFlow, String packageName, String className, String type) {
        // 1、============
        Map<String, String> systemClassNameMapping = SystemClassMapping.getSystemClassNameMapping();
        String systemClassName = systemClassNameMapping.get(serviceFlow + type);
        if(StringUtil.isEmpty(systemClassName)) {
            return;
        }
        String classPath = ClassLoader.getSystemResource("").getPath() + "/" + serviceFlow + "/" + packageName + "/" + className + ".class";

        // 2、============开始写入class文件
        ClassFileUtil.deleteClassfile(classPath);

        // 完成
        logger.info("===================" + packageName + CoreConstant.DOT + className + ".class 删除过程结束");
    }
}
