package com.saki.tools;

import com.eclipsesource.v8.V8;
import com.eclipsesource.v8.V8Object;
import com.saki.encode.Canvart;
import com.saki.http.Http;
import com.saki.log.SQLog;
import com.setqq.script.javascript.JavaScript;
import com.setqq.script.lua.Lua;

import org.json.JSONArray;
import org.json.JSONObject;
import org.keplerproject.luajava.LuaState;
import org.keplerproject.luajava.LuaStateFactory;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

public class ScriptUtil {
    public static final String[] UNPACK_SUFFIX = {Lua.SUFFIX,JavaScript.SUFFIX,".bak",".zip"};
    File scriptFile;
    String id;
    public ScriptUtil(String path)
    {
        scriptFile = new File(path);
    }
    public String getId()
    {
        return id;
    }
    public File getScriptFile(){
        return scriptFile;
    }
    public boolean checkScript(){
        try {
            if (scriptFile.getName().endsWith(Lua.SUFFIX)) {
                LuaState l = LuaStateFactory.newLuaState();
                l.openLibs();
                l.LdoString(new String(FileUtil.readFile(scriptFile)));
                id = l.getLuaObject("id").toString();
                if (id.equals("nil"))
                    return false;
                return true;
            } else if (scriptFile.getName().endsWith(JavaScript.SUFFIX)) {
                V8 v8 = V8.createV8Runtime();
                v8.executeScript(new String(FileUtil.readFile(scriptFile)));
                V8Object obj = v8.getObject("Script");
                id = obj.getString("id");
                if (id == null || id.equals(""))
                    return false;
                return true;
            }
        }catch (Exception e) {
            StringWriter sw = new StringWriter();
            e.printStackTrace(new PrintWriter(sw));
            SQLog.e("识别脚本异常:"+sw.toString());
        }
        return false;
    }
    public static void checkScriptPublicLibraryFile(){
        new Thread(new Runnable() {
            private boolean downloadFile(Http http,String name,File file){
                SQLog.i("更新库文件:"+name);
                try {
                    String url = "http://setqqv8.top:8080/SQv8/Script/ScriptLib.jsp?type=file&name=" + name;
                    byte[] bin = http.call("GET",url,null);
                    return FileUtil.writeFile(file,bin);
                }catch (Exception e){e.printStackTrace();}
                return false;
            }
            @Override
            public void run() {
                try {
                    String dir = "http://setqqv8.top:8080/SQv8/Script/ScriptLib.jsp?type=dir";
                    Http get = new Http();
                    String result = new String(get.call("GET",dir,null));
                    JSONObject obj = new JSONObject(result);
                    if(obj.getInt("code") == 0) {
                        JSONArray files = obj.getJSONArray("files");
                        for(int i=0;i<files.length();i++){
                            JSONObject file = files.getJSONObject(i);
                            String name = file.getString("name");
                            String md5 = file.getString("md5");
                            File lib = new File(FileUtil.SCRIPT_LIB_PATH+name);
                            if(!lib.exists()){//文件不存在
                                downloadFile(get,name,lib);
                            }else{
                                String o_md5 = Canvart.Bytes2Hex(FileUtil.getFileMd5(lib),"");
                                if(!o_md5.equals(md5))//文件已过期
                                    downloadFile(get,name,lib);
                            }
                        }
                    }
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        }).start();
    }
    public static String unpackZip(InputStream in,String relesPath) throws  IOException{
        ZipInputStream zip = new ZipInputStream(in);
        ZipEntry entry = null;
        String packname = null;
        while((entry = zip.getNextEntry())!=null){
            if(entry.isDirectory()){
                if(packname == null)
                    packname =entry.getName();
                File tmp = new File(relesPath + entry.getName()+"/");
                if(!tmp.exists())
                    tmp.mkdirs();
            }else{
                File tmp = new File(relesPath + entry.getName());
                if(!tmp.exists()){
                    tmp.getParentFile().mkdirs();
                    tmp.createNewFile();
                }
                OutputStream out = new FileOutputStream(tmp);
                byte[] bin = new byte[0x10000];
                int len = -1;
                while((len = zip.read(bin))!=-1)
                    out.write(bin,0,len);
                out.flush();
                out.close();
            }
        }
        zip.close();
        return packname;
    }
    public static String unpackZip(File zipPath,String relesPath) throws IOException {
       return unpackZip(new FileInputStream(zipPath),relesPath);
    }
    public static byte[] packZip(File lua,String dir){
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        try{
            encodeAndNewFile(lua);
            ZipOutputStream zip = new ZipOutputStream(out);
            packZip(zip, lua.getParentFile().listFiles(), dir,UNPACK_SUFFIX);
            zip.flush();
            zip.close();
        }catch(IOException e){
            e.printStackTrace();
        }
        return out.toByteArray();
    }
    public static byte[] packZip(String path,String dir){
        return packZip(new File(path), dir);
    }
    private static void encodeAndNewFile(File file) throws IOException{
        String path = file.getAbsolutePath();

        path = path.substring(0, path.lastIndexOf("."))+getEncodeSuffix(file);
        File ec = new File(path);
        if(!ec.exists()){
            ec.createNewFile();
        }
        FileUtil.saveEndcodeFile(file,ec);
    }
    private static String getEncodeSuffix(File file){
        if(file.getName().endsWith(Lua.SUFFIX))
            return Lua.ENCODE_SUFFIX;
        if(file.getName().endsWith(JavaScript.SUFFIX))
            return JavaScript.ENCODE_SUFFIX;
        return ".ec";
    }
    public static void packZip(ZipOutputStream zip,File[] fs,String dir,String ...extension) throws IOException{
        if(fs == null)
            return;
        for(File f: fs){
            if(f==null || !f.exists())
                continue;
            if(extension != null){
                boolean skip = false;
                for(int i=0;i<extension.length;i++){
                    if(f.getName().endsWith(extension[i])){
                        skip = true;
                        break;
                    }
                }
                if(skip)
                    continue;
            }
            if(f.isDirectory()){
                String ndir = dir + f.getName()+"/";
                zip.putNextEntry(new ZipEntry(ndir));
                packZip(zip, f.listFiles(),ndir);
            }else{
                zip.putNextEntry(new ZipEntry(dir + f.getName()));
                InputStream in = new FileInputStream(f);
                byte[] bin = new byte[0x10000];
                int len = -1;
                while((len = in.read(bin))!=-1){
                    zip.write(bin, 0, len);
                }
                in.close();
            }
        }
    }

}
