package org.bdware.analysis.example;

import org.bdware.analysis.BasicBlock;
import org.bdware.analysis.BreadthFirstSearch;
import org.bdware.analysis.taint.*;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.LabelNode;

import java.util.*;

public class NaiveTaintAnalysis extends BreadthFirstSearch<TaintResult, TaintBB> {
    TaintCFG cfg;

    public NaiveTaintAnalysis(TaintCFG cfg) {
        this.cfg = cfg;
        List<TaintBB> toAnalysis = new ArrayList<>();
        // TODO add inputBlock!
        TaintBB b = (TaintBB) cfg.getBasicBlockAt(0);

        b.preResult = new TaintResult();
        // local0=scriptfuncion, is not tainted;
        // local1=this, is not tainted;
        // local2=this, is not tainted;
        if (TaintResult.nLocals > 2) {
            b.preResult.frame.setLocal(0, new TaintValue(1, 0));
            b.preResult.frame.setLocal(1, new TaintValue(1, 0));
            b.preResult.frame.setLocal(2, new TaintValue(1, 1));
        }
        b.preResult.ret = new TaintValue(1);
        TaintResult.printer.setLabelOrder(cfg.getLabelOrder());
        toAnalysis.add(b);
        b.setInList(true);
        setToAnalysis(toAnalysis);
        if (TaintConfig.isDebug) {
            System.out.println("===Method:" + cfg.getMethodNode().name + cfg.getMethodNode().desc);
            System.out.println(
                    "===Local:"
                            + cfg.getMethodNode().maxLocals
                            + " "
                            + cfg.getMethodNode().maxStack);
        }
    }

    @Override
    public TaintResult execute(TaintBB t) {
        return t.forwardAnalysis();
    }

    // Current Block is done, merge sucResult to sucBlocks!
    @Override
    public Collection<TaintBB> getSuc(TaintBB t) {
        // System.out.println("---------------------------------");
        // System.out.println("XXXXXB" + t.blockID + " sucBlock:" +
        // t.sucResult.frame2Str());
        Set<BasicBlock> subBlock = cfg.getSucBlocks(t);
        System.out.println("ttlist" + t.list);
        System.out.println("subblock" + subBlock.size());
        Set<TaintBB> ret = new HashSet<>();
        AbstractInsnNode insn = t.lastInsn();
        if (insn instanceof LabelNode) {
            LabelNode label = ((LabelNode) insn);
            System.out.println("-----");
            System.out.println("label" + label.getLabel().toString());
            System.out.println(cfg.getBasicBlockByLabel(label.getLabel()).blockID);
        }

        for (BasicBlock bb : subBlock) {
            System.out.println(bb.blockID);
            TaintBB ntbb = (TaintBB) bb;
            ntbb.preResult.mergeResult(t.sucResult);
            // System.out.println(
            // "XXXXXB" + ntbb.blockID + " mergedBlock:" + ntbb.preResult.frame2Str() + " "
            // + ntbb.preResult);
            ret.add(ntbb);
        }
        // System.out.println("---------------------------------");
        return ret;
    }
}
