package com.setqq.script.javascript;

import android.webkit.JavascriptInterface;

import com.eclipsesource.v8.V8;
import com.eclipsesource.v8.V8Array;
import com.eclipsesource.v8.V8Object;
import com.saki.service.NewService;
import com.saki.tools.FileUtil;
import com.setqq.script.Msg;
import com.setqq.script.NullIDException;
import com.setqq.script.sdk.ApiAdapter;
import com.setqq.script.sdk.ApiInterface;
import com.setqq.script.sdk.ScriptAdapter;

import java.lang.reflect.Method;

/**
 * Created by Saki on 2018/6/4.
 */

public class JavaScript extends ScriptAdapter{
    public static final String SUFFIX = ".sj";
    public static final String ENCODE_SUFFIX = ".ecj";
    static{
        V8.setFlags("-harmony-dynamic-import");
        V8.setFlags("-harmony-import-meta");
    }
    NewService context;
    V8Object script;
    V8 runtime;

    public JavaScript(NewService context, String fileName) throws Exception {
        this.context = context;
        runtime = V8.createV8Runtime("window");
        runtime.executeVoidScript(FileUtil.loadEncodeFile(fileName));
        script = runtime.getObject("Script");
        id = script.getString("id");
        if(id == null || id.equals(""))
            throw new NullIDException(fileName);
        name = script.getString("name");
        version = script.getString("version");
        author = script.getString("author");
        info = script.getString("info");
        icon = script.getString("icon");
        ui = script.getString("ui");
        path = fileName;
        initScript(context);
        runtime.getLocker().release();
    }

    @Override
    public void onLoad(NewService context) {
        Msg msg = new Msg(19);
        onMessageHandler(msg);
    }

    void execJavaScript(String method, ApiInterface api,String ...param)
    {
        V8Object obj = null;
        V8Array p = null;
        try {
            runtime.getLocker().acquire();
            obj = new V8Object(runtime);
            p = new V8Array(runtime);
            if(api != null) {
                Method[] methods = api.getClass().getMethods();
                for (Method m : methods) {
                    String mn = m.getName();
                    obj.registerJavaMethod(api, mn, mn, m.getParameterTypes());
                }
                p.push(obj);
            }
            for(String s : param){
                p.push(s);
            }
            script.executeFunction(method, p);
        }finally{
            if(obj!=null)
                obj.release();
            if(p!=null)
                p.release();
            if(runtime != null && runtime.getLocker() != null && runtime.getLocker().hasLock()) {
                runtime.getLocker().release();
            }
        }
    }
    @Override
    public void onMessageHandler(Msg msg) {
        execJavaScript("handleMessage",new ApiAdapter(context,this,msg));
    }
    @Override
    public void runFunction(String funName,String param){
        execJavaScript(funName,null,param);
    }
    @Override
    @JavascriptInterface
    public String onAction(String value) {
        V8Object obj = null;
        V8Array p = null;
        try {
            runtime.getLocker().acquire();
            obj = new V8Object(runtime);
            Msg msg = new Msg(-1);
            msg.addMsg("msg", value);
            ApiAdapter api = new ApiAdapter(context,this,msg);
            Method[] methods = api.getClass().getMethods();
            for (Method m : methods) {
                String mn = m.getName();
                obj.registerJavaMethod(api, mn, mn, m.getParameterTypes());
            }
            p = new V8Array(runtime).push(obj);
            String result = script.executeStringFunction("onAction", p);
            return result;
        }finally{
            if(obj!=null)
                obj.release();
            if(p!=null)
                p.release();
            if(runtime != null && runtime.getLocker() != null && runtime.getLocker().hasLock()) {
                runtime.getLocker().release();
            }
        }
    }

    @Override
    public void destroy() {
        try {
            runtime.getLocker().acquire();
            script.release();
            runtime.release();
        }finally {
            if(runtime != null && runtime.getLocker() != null && runtime.getLocker().hasLock()) {
                runtime.getLocker().release();
            }
            runtime = null;
        }
    }

    @Override
    public String getIcon() {
        if(icon!=null&&!icon.equals(""))
            return icon;
        return null;
    }

    @Override
    public boolean hasUI() {
        return ui!=null&&!ui.equals("");
    }
}
