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


class LayoutGarble:
    __used_names = []
    __layout_model = []
    __colors = []
    __config = []

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

    #随机取数组中一个item
    def __rand_item(self, values):
        return values[random.randint(0, len(values)-1)]

    #填充属性值
    def __set_values(self, attrs):
        gravity = ['center_vertical', 'center_horizontal',
                   'left', 'right', 'bottom', 'top']
        visibility = ['visible', 'invisible', 'gone']
        boolean = ['true', 'false']
        size = ['wrap_content', 'match_parent', '${number}dp']
        orientation = ['horizontal', 'vertical']
        scale_type = ['fitCenter', 'centerCrop', 'center',
                      'fitXY', 'centerInside', 'fitEnd', 'fitStart', 'matrix']

        return attrs.replace("${id}", self.__gen_rand_str())\
            .replace("${string}", self.__gen_rand_str())\
            .replace("${color}", self.__rand_item(self.__colors))\
            .replace("${gravity}", self.__rand_item(gravity))\
            .replace("${visibility}", self.__rand_item(visibility))\
            .replace("${boolean}", self.__rand_item(boolean))\
            .replace("${number}", "%d"%random.randint(0, 500))\
            .replace("${size}", self.__rand_item(size).replace("${number}", "%d"%random.randint(0, 500)))\
            .replace("${orientation}", self.__rand_item(orientation))\
            .replace("${scaleType}", self.__rand_item(scale_type))

    #创建随机属性
    def __create_attributes(self):
        attrs = self.__layout_model[0].replace("\n","").split("*")
        result = ""
        length = int(len(attrs) / 2)
        for i in range(0,random.randint(1, length)):
            item = attrs[random.randint(0, len(attrs)-1)]
            result += "%s\n" % self.__set_values(item)
            attrs.remove(item)
        return ("%s$"%result).replace("\n$","")

    #创建随机数量的View
    def __create_views(self,max):
        view_model = self.__layout_model[2].split("@---sep---")
        views = ""
        for i in range(0,random.randint(1,max)):
            view = self.__rand_item(view_model)
            views += self.__set_values(view).replace("${attributes}", self.__create_attributes())
        return views


    #生成一个layout文件
    def __create_layout(self, path):
        layouts = self.__layout_model[1].split("@---sep---")
        root_layout = self.__rand_item(layouts)
        root_layout = root_layout.replace(
            "${attributes}", "%s\n${attributes}" % "xmlns:android=\"http://schemas.android.com/apk/res/android\"")
        root_layout = self.__set_values(root_layout).replace("${attributes}", self.__create_attributes())
        content = ""
        for i in range(0,random.randint(1,5)):
            if random.randint(0,10) % random.randint(2,3) == 0:
                layout = self.__rand_item(layouts).replace("${attributes}", self.__create_attributes())
                layout = self.__set_values(layout).replace("${childs}",self.__create_views(4))
                content += layout
            else:
                content += self.__create_views(4)
        root_layout = root_layout.replace("${childs}",content)

        with open(path,"w+",encoding='utf-8') as fout:
            fout.write(root_layout)
                
    #混淆已存在的layout
    def __rewrite_layout(self,path):
        with open(path,"r",encoding='utf-8') as fin:
            lines = fin.readlines()
        with open(path,"w+",encoding='utf-8') as fin:
            ignores = []
            for line in lines:
                view_name = line.replace("<","").replace("/","").replace(">","").replace("\n","")
                #自定义layout忽略
                if "<" in line and "." in line and "/" not in line:
                    items = view_name.split(".")
                    if items[len(items)-1] in self.__config['ignore_layout']:
                        ignores.append(view_name)
                
                if "/" in line and view_name in ignores:
                    ignores.remove(view_name)

                if len(ignores) == 0 and "<!--" not in line:
                    if "</LinearLayout>" in line or "</RelativeLayout>" in line or "</FrameLayout>" in line or "<TextView" in line \
                        or "<ImageView" in line or "<EditText" in line or "<Button" in line or "<ImageButton" in line or "<CheckBox" in line:
                        if random.randint(0,10) % random.randint(2,3) == 0:
                            view = self.__create_views(1).replace("/>","\n%s/>"%"android:visibility=\"gone\"")
                            line = "%s\n%s"%(view,line) 
                fin.write(line)

    #开始layout混淆
    def layout_garble(self, config):
        self.__config = config
        with open("tools/garble/model/layout_model.xml", "r", encoding="utf-8") as fin:
            self.__layout_model = fin.read().split("@code\n")

        with open("tools/garble/model/colors.json", "r", encoding="utf-8") as fin:
            self.__colors = json.loads(fin.read())

        for main_dir in config['lib_main']:
            for root, dirs, files in os.walk("%s/%s" % (config["root"], "%s/res/layout"%main_dir)):
                print("layout generating ...")
                for i in range(30,100):
                    self.__create_layout(os.path.join(root, "%s.xml" % self.__gen_rand_str()))

                print("layout rewriting ...")
                for file in files:
                    self.__rewrite_layout(os.path.join(root, file))

        print("done")
