
package org.tio.sitexxx.server.http.stat.ip;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tio.core.TioConfig;
import org.tio.http.common.HttpRequest;
import org.tio.http.server.handler.DefaultHttpRequestHandler;
import org.tio.http.server.stat.ip.path.IpAccessStat;
import org.tio.http.server.stat.ip.path.IpPathAccessStat;
import org.tio.http.server.stat.ip.path.IpPathAccessStatListener;
import org.tio.sitexxx.service.service.ConfService;
import org.tio.sitexxx.service.vo.Const;
import org.tio.sitexxx.server.http.WebApiHttpSessionListener;
import org.tio.utils.hutool.StrUtil;
import org.tio.utils.json.Json;

import java.util.HashSet;
import java.util.Objects;
import java.util.Set;

/**
 * 
 * @author tanyaowu 
 * 2016年10月30日 下午1:19:04
 */
public class TioSiteIpPathAccessStatListener implements IpPathAccessStatListener {
	private static Logger log = LoggerFactory.getLogger(TioSiteIpPathAccessStatListener.class);

	public static final TioSiteIpPathAccessStatListener ME_SITE_VIEW = new TioSiteIpPathAccessStatListener();

	public static final TioSiteIpPathAccessStatListener ME_SITE_API = new TioSiteIpPathAccessStatListener();

	private static Set<String> skipExtSet = new HashSet<>();

	static {
		skipExtSet.add("css");
		skipExtSet.add("js");
		skipExtSet.add("ico");
		skipExtSet.add("png");
		skipExtSet.add("jpg");
		skipExtSet.add("swf");
		skipExtSet.add("xml");
		skipExtSet.add("gif");
		skipExtSet.add("jpeg");
		skipExtSet.add("woff");
		skipExtSet.add("map");
		skipExtSet.add("txt");

		skipExtSet.add("mp4");
		skipExtSet.add("m3u8");
		skipExtSet.add("svg");
	}

	/** 
	 * @param tioConfig
	 * @param ip
	 * @param ipAccessStat
	 * @author tanyaowu
	 */
	@Override
	public void onExpired(TioConfig tioConfig, String ip, IpAccessStat ipAccessStat) {
		if (Objects.equals(ipAccessStat.getDurationType(), Const.IpPathAccessStatDuration.DURATION_2)) {
			if (log.isDebugEnabled()) {
				log.debug("ip:{}, \r\nipAccessStat:{} ", ip, Json.toFormatedJson(ipAccessStat));
			}
		}
	}

	private static final String CONF_PREFIX = "ip.access.";

	private static final int STEP = ConfService.getInt(CONF_PREFIX + "STEP", 200);

	//某IP不带session的最多次，默认1000
	private static final int MAX_NO_SESSION_COUNT = ConfService.getInt(CONF_PREFIX + "MAX_NO_SESSION_COUNT", 1000);

	//某IP带不同值sessionid的最多次，默认1000
	private static final int MAX_SESSION_COUNT = ConfService.getInt(CONF_PREFIX + "MAX_SESSION_COUNT", 1000);

	private static final int	G1_MAX_COUNT		= ConfService.getInt(CONF_PREFIX + "G1_MAX_COUNT", 3000);
	private static final int	G1_MAX_PER_SECOND	= ConfService.getInt(CONF_PREFIX + "G1_MAX_PER_SECOND", 5);

	private static final int	G2_MAX_COUNT		= ConfService.getInt(CONF_PREFIX + "G2_MAX_COUNT", 1000);
	private static final int	G2_MAX_PER_SECOND	= ConfService.getInt(CONF_PREFIX + "G2_MAX_PER_SECOND", 50);

	/** 
	 * @param httpRequest
	 * @param ip
	 * @param path
	 * @param ipAccessStat
	 * @param ipPathAccessStat
	 * @author tanyaowu
	 */
	@Override
	public boolean onChanged(HttpRequest httpRequest, String ip, String path, IpAccessStat ipAccessStat, IpPathAccessStat ipPathAccessStat) {
		int allcount = ipAccessStat.count.get();

		if (allcount % STEP != 0) {
			return true;
		}

		log.debug("ip:{}, path:{}", ip, path);

		double preSecond = ipAccessStat.getPerSecond();

		int noSessionCount = ipAccessStat.noSessionCount.get();

		if (noSessionCount > MAX_NO_SESSION_COUNT) {
			return false;
		}

		if (ipAccessStat.sessionIds.size() > MAX_SESSION_COUNT) {
			return false;
		}

		boolean g1;
		boolean g2;

		boolean g1_c1 = allcount > G1_MAX_COUNT; //总访问次数大于该值
		boolean g1_c2 = preSecond > G1_MAX_PER_SECOND; //平均每秒访问次数大于该值
		g1 = g1_c1 && g1_c2;
		if (g1) {
			return false;
		}

		boolean g2_c1 = allcount > G2_MAX_COUNT; //总访问次数大于该值
		boolean g2_c2 = preSecond > G2_MAX_PER_SECOND; //平均每秒访问次数大于该值
		g2 = g2_c1 && g2_c2;
		if (g2) {
			return false;
		}

		String sessionId = DefaultHttpRequestHandler.getSessionId(httpRequest);
		if (StrUtil.isNotBlank(sessionId)) {
			WebApiHttpSessionListener.isValidSessionId(sessionId);
		}

		return true;
	}
}
