package org.bdware.sc.memory;

import org.bdware.sc.boundry.JavaScriptEntry;
import org.bdware.sc.util.JsonUtil;
import wrp.jdk.nashorn.api.scripting.NashornScriptEngine;

import javax.script.Bindings;
import javax.script.ScriptContext;
import java.io.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

public class MemoryDumpUtil {
    public static final String STATELESS_MEMORY = "statelessContractMemory";
    public static AtomicInteger checkPointCounter;   //用于common模式下的检查点计数
    NashornScriptEngine engine;
    String dumpContent;
    MemoryDump memoryDump = null;

    public MemoryDumpUtil(NashornScriptEngine en) {
        this.engine = en;
    }

    public static String getContentFromFile(String path) {
        File file = new File(path);
        ObjectInputStream reader;
        try {
            FileInputStream fileout = new FileInputStream(file);
            GZIPInputStream gzin = new GZIPInputStream(fileout);
            reader = new ObjectInputStream(gzin);
            MemoryDump memoryDump = new MemoryDump();
            //memoryDump.objects = (Map<Long, MemoryObject>) reader.readObject();
            memoryDump = (MemoryDump) reader.readObject();
            reader.close();
            String ret = JsonUtil.toPrettyJson(memoryDump.objects);
            ret += ("<seperate>" + memoryDump.jseDump.invokeID + ";" + memoryDump.jseDump.ranSeed + ";" + memoryDump.jseDump.numsOfCopies + "");
            return ret;
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }

    /*
    public static String getContentFromFile2(String path) {
    	File file = new File(path);
    	ObjectInputStream reader;
    	try {
    		FileInputStream fileout = new FileInputStream(file);
    		reader = new ObjectInputStream(fileout);
    		String ret = (String)reader.readObject();
    		reader.close();
    		return ret;
    	} catch (IOException | ClassNotFoundException e) {
    		e.printStackTrace();
    	}
    	return null;
    }
    */

    //stateful 表示合约是有/无状态合约
    public String dumpMemory(String path, boolean stateful) {
        synchronized (engine) {
            String ret;
            memoryDump = new MemoryDump();

            if (stateful) {
                Bindings bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE);
                MemoryJSObject root = memoryDump.getRoot();
                for (String key : bindings.keySet()) {
                    Object obj = bindings.get(key);
                    long id = memoryDump.allocate(obj);
                    root.addField(key, id);
                }
                memoryDump.jseDump = new JSEDump(JavaScriptEntry.invokeID, Long.parseLong(JavaScriptEntry.currentSyncUtil.contractID), JavaScriptEntry.numOfCopies);
                ret = JsonUtil.toPrettyJson(memoryDump.objects);
            } else { //无状态合约
                memoryDump.jseDump = new JSEDump(JavaScriptEntry.invokeID, Long.parseLong(JavaScriptEntry.currentSyncUtil.contractID), JavaScriptEntry.numOfCopies);
                memoryDump.objects.clear();
                ret = JsonUtil.toPrettyJson(memoryDump.objects);
            }

            ret += "--seperate--";
            ret += (memoryDump.jseDump.invokeID + ";" + memoryDump.jseDump.ranSeed + ";" + memoryDump.jseDump.numsOfCopies);

            if (path == null || path.equals("")) {
                return ret;
            }

            File mem = new File(path);
            File parent = mem.getParentFile();
            if (!parent.exists()) parent.mkdirs();
            ObjectOutputStream writer;
            try {
                FileOutputStream fileout = new FileOutputStream(mem);
                GZIPOutputStream out = new GZIPOutputStream(fileout);
                writer = new ObjectOutputStream(out);
                //writer.writeObject(memoryDump.objects);
                writer.writeObject(memoryDump);
                writer.flush();
                writer.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

            memoryDump = null;

            return ret;
        }
    }


    /*
    public String dumpMemory(String path) {
    	memoryDump = new MemoryDump();
    	Bindings bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE);
    	System.out.println("[MemoryDumpUtil] bindings size=" + bindings.size());
    	MemoryJSObject root = memoryDump.getRoot();
    	for (String key : bindings.keySet()) {
    		System.out.println("[MemoryDumpUtil] dumpMemory " + key);
    		Object obj = bindings.get(key);
    		long id = memoryDump.allocate(obj);
    		root.addField(key, id);

    		System.out.println("[root addFiled] key=" + key + "   id=" + id);
    	}
    	String ret = JsonUtil.toPrettyJson(memoryDump);
    	dumpContent = ret;

    	if(path == null || path.equals("")) {
    		return ret;
    	}

    	File mem = new File(path);
    	File parent = mem.getParentFile();
    	if (!parent.exists())
    		parent.mkdirs();
    	ObjectOutputStream writer;
    	try {
    		FileOutputStream fileout = new FileOutputStream(mem);
    		writer = new ObjectOutputStream(fileout);
    		writer.writeObject(dumpContent);

    		writer.flush();
    		writer.close();
    	} catch (IOException e) {
    		e.printStackTrace();
    	}

    	memoryDump = null;
    	return ret;
    }
    */
}
