package com.goafanti.core.shiro.cache;

import com.goafanti.common.utils.LoggerUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.shiro.cache.AbstractCacheManager;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.springframework.data.redis.core.RedisTemplate;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.util.Objects;
import java.util.regex.Pattern;

public class ShiroRedisCacheManager extends AbstractCacheManager {

	private RedisTemplate<String, Object>	redisTemplate;

	private long							expire	= 2592000l;	// 秒

	private static final ScriptEngine scriptEngine = new ScriptEngineManager().getEngineByName("JavaScript");

	private static final Pattern pattern = Pattern.compile("[+\\-*/%]");

	/**
	 * 分隔符
	 */
	private char separator = '#';

	@Override
	protected Cache<String, Object> createCache(String name) throws CacheException {
		// 获取默认时间
		long expiration = getExpire();
		int index = name.indexOf(separator);
		if (index > 0) {
			expiration = getExpiration(name, index, expiration);
		}
		return new ShiroRedisCache(redisTemplate, name, expire);
	}

	/**
	 * 计算缓存时间
	 * @param name 缓存名字 cache#60*60
	 * @param separatorIndex 分隔符位置
	 * @param defalutExp 默认缓存时间
	 * @return
	 */
	protected long getExpiration(final String name, final int separatorIndex, final long defalutExp) {
		Long expiration = null;
		String expirationAsString = name.substring(separatorIndex + 1);
		try {
			if (pattern.matcher(expirationAsString).find()) {
				expiration = NumberUtils.toLong(scriptEngine.eval(expirationAsString).toString(), defalutExp);
			} else {
				expiration = NumberUtils.toLong(expirationAsString, defalutExp);
			}
		} catch (ScriptException e) {
			LoggerUtils.fmtError(ShiroRedisCacheManager.class,e,"缓存时间转换错误:{},异常:{}", name, e.getMessage());
		}
		return Objects.nonNull(expiration) ? expiration.longValue() : defalutExp;
	}

	public RedisTemplate<String, Object> getRedisTemplate() {
		return redisTemplate;
	}

	public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) {
		this.redisTemplate = redisTemplate;
	}

	public long getExpire() {
		return expire;
	}

	public void setExpire(long expire) {
		this.expire = expire;
	}

}
