package cn.myapps.runtime.excutor.async;

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 cn.myapps.common.model.ValueObject;
import cn.myapps.runtime.common.dao.WrapConnection;
import cn.myapps.runtime.dynaform.document.dao.AbstractDocStaticTblDAO;
import cn.myapps.runtime.dynaform.document.dql.DQLASTUtil;
import cn.myapps.runtime.dynaform.document.model.IDocument;
import cn.myapps.common.util.cache.EhcacheProvider;
import cn.myapps.common.util.cache.IMyCache;
import cn.myapps.common.util.cache.IMyElement;
import cn.myapps.common.util.cache.MyCacheManager;


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

    private final static String CACHE_KEY = "RUNTIME_DAO_CACHE_KEY";

    @Autowired
    private RuntimeDaoCommandDispatch commandExecutor;

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

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

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

            Object[] args = pjp.getArgs();

            AbstractDocStaticTblDAO thisObj = (AbstractDocStaticTblDAO) 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());

            EhcacheProvider provider = (EhcacheProvider) MyCacheManager.getProviderInstance();
            IMyCache iMyCache = provider.getCache(CACHE_KEY);
            if (iMyCache == null) {
                iMyCache = provider.createCache(CACHE_KEY, 50000, false, false, 24 * 60 * 60, 24 * 60 * 60);
            }

            Object o = null;

            ValueObject vo = null;
            String key = null;
            IMyElement element = null;
            switch (signString) {
                case "create(ValueObject)":// 创建-同步处理
//				execMethod(pjp, methodName, args, typeName, wconn);
                    o = pjp.proceed();
                    vo = (ValueObject) args[0];
                    iMyCache.put(vo.getId(), vo);
                    break;
                case "update(ValueObject)":// 更新-同步处理
//				execMethod(pjp, methodName, args, typeName, wconn);
                    o = pjp.proceed();
                    vo = (ValueObject) args[0];
                    iMyCache.put(vo.getId(), vo);
                case "remove(String)":// 移除-同步处理
//				execMethod(pjp, methodName, args, typeName, wconn);
                    o = pjp.proceed();
                    key = (String) args[0];
                    iMyCache.remove(key);
                    break;
                case "find(String)":// 创建-同步处理
                    key = (String) args[0];
                    element = iMyCache.get(key);
                    o = element == null ? null : element.getValue();
                    if (element == null) {
                        o = pjp.proceed();
                        iMyCache.put(key, o);// 加回缓存
                    }
                    break;
                case "storeDocument(Document)"://保存文档-同步处理
                    vo = (ValueObject) args[0];
                    iMyCache.put(vo.getId(), vo);
                    o = pjp.proceed();
                    break;
                case "removeDocument(IDocument)"://删除文档-同步处理
                    key = ((IDocument) args[0]).getId();
                    iMyCache.remove(key);
                    o = pjp.proceed();
                    break;
                case "updateDocument(IDocument)"://更新文档-同步处理
                    vo = (ValueObject) args[0];
                    iMyCache.put(vo.getId(), null);
                    iMyCache.put(vo.getId(), vo);
                    o = pjp.proceed();
                    break;
                case "createDocument(IDocument)"://同步
                    vo = (ValueObject) args[0];
                    iMyCache.put(vo.getId(), vo);
                    o = pjp.proceed();
                    break;
                case "createDocument(IDocument,int)"://同步
                    int type = (int) args[1];
                    if (type == DQLASTUtil.TABEL_TYPE_CONTENT) {
                        vo = (ValueObject) args[0];
                        iMyCache.put(vo.getId(), vo);
                    }
                    o = pjp.proceed();
                    break;
                case "findVersions(String)"://
                    key = (String) args[0];
                    element = iMyCache.get(key);
                    o = element == null ? null : element.getValue();
                    if (element == null) {
                        o = thisObj.find(key);
                        iMyCache.put(key, o);// 加回缓存
                    }
                    return ((IDocument) o).getVersions();
                case "isExist(String)"://
                    key = (String) args[0];
                    element = iMyCache.get(key);
                    o = element == null ? null : element.getValue();
                    if (element == null) {
                        o = thisObj.find(key);
                        iMyCache.put(key, o);// 加回缓存
                    }
                    return o != null;
                case "createAuthDocWithCondition(String,String,Collection)":///异步
                	asyncExecMethod(pjp, methodName, args, typeName, wconn);
                    break;
                case "createDocumentHead(IDocument)":///异步
                	asyncExecMethod(pjp, methodName, args, typeName, wconn);
                    break;
                case "removeAuthByDoc(Document)":///异步
                	asyncExecMethod(pjp, methodName, args, typeName, wconn);
                    break;
                case "updateWordField(String,String,String,String)"://异步
                    key = (String) args[3];
                    element = iMyCache.get(key);
                    o = element == null ? null : element.getValue();
                    if (element == null) {
                        o = thisObj.find(key);
                        IDocument doc = (IDocument) o;
                        String content = (String) args[0];
                        String fieldname = (String) args[1];
                        doc.findItem(fieldname).setValue(content);
                        iMyCache.put(key, o);// 加回缓存
                    }
                    asyncExecMethod(pjp, methodName, args, typeName, wconn);
                    break;
                case "updateFileSorting(String,String,String,String)"://异步
                    key = (String) args[0];
                    element = iMyCache.get(key);
                    o = element == null ? null : element.getValue();
                    if (element == null) {
                        o = thisObj.find(key);
                        IDocument doc = (IDocument) o;
                        String fieldname = (String) args[2];
                        String content = (String) args[3];
                        doc.findItem(fieldname).setValue(content);
                        iMyCache.put(key, o);// 加回缓存
                    }
                    asyncExecMethod(pjp, methodName, args, typeName, wconn);
                    break;

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

        } catch (Throwable e) {
            throw new Exception(e.getMessage());
        }
    }

    /**
     * 当线程变量中的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();
        }
    }

}