package com.elab.log.filter;

import com.dianping.cat.Cat;
import com.dianping.cat.CatConstants;
import com.dianping.cat.message.Event;
import com.dianping.cat.message.Transaction;
import com.dianping.cat.message.internal.AbstractMessage;
import com.dianping.cat.message.internal.NullMessage;
import com.elab.core.utils.StringUtils;
import com.elab.log.utils.CatCrossProcess;
import com.elab.log.utils.CatMsgConstants;
import com.elab.log.utils.CatMsgContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * Cat消息串联过滤器
 *
 * @author : liukx
 * @create : 2018/7/2 11:31
 * @email : liukx@elab-plus.com
 */
public class HttpCatCrossFliter implements Filter {

    private static final Logger logger = LoggerFactory.getLogger(HttpCatCrossFliter.class);

    private static final String DEFAULT_APPLICATION_NAME = "default";

    private List<String> includeContentTypeList = new ArrayList<>();

    public void addincludeContentType(String resource) {
        includeContentTypeList.add(resource);
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain filterChain) throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;
        String requestURI = request.getRequestURI();
        String contentType = request.getContentType();
//        String method = request.getMethod();
        // 过滤非匹配的拦截请求
//        if (!"GET".equals(method) && !includeContentType(contentType)) {
////            filterChain.doFilter(req, resp);
////            return;
////        }


        String rootId = request.getHeader(Cat.Context.ROOT);
        String parentId = request.getHeader(Cat.Context.PARENT);
        String childId = request.getHeader(Cat.Context.CHILD);
        Transaction t = null;
        try {
            // 如果包含调用关系
            if (StringUtils.areNotEmpty(rootId, parentId, childId)) {
                logger.debug(" 开启CAT消息树串联模式 ... " + requestURI + " \t " + contentType + " 相关消息编号 : rootId : " + rootId + " parentId :" + parentId + " childId : " + childId);
                t = Cat.newTransaction(CatMsgConstants.CROSS_SERVER, requestURI);
                Cat.Context context = new CatMsgContext();
                context.addProperty(Cat.Context.ROOT, rootId);
                context.addProperty(Cat.Context.PARENT, parentId);
                context.addProperty(Cat.Context.CHILD, childId);
                Cat.logRemoteCallServer(context);
                CatCrossProcess.createProviderCross(request, t);
            } else {
                logger.debug(" 开启普通URL请求调用 ... ");
                t = Cat.getProducer().newTransaction(CatConstants.TYPE_URL, requestURI);
            }
            filterChain.doFilter(req, resp);
            t.setStatus(Transaction.SUCCESS);
        } catch (Exception e) {
            logger.error("------ Get cat msgtree error : ", e);
            Event event = Cat.newEvent("HTTP_REST_CAT_ERROR", requestURI);
            event.setStatus(e);
            completeEvent(event);
            t.addChild(event);
            t.setStatus(e.getClass().getSimpleName());
        } finally {
            t.complete();
            logger.debug("CAT 调用完毕 ... ");
        }
    }

    @Override
    public void init(FilterConfig arg0) throws ServletException {
        // 初始化默认的拦截请求类型
        includeContentTypeList.add(MediaType.APPLICATION_JSON_VALUE);
        includeContentTypeList.add(MediaType.APPLICATION_FORM_URLENCODED_VALUE);
    }

    /**
     * 排除静态资源
     *
     * @param url
     * @return
     */
    public boolean includeContentType(String url) {
        if (url == null) {
            return false;
        }
        for (int i = 0; i < includeContentTypeList.size(); i++) {
            String contentType = includeContentTypeList.get(i);
            if (url.startsWith(contentType)) {
                return true;
            }
        }
        return false;
    }

    @Override
    public void destroy() {
    }

    private void completeEvent(Event event) {
        if (event != NullMessage.EVENT) {
            AbstractMessage message = (AbstractMessage) event;
            message.setCompleted(true);
        }
    }

}