/*
 * Copyright (C), 2002-2015, 江苏三六五网络股份有限公司
 * FileName: ServiceContext.java
 * Author:   duhui
 * Date:     2015年1月24日 下午6:27:44
 * Description:     
 * History: 
 * <author>      <time>      <version>    <desc>
 * 修改人姓名                          修改时间                        版本号                                 描述
 */
package com.house365.rest.context;

import com.google.common.base.Strings;
import com.house365.rest.exception.NeedRollBackException;
import com.house365.rest.exception.ServiceConfigException;
import com.house365.web.util.ContextUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * 服务上下文容器
 * 负责服务创建、启动、监控等
 * 目前主要实现创建、启动
 *
 * @author duhui
 * @version [v1.0.0, 2015年1月24日]
 * @see [相关类/方法]（可选）
 * @since [产品/模块版本] （可选）
 */
public final class ServiceContext {

    /**
     * 单例容器 参见Servlet单例多线程
     */

    private ServiceContext() {
    }

    private static ServiceContext context;

    /**
     * 接口监控器
     */
    private static ServiceMonitor serviceMonitor;

    /**
     * 日志记录器
     */
    private static final Logger LOGGER = LoggerFactory.getLogger("InterfaceLog");

    /**
     * 静态内部类方式
     */
    private static class ServiceContextHolder {
        private static final ServiceContext INSTANCE = new ServiceContext();
    }

    /**
     * 达到lazy loading效果
     */
    public static final ServiceContext getInstance() {
        serviceMonitor = new ServiceMonitor();
        context = ServiceContextHolder.INSTANCE;
        return context;
    }

    /**
     * 根据服务名实例化相应服务
     *
     * @param sid 服务名
     * @return 服务实例
     * @throws ServiceConfigException 如果无法创建服务实例则抛出服务定义异常
     */
    public IService createServiceInstance(String sid) throws ServiceConfigException {
        IService service = null;
        try {
            service = (IService) ContextUtils.getApplicationContext().getBean(sid);
        } catch (BeansException be) {
            LOGGER.error("创建服务实例异常:" + be.getMessage());
            throw new ServiceConfigException("Spring服务配置错误(sid=" + sid + ").", be);
        } catch (ClassCastException ce) {
            LOGGER.error("创建服务实例异常:" + ce.getMessage());
            throw new ServiceConfigException("服务接口不满足规范,类型转换失败.", ce);
        }

        return service;
    }

    /**
     * 启动指定的服务
     *
     * @param service   要启动的服务，可以为空
     * @param parameter 服务参数，可以为空
     * @param initText  服务参数初始化信息，可以为空
     * @param input     服务输入，可以为空
     * @return 服务执行结果
     */
    public Object startService(IService service, Parameter parameter, String initText, Object input) throws Exception {
        if (service == null) {
            return handleNullService();
        }
        
        /*
         * 启动服务监视
         */
        final String serviceName = parameter.getArg("serviceName") == null ? "" : (parameter.getArg(
            "serviceName").getClass().isArray() ? ((String[]) parameter.getArg("serviceName"))[0] : String.valueOf(
            parameter.getArg("serviceName")));
        long start = System.currentTimeMillis();
        
        /*
         * 执行服务
         */
        Object result = null;

        try {
            result = service.exectue(parameter);
        } catch (NeedRollBackException rbe) {
            service.rollback();
            throw new Exception(rbe);
        } catch (Exception ex) {
            LOGGER.error("[" + start + "] 调用服务 [" + serviceName + "] 异常：" + ex.getMessage(), ex);
            throw new Exception(ex);
        } finally {
            LOGGER.info("[" + start + "] 服务用时：[{}] -- [{}]ms", serviceName, System.currentTimeMillis() - start);
        }
        return result;
    }

    /**
     * 启动指定的服务(重载)
     *
     * @param service   要启动的服务，可以为空
     * @param parameter 服务参数，可以为空
     * @param initText  服务参数初始化信息，可以为空
     * @return 服务执行结果
     */
    public Object startService(IService service, Parameter parameter, String initText) throws Exception {
        return startService(service, parameter, initText, null);
    }

    /**
     * 启动指定的服务(重载)
     *
     * @param service   要启动的服务，可以为空
     * @param parameter 服务参数，可以为空
     * @return 服务执行结果
     */
    public Object startService(IService service, Parameter parameter) throws Exception {
        return startService(service, parameter, null, null);
    }

    /**
     * 启动指定的服务(重载)
     *
     * @param service 要启动的服务，可以为空
     * @return 服务执行结果
     */
    public Object startService(IService service) throws Exception {
        return startService(service, null, null, null);
    }

    public Object startServiceWithMethod(
        IService service, Map<String, Object> parameter, String methodName
    ) throws Exception {
        if (service == null) {
            return handleNullService();
        }

        String serviceName = parameter.containsKey("serviceReg") ? (String) parameter.get("serviceReg") : "";

        if (Strings.isNullOrEmpty(serviceName)) {
            serviceName = parameter.get("serviceName").getClass().isArray() ? ((String[]) parameter.get(
                "serviceName"))[0] : String.valueOf(parameter.get("serviceName"));
        }

        long start = System.currentTimeMillis();
        Object result = null;
        try {
            Method method = service.getClass().getDeclaredMethod(methodName, Map.class);
            result = method.invoke(service, parameter);
        } catch (Exception ex) {
            LOGGER.error("[" + start + "] 调用服务 [" + serviceName + "] 方法 [" + methodName + "]，异常：", ex);
            throw new Exception(ex);
        } finally {
            LOGGER.info("[" + start + "] 服务用时：[{" + serviceName + "}.{" + methodName + "}] -- [{}]",
                        System.currentTimeMillis() - start);
        }
        return result;
    }

    public Object startServiceWithMethodNew(
        IService service, Parameter para, String methodName
    ) throws Exception {
        if (service == null) {
            return handleNullService();
        }
        Map<String, Object> parameter = para.getArgs();
        String serviceName = parameter.containsKey("serviceReg") ? (String) parameter.get("serviceReg") : "";

        if (Strings.isNullOrEmpty(serviceName)) {
            serviceName = parameter.get("serviceName").getClass().isArray() ? ((String[]) parameter.get(
                "serviceName"))[0] : String.valueOf(parameter.get("serviceName"));
        }

        long start = System.currentTimeMillis();
        Object result = null;
        try {
            Method method = service.getClass().getDeclaredMethod(methodName, Parameter.class);
            result = method.invoke(service, para);
        } catch (Exception ex) {
            LOGGER.error("[" + start + "] 调用服务 [" + serviceName + "] 方法 [" + methodName + "]，异常：", ex);
            throw new Exception(ex);
        } finally {
            LOGGER.info("[" + start + "] 服务用时：[{" + serviceName + "}.{" + methodName + "}] -- [{}]",
                        System.currentTimeMillis() - start);
        }
        return result;
    }

    /**
     * 处理空服务，待完善，目前返回空
     *
     * @return 处理结果
     */
    private Object handleNullService() {
        return null;
    }

    /**
     * 生成服务ID
     *
     * @return 随机服务ID
     * @see java.util.UUID
     */
    private String generateServiceId() {
        return java.util.UUID.randomUUID().toString();
    }

}
