# -*-coding:utf-8-*-
import glob
import os
import string
import random

class PackageGarble:
    used_names = []
    pkg_mapping = {}

    # 随机串(全小写加下划线，避免和activity混淆重复)
    def __gen_rand_str(self):
        result = ""
        while len(result) == 0 or result in self.used_names:
            random_str1 = ''.join(random.sample(
                "abcdefghijklmnopqrstuvwxyz", random.randint(3, 6)))
            random_str2 = ''.join(random.sample(
                "abcdefghijklmnopqrstuvwxyz", random.randint(3, 6)))
            result = "%s_%s"%(random_str1,random_str2)
        self.used_names.append(result)
        return result

    # 替换文件内容
    def __process_file_content(self, path, file_name):
        # print("processing content: %s..."%path)
        with open(path, "rt") as fin:
            file_content = fin.read()
            # 必须先替换长路径
            keys = sorted(self.pkg_mapping.keys(),
                      key=lambda i: len(i.split(".")), reverse=True)
            for pkg in keys:
                file_content = file_content.replace(pkg, self.pkg_mapping[pkg])

            ext = os.path.splitext(file_name)[1]
            with open(path, "wt") as fout:
                fout.write(file_content)
        return

    # 搜集混淆字典
    def __find_pkgs(self, path):
        for root, dirs, files in os.walk(path):
            if len(dirs) == 0:
                mp_path = root.split("main/java/")[1].replace("/", ".")
                if mp_path not in self.pkg_mapping.keys():
                    random_str = ""
                    # 按长度排序
                    pkg_path = mp_path

                    keys = sorted(self.pkg_mapping.keys(),
                                  key=lambda i: len(i), reverse=True)
                    for key in keys:
                        if pkg_path.startswith(key):
                            random_str += self.pkg_mapping[key]
                            pkg_path = pkg_path.replace(key, "")

                    # 没混淆过的包名补全混淆
                    for pkgname in pkg_path.split("."):
                        if len(pkgname) > 0:
                            if len(random_str) > 0:
                                random_str += "."
                            random_str += self.__gen_rand_str()

                    size = len(mp_path.split("."))
                    while size > 0:
                        if mp_path not in self.pkg_mapping.keys():
                            self.pkg_mapping[mp_path] = random_str
                        #添加一个结尾标识，避免有路径中间有重复的包名被替换
                        mp_path += "**"
                        mp_path = mp_path.replace(
                            ".%s" % mp_path.split(".")[size-1], "")
                        random_str = random_str.replace(
                            ".%s" % random_str.split(".")[size-1], "")
                        size -= 1

    #重命名所有包路径
    def __rename_pkg(self,path):
        mapping = {}
        for root, dirs, files in os.walk(path):
            if "main/java" in root:
                root += "/"
                mp_path = root.split("main/java/")[1].replace("/", ".")
                for dir in dirs:
                    pkg_path = "%s%s"%(mp_path,dir)
                    for (key,value) in self.pkg_mapping.items():
                        if key.startswith(pkg_path):
                            index = len(pkg_path.split(".")) - 1
                            dir_name = value.split(".")[index]
                            old_name = os.path.join(os.path.join(os.getcwd(), root), dir)
                            new_name = os.path.join(os.path.join(os.getcwd(), root),dir_name )
                            mapping[old_name] = new_name
                            print ("rename %s -> %s"%(dir,dir_name))
                            break

        keys = sorted(mapping.keys(),
                      key=lambda i: len(i.split("/")), reverse=True)    
        for key in keys:
            os.rename(key, mapping[key])

    def __process_files(self, path):
        if os.path.isfile(path):
            dirs = path.split("/")
            file_name = dirs[len(dirs)-1]
            self.__process_file_content(path, file_name)
        else:   
            for root, dirs, files in os.walk(path):
                directory = os.path.join(os.getcwd(), root)
                for file in files:
                    if file.endswith(".java") or file.endswith(".kt") or file.endswith(".xml"):
                        self.__process_file_content(
                            os.path.join(directory, file), file)

    #包路径混淆
    def pkg_garble(self, config):
        print("find pkgs...")
        #生成混淆字典
        for main_dir in config['lib_main']:
            self.__find_pkgs("%s/%s/java" % (config['root'], main_dir))
        
        # keys = sorted(self.pkg_mapping.keys(),
        #               key=lambda i: len(i.split(".")), reverse=True)
        # for key in keys:
        #     print(key+" -> " + self.pkg_mapping[key])

        #重命名路径
        for main_dir in config['lib_main']:
            self.__rename_pkg("%s/%s/java" % (config['root'], main_dir))

        
        for (key,value) in self.pkg_mapping.items():
            path_level = len(key.split("."))
            #com. cn. 开头的二级包名不混淆，避免干扰到三方SDK
            if path_level <= 2 and (key.startswith("com.") or key.startswith("cn.")):
                self.pkg_mapping[key] = key
            #单个一级包名，干扰太多，不混淆
            elif path_level <= 1:
                self.pkg_mapping[key] = key

        #全局替换
        for proguard in config['proguard']:
            self.__process_files("%s/%s" % (config['root'],proguard))

        for main_dir in config['lib_main']:
            self.__process_files("%s/%s" % (config['root'], main_dir))


        print("done")

if __name__ == "__main__":
    #project 根目录
    PackageGarble().pkg_garble({})