package com.brilliance.isc.common.validator.es.factory;

import com.brilliance.isc.common.validator.es.vo.EnvDespVo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.script.*;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * CompiledScript工厂，存放CompileScript缓存
 * @author fukai
 */
@Component
public class CompiledScriptFactory {

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

    private static Map<String, CompiledScript> cache = new ConcurrentHashMap<>();

    private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();

    @Resource
    private ScriptTemplateFactory scriptTemplateFactory;

    public CompiledScript getCompileScriptByScriptName(EnvDespVo envDespVo) {
        String scriptName = envDespVo.getScriptName();
        try {
            rwl.readLock().lock();
            if (cache.containsKey(scriptName)) {
                return cache.get(scriptName);
            }
            synchronized (cache) {
                if (cache.containsKey(scriptName)) {
                    return cache.get(scriptName);
                }
                ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
                ScriptEngine scriptEngine = scriptEngineManager.getEngineByName("nashorn");
                String script = scriptTemplateFactory.getEsScript(envDespVo,null);
                try {
                    //如果是调试模式，改为Load模式执行
                    if(scriptTemplateFactory.isDebugMode()){
                        script = scriptTemplateFactory.saveBakEsScript(envDespVo,script);
                    }
                    CompiledScript compiledScript = ((Compilable) scriptEngine).compile(script);
                    if(!scriptTemplateFactory.isDebugMode()) {
                        cache.put(scriptName, compiledScript);
                    }
                    return compiledScript;
                } catch (ScriptException e) {
                    logger.error("failed to compile js:{}", e);
                    throw new RuntimeException("failed to compile js", e);
                }
            }
        } finally {
            rwl.readLock().unlock();
        }
    }

    public void resetCache() {
        rwl.writeLock().lock();
        cache.clear();
        rwl.writeLock().unlock();
    }

}
