package cn.myapps.runtime.excutor.async;

import cn.myapps.runtime.common.dao.WrapConnection;
import cn.myapps.runtime.workflow.storage.runtime.dao.AbstractFlowStateRTDAO;
import cn.myapps.runtime.workflow.storage.runtime.ejb.FlowStateRT;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Set;

/**
 * 异步处理器，只有明确知道是安全的情况下，才启用异步处理器提升性能，目前包括：
 *
 * 1 - DocumentAuthor信息 2 - DocumentLog信息 3 - DocumentHeader 4 - 流程历史
 *
 * @author Jarod
 *
 */
@Aspect
@Component
public class FlowStateRTDAOAspect {
	private Logger logger = LoggerFactory.getLogger(FlowStateRTDAOAspect.class);

	private final static String CACHE_KEY = "RUNTIME_DAO_CACHE_KEY";

	@Autowired
	private RedisUtil redisUtil;

	@Autowired
	private RuntimeDaoCommandDispatch commandExecutor;

	/**
	 * @Description: 定义切入点
	 */
	@Pointcut("(execution(public * cn.myapps.runtime.workflow.storage.runtime.dao.AbstractFlowStateRTDAO.*(..)))")
	public void pointCut() {
	}

	/**
	 * @Description: 环绕通知,环绕增强，相当于MethodInterceptor
	 */
	@SuppressWarnings("unchecked")
	@Around("pointCut()")
	public Object around(ProceedingJoinPoint pjp) {
		try {
			String methodName = pjp.getSignature().getName();

			if (methodName.equals("getConnection") || methodName.equals("setConnection")) {
				return pjp.proceed();
			}

			Object[] args = pjp.getArgs();

			AbstractFlowStateRTDAO thisObj = (AbstractFlowStateRTDAO) pjp.getTarget();
			String typeName = thisObj.getClass().getName().split("[$][$]")[0];// 处理cglib
			WrapConnection wconn = thisObj.getConnection();

			String signLongString = pjp.getSignature().toString();
			int pos = signLongString.lastIndexOf(".");
			String signString = signLongString.substring(pos + 1, signLongString.length());
			logger.debug("MethodInterceptor ARROUND $${}",signString);

			Object o = null;
			switch (signString) {
				case "create(FlowStateRT)": {
					asyncExecMethod(pjp, methodName, args, typeName, wconn);
					FlowStateRT flowState = (FlowStateRT) args[0];
					if (flowState != null) {
						String id = flowState.getId();
						String key = "FlowStateRT:" + id.replace("-", ":");
						redisUtil.set(key, flowState, 0);
					}
					break;
				}

				case "update(FlowStateRT)":{
					asyncExecMethod(pjp, methodName, args, typeName, wconn);
					FlowStateRT flowState = (FlowStateRT) args[0];
					if (flowState != null) {
						String id = flowState.getId();
						String key = "FlowStateRT:" + id.replace("-", ":");
						redisUtil.set(key, flowState, 0);
					}
					break;
				}
				case "remove(String)":{
					asyncExecMethod(pjp, methodName, args, typeName, wconn);
					String id = (String) args[0];
					String key = "FlowStateRT:" + id.replace("-", ":");
					o = redisUtil.get(key);
					if (o != null) {
						//删除FlowStateRT
						redisUtil.del(key);
						//级联删除NodeRT
						Set<String> nkeys = redisUtil.keys("NodeRT:" + id + "*");
						for (String nkey : nkeys) {
							redisUtil.del(nkey);
						}
						//级联删除ActorRT
						Set<String> akeys = redisUtil.keys("ActorRT:" + id + "*");
						for (String akey : akeys) {
							redisUtil.del(akey);
						}
					}
					break;
				}
				case "find(String)": {
					String id = (String) args[0];
					String key = "FlowStateRT:" + id.replace("-", ":");
					o = redisUtil.get(key);
					if (o == null) {
						o = pjp.proceed();
						if(o != null){
							redisUtil.set(key, o, 0);
						}
					}
					break;
				}

				case "queryFlowStateRTByDocId(String)": {
					o = pjp.proceed();
					/*
					String docid = (String) args[0];
					String pattern = "FlowStateRT:" + docid.replace("-", ":") + ":*";

					ArrayList<FlowStateRT> rtns = new ArrayList<FlowStateRT>();
					Set<String> keys = redisUtil.keys(pattern);
					for (String key : keys) {
						FlowStateRT flowState = (FlowStateRT)redisUtil.get(key);
						if(flowState != null){
							rtns.add(flowState);
						}
						o = rtns;
					}

					if (rtns.isEmpty()) {
						o = pjp.proceed();
						if (o !=null && o instanceof Collection) {
							for (FlowStateRT flowState  : (Collection<FlowStateRT>)o) {
								String key = "FlowStateRT:" + flowState.getId().replace("-", ":");
								redisUtil.set(key, flowState, 0);
							}
						}
					}
					 */
					break;
				}
//			case "removeFlowStateRTByDocId(String)":{
//				String docid = (String) args[0];
//				String pattern = "FlowStateRT:" + docid + ":*";
//				Set<String> keys = redisUtil.keys(pattern);
//				if (!keys.isEmpty()) {
//					for (String key : keys) {
//						redisUtil.del(key);
//					}
//				}
//				asyncExecMethod(pjp, methodName, args, typeName, wconn);
//				break;
//			}
//			case "querySubFlowStateRT(String)"://
//			case "isAllFlowInstancesCompleted(String)"://
//			case "isAllSubFlowStateRTComplete(FlowStateRT)"://
//			case "isMultiFlowState(IDocument)"://
//			case "isMultiFlowState(String,String,Collection)"://


				default:// 其他方法
					o = pjp.proceed();
					break;
			}
			return o;

		} catch (Throwable e) {
			logger.error(e.getMessage());
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * 当线程变量中的groupcommand被初始化后采用异步执行，否则同步执行
	 *
	 * @param pjp
	 * @param methodName
	 * @param args
	 * @param typeName
	 * @param wconn
	 * @throws Throwable
	 */
	private void asyncExecMethod(ProceedingJoinPoint pjp, String methodName, Object[] args, String typeName,
								 WrapConnection wconn) throws Throwable {
		if (RuntimeDaoCommandDispatch.initialized()) {
			commandExecutor.addToExecGroup(new RuntimeDaoCommand(typeName, methodName, args, wconn.getApplicationId()));
		} else {
			pjp.proceed();
		}
	}

}