#!/usr/bin/env python3
# -*-coding=utf-8-*-

# This tool is used to analyze the file generated by compare_binary_iodump.py.
# parse() can build a dependency tree with those varnodes
# where accuracy shake occurs and show the root varnodes.
# get_varNode()/get_dependence_list()/get_reference_list()/show_src_info()
# are some functions which are used to query dependencies between varnodes.
import argparse
import os


class varNode:
    var_node_dict = {}
    var_node_root_dict = {}

    def __init__(self, id, dependence_list, src_info):
        self.src_info = src_info
        if not id in varNode.var_node_dict.keys():
            self.id = id
            self.dependence_list = []
            self.reference_list = []
        else:
            self = varNode.var_node_dict[id]

        if dependence_list:
            self.vitrual = False
            self.is_root = True
        else:
            self.vitrual = True
            self.is_root = False

        for i in dependence_list:
            if not i in varNode.var_node_dict.keys():
                varNode.var_node_dict[i] = varNode(i, [], "")

            dv = varNode.var_node_dict[i]
            self.dependence_list.append(dv)
            if not dv.vitrual:
                self.is_root = False
            dv.reference_list.append(self)

        for i in self.reference_list:
            i.is_root = False
            varNode.var_node_root_dict.pop[i.id]

        if self.is_root:
            varNode.var_node_root_dict[id] = self

        varNode.var_node_dict[id] = self

    @staticmethod
    def get_varNode(id):
        return varNode.var_node_dict[id]

    def get_dependence_list(self):
        return self.dependence_list

    def get_reference_list(self):
        return self.reference_list

    def show_src_info(self):
        print(self.src_info)


def get_dependence(string, src_info):
    start1 = "id:"
    end1 = ","
    e = 0

    count = string.count(start1)
    dependence_list = []
    for x in range(0, count):
        s = string.find(start1, e)
        e = string.find(end1, s)
        sub_str = string[s:e]
        if x == 0:
            var = sub_str
        else:
            dependence_list.append(sub_str)
    varNode(var, dependence_list, src_info)


def parse(filename):
    with open(filename) as f:
        varNode.var_node_dict.clear()
        varNode.var_node_root_dict.clear()
        line = f.readline()
        s = ["", "", ""]
        idx = 1
        while line:
            if line.find("not equal: ") != -1:
                s[2] = line
                src_info = s[0] + "\n" + s[1] + "\n" + s[2]
                get_dependence(s[0], src_info)
            else:
                if line.find("var={id:") != -1:
                    idx = idx ^ 1
                    s[idx] = ""
                s[idx] = s[idx] + line.strip()
            line = f.readline()

    return varNode.var_node_root_dict


def main():
    parser = argparse.ArgumentParser(
        description=(
            "Analyze the outputs of compare_binary_iodump.py"
            "Should save the outputs of compare_binary_iodump.py"
            "as a file"
        ),
        formatter_class=argparse.ArgumentDefaultsHelpFormatter,
    )
    parser.add_argument(
        "filename", help="file which save the outputs of compare_binary_iodump.py"
    )
    args = parser.parse_args()

    parse(args.filename)

    print("varnode root:")
    for key, value in varNode.var_node_root_dict.items():
        print(key)
        print("detail info:")
        value.show_src_info()


if __name__ == "__main__":
    main()
