# -*-coding:utf-8-*-
import random
import re
import os


class JavaGarble:
    __used_names = []
    __functions = []
    __logic_model = ""
    __config = {}

    def __gen_rand_str(self):
        result = ""
        while len(result) == 0 or result in self.__used_names:
            result = ''.join(random.sample(
                "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", random.randint(5, 12)))
        self.__used_names.append(result)
        return result

    # 生成方法

    def __generate_function(self, model_path):
        func_scope = ["public", "private", "protected"]
        return_type = ["String", "int", "double", "float"]

        fun_content = ""
        with open(model_path, "r", encoding="utf-8") as fin:
            fun_content = fin.read()

        re_type = return_type[random.randint(0, 3)]
        fun_content = fun_content\
            .replace("${func_scope}", func_scope[random.randint(0, 2)])\
            .replace("${return_type}", re_type)\
            .replace("${func_name}", self.__gen_rand_str())

        # 方法参数
        param_names = []
        params_code = ""
        for i in range(0, random.randint(1, 5)):
            parans_name = self.__gen_rand_str()
            code = "%s %s" % (
                return_type[random.randint(0, 3)],
                parans_name
            )
            params_code += code + ", "
            param_names.append(parans_name)

        params_code = ("%s*" % params_code).replace(", *", "")
        fun_content = fun_content.replace("${params}", params_code)

        # 随机引用全局变量
        for var_code in self.__variables:
            if random.randint(0, 2) % 2 == 0:
                param_names.append(var_code.split(" ")[2])
        return_value = ""
        for name in param_names:
            return_value += name + "+"

        # 转string
        return_value += "\"\""

        if re_type in "int":
            return_value = "(%s).length()" % return_value
        elif re_type in "float":
            return_value = "Float.valueOf((%s).length())" % return_value
        elif re_type in "double":
            return_value = "Double.valueOf((%s).length())" % return_value

        return_value = "return %s;" % return_value

        log_code = ""
        for i in range(0, random.randint(0, 5)):
            log_code += "android.util.Log.%s(\"%s\",\"%s\");\n" % (
                ''.join(random.sample("idew", random.randint(1, 1))),
                ''.join(random.sample(
                    "ABCDEFGHIJKLMNOPQRSTUVWXYZ", random.randint(3, 10))),
                ''.join(random.sample(
                    "ABCDEFGHIJKLMNOPQRSTUVWXYZ", random.randint(5, 15)))
            )

        fun_content = fun_content.replace(
            "${func_content}", log_code + return_value)
        self.__functions.append(fun_content)

        if len(self.__functions) < random.randint(3, 10):
            self.__generate_function(model_path)

    # 插入代码
    def __insert_code(self):
        insert_code = ""
        codes = self.__logic_model.split("@code\n")
        # 选择一个变量
        vars = codes[0].replace("\n", "").split("*")
        index = random.randint(0, len(vars)-1)

        # 选择一段逻辑代码
        models = codes[2].split("@---sep---\n")
        insert_code += models[random.randint(0, len(models)-1)]

        # 选择一个判断条件
        condition = codes[1].replace("\n", "").split("*")[index]

        insert_code = insert_code.replace("${vars}", vars[index])\
            .replace("${condition}", condition)

        insert_code = insert_code.replace("${string1}", self.__gen_rand_str())\
            .replace("${string2}", self.__gen_rand_str())\
            .replace("${string3}", self.__gen_rand_str())\
            .replace("${string4}", self.__gen_rand_str())\
            .replace("${string5}", self.__gen_rand_str())\
            .replace("${number1}", str(random.randint(1, 10000)))\
            .replace("${number2}", str(random.randint(1, 10000)))\
            .replace("${number3}", str(random.randint(1, 10000)))\
            .replace("${number4}", str(random.randint(1, 10000)))\
            .replace("${number5}", str(random.randint(1, 10000)))\
            .replace("${name1}", self.__gen_rand_str())\
            .replace("${name2}", self.__gen_rand_str())\
            .replace("${name3}", self.__gen_rand_str())\
            .replace("${name4}", self.__gen_rand_str())\
            .replace("${name5}", self.__gen_rand_str())\

        return insert_code

    def __garble_java_file(self, file):
        self.__used_names = []
        self.__variables = []
        self.__functions = []
        with open(file, "r", encoding="utf-8") as fin:
            lines = fin.readlines()

        # 生成方法
        self.__generate_function("tools/garble/model/function_model.java")

        ignore = False
        # 花括号
        curly_braces = 0
        # 忽略混淆的代码块
        ignore_parts = {}
        with open(file, "w+", encoding="utf-8") as fout:
            for line in lines:
                # interface 不混淆
                if "interface" in line and "{\n" in line or ignore:
                    ignore = True
                    fout.write(line)
                    continue

                if (line.startswith("class ") or " class " in line) and "{\n" in line and "//" not in line:
                    # 插入全局变量
                    for var in self.__variables:
                        line += "%s\n" % var
                    # 插入方法
                    for fun in self.__functions:
                        line += "%s\n" % fun
                
                if curly_braces >= 1:
                    curly_braces += line.count("{")
                    curly_braces -= line.count("}")

                # 定位1个缩进开头的类方法
                if line.startswith("    ") and not line.startswith("     ") \
                    and ("){\n" in line or ") {\n" in line):
                    curly_braces = line.count("{")
                    curly_braces -= line.count("}")
                    
                for brace in ignore_parts.keys():
                    if curly_braces < brace:
                        ignore_parts[brace] = -10000

                if "new" in line and "{\n" in line:
                    ignore_parts[curly_braces] = curly_braces

                if curly_braces >= 1 and curly_braces not in ignore_parts.values():
                    if "return" in line or "throw" in line:
                        curly_braces = -10000
                    elif ";\n" in line and len(line.replace(" ","")) > 10 and "//" not in line:
                        #随机取余决定是否插入乱码
                        if random.randint(1,10) % random.randint(1,3) == 0:
                            line += self.__insert_code()

                fout.write(line)

    def java_garble(self, config):
        self.__config = config
        with open("tools/garble/model/logic_model.java", "r", encoding="utf-8") as fin:
            self.__logic_model = fin.read().replace("\n\n", "\n").replace("\n\n", "\n")

        print("ccode inserting ...")
        for main_dir in config['lib_main']:
            for root, dirs, files in os.walk("%s/%s" % (config["root"], main_dir)):
                for file in files:
                    if file.endswith(".java"):
                        self.__garble_java_file(os.path.join(root, file))
        print("done")
