package org.bdware.analysis.example;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.bdware.analysis.BasicBlock;
import org.bdware.analysis.FrontCF;
import org.bdware.analysis.taint.TaintBB;
import org.bdware.analysis.taint.TaintCFG;
import org.bdware.analysis.taint.TaintResult;
import org.bdware.sc.ContractResult;
import org.bdware.sc.compiler.YJSCompiler;
import org.bdware.sc.engine.DesktopEngine;
import org.bdware.sc.node.ContractNode;
import org.bdware.sc.node.FunctionNode;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.MethodNode;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.zip.ZipFile;

public class MultiSourceTaintAyalysisTest extends MultiSourceTaintAnalysis {
    public MultiSourceTaintAyalysisTest(TaintCFG cfg) {
        super(cfg);
    }

    public static void main(String[] args) throws Exception {
        long start = System.currentTimeMillis();
        // String clzPath =
        // "./output/traceTest/wrp/jdk/nashorn/internal/scripts/Script$Recompilation$7$23A$contract_main_yjs7.class";

        // String path =
        // "/Users/damei/Documents/Project/DataContract/SmartContract/contractExamples/traceTest/main.yjs";
        String path =
                "/Users/damei/Documents/Project/DataContract/SmartContract/contractExamples/Test.yjs";

        ContractNode contractNode = null;
        YJSCompiler compiler = new YJSCompiler();

        // contractNode = compiler.compile(new FileInputStream(path), "contract_main.yjs");
      //  contractNode = compiler.compile(new FileInputStream(path), "DORepo.yjs");
        contractNode =
                compiler.compile(
                                new ZipFile(
                                        "/Users/huaqiancai/BDWare/BDContract/front-agent/./BDWareProjectDir/publicCompiled/StaticAnalysisExample_2020-07-09-00.ypk"))
                        .mergeContractNode();
        DesktopEngine engine = new DesktopEngine(); // engine.loadJar(zf);
        ContractResult result2 = engine.loadContract(null,contractNode, false);
        System.out.println("----LoadResult------");
        System.out.println(new Gson().toJson(result2));
        Map<String, byte[]> clzs = engine.dumpClass();
        Map<String, MethodNode> methods = new HashMap<>();
        System.out.println("[ContractManager] load bytecode:");
        for (byte[] clz : clzs.values()) {
            ClassNode classNode = new ClassNode();
            ClassReader cr = new ClassReader(clz);
            cr.accept(classNode, ClassReader.EXPAND_FRAMES);
            for (MethodNode mn : classNode.methods) {
                methods.put(mn.name, mn);
                System.out.println("[ContractManager] putMethod:" + mn.name);
            }
        }
        Map<String, String> result = new HashMap<>();
        for (FunctionNode fn : contractNode.getFunctions()) {
            MethodNode mn = methods.get(fn.functionName);
            if (mn != null) {
                TaintResult.nLocals = mn.maxLocals;
                TaintResult.nStack = mn.maxStack;
                TaintCFG cfg = new TaintCFG(mn);

                // DependencyAnalysis

                // if(fn.functionName.equals("depTest"))
               // depAnalysis(cfg);





                TaintResult.printer.setLabelOrder(cfg.getLabelOrder());
                MultiSourceTaintAnalysis analysis = new MultiSourceTaintAnalysis(cfg);
                analysis.analysis();
                Map<Integer, List<Integer>> map = MultiSourceTaintAnalysis.depAnalysis(cfg);
                FrontCF frontCF = new FrontCF(cfg);
                String[] data = fn.plainText().split("\n");
                for (int i = 0; i < cfg.getBasicBlockSize(); i++) {
                    BasicBlock bb = cfg.getBasicBlockAt(i);
                    String decompiled = "";
                    if (bb.lineNum - 1 < data.length && bb.lineNum > 0) {
                        decompiled = data[bb.lineNum - 1];
                    }
                    List<Integer> ids = map.get(i);
                    frontCF.addBB(bb, decompiled, ids, cfg);
                    Set<BasicBlock> suc = cfg.getSucBlocks(bb);
                    for (BasicBlock sucBB : suc) frontCF.addEdge(bb, sucBB);
                }
                TaintBB bb = cfg.getLastBlock();
                cfg.printSelf();
                // printTest
                // if(fn.functionName.equals("setDBInfo"))
                // cfg.printSelf();

                if (bb != null) result.put(fn.functionName, bb.getResultWithTaintBit());
                System.out.println("[ContractManager] verifyDone:" + fn.functionName);
            }
        }
        System.out.println(new GsonBuilder().setPrettyPrinting().create().toJson(result));
        long end = System.currentTimeMillis();
        System.out.println(end - start);
    }
}
