# -*- coding: UTF-8 -*-
# 添加OC垃圾代码
import os,sys
import random
import string
import re
#import md5
import time
import json
import shutil
import hashlib 
import time
import argparse


import sys

#sys.setdefaultencoding("utf-8")

script_path = os.path.split(os.path.realpath(sys.argv[0]))[0]
#垃圾代码临时存放目录
target_ios_folder = os.path.join(script_path, "./target_ios")
#备份目录
backup_ios_folder = os.path.join(script_path, "./backup_ios")

#忽略文件列表，不给这些文件添加垃圾函数
ignore_file_list = ["main.m", "GNative.mm", "MobClickCpp.mm"]
#忽略文件夹列表，不处理这些文件夹下的文件
ignore_folder_list = ["thirdparty","Support",".svn","paycenter","UMMobClick.framework","UMessage_Sdk_1.5.0a","TencentOpenApi_IOS_Bundle.bundle",
                        "TencentOpenAPI.framework","Bugly.framework","AlipaySDK.framework","AlipaySDK.bundle"]

#创建函数数量范围
create_func_min = 2
create_func_max = 10
            
#创建垃圾文件数量范围
create_file_min = 10
create_file_max = 100
            
#oc代码目录
ios_src_path = ""

#确保添加的函数不重名
funcname_set = set()

#单词列表，用以随机名称
with open(os.path.join(script_path, "./word_list.json"), "r") as fileObj:
    word_name_list = json.load(fileObj)

#获取一个随机名称
def getOneName():
    global word_name_list
    return random.choice(word_name_list)

#oc代码头文件函数声明
def getOCHeaderFuncText():
    funcName = getOneName()
    text = "\n- (void)%s" %(funcName)
    return text

#oc代码函数实现模板
def getOCFuncText(header_text):
    arg1 = getOneName()
    arg2 = getOneName()
    text = [
        header_text + "\n",
        "{\n",
        "\tint %s = 2;\n" %(arg1),
        "\tint %s = 3;\n" %(arg2),
        "\t%s += %s ;\n" %(arg2,arg1),
        "\t[[NSUserDefaults standardUserDefaults] setObject:@(%s) forKey:@\"%s\"];\n" %(arg2,arg1),
        "\tNSLog(@\"%s\");\n" %(arg1),
        "}\n"
    ]
    return "".join(text)

#oc代码以@end结尾，在其前面添加text
def appendTextToOCFile(file_path, text):
    with open(file_path, "r") as fileObj:
        old_text = fileObj.read()
        fileObj.close()
        end_mark_index = old_text.rfind("@end")
        if end_mark_index == -1:
            print("\t非法的结尾格式: " + file_path)
            return
        new_text = old_text[:end_mark_index]
        new_text = new_text + text + "\n"
        new_text = new_text + old_text[end_mark_index:]

    with open(file_path, "w") as fileObj:
        fileObj.write(new_text)

#处理单个OC文件，添加垃圾函数。确保其对应头文件存在于相同目录
def dealWithOCFile(filename, file_path):
    global target_ios_folder,create_func_min,create_func_max,funcname_set
    funcname_set.clear()
    end_index = file_path.rfind(".")
    pre_name = file_path[:end_index]
    header_path = pre_name + ".h"
    if not os.path.exists(header_path):
        print ("\t相应头文件不存在：" + file_path)
        return

    new_func_num = random.randint(create_func_min, create_func_max)
    print ("\t给%s添加%d个方法" %(filename, new_func_num))
    for i in range(new_func_num):
        header_text = getOCHeaderFuncText()
        # print "add %s to %s" %(header_text, header_path.replace(target_ios_folder, ""))
        appendTextToOCFile(header_path, header_text + ";\n")
        funcText = getOCFuncText(header_text)
        appendTextToOCFile(file_path, funcText)

#扫描parent_folder，添加垃圾函数，处理了忽略列表
def addOCFunctions(parent_folder):
    global ignore_file_list
    for parent, folders, files in os.walk(parent_folder):
        need_ignore = None
        for ignore_folder in ignore_folder_list:
            if parent.find("/" + ignore_folder) != -1:
                need_ignore = ignore_folder
                break
        if need_ignore:
            print ("\t忽略文件夹" + ignore_folder)
            continue

        for file in files:
            if file.endswith(".m") or file.endswith(".mm"):
                if file in ignore_file_list:
                    continue
                dealWithOCFile(file, os.path.join(parent, file))

#新创建的垃圾文件header模板
def getOCHeaderFileText(class_name):
    global funcname_set
    new_func_name = getOneName()
    while new_func_name in funcname_set:
        new_func_name = getOneName()
    funcname_set.add(new_func_name)

    text = [
        "#import <Foundation/Foundation.h>\n\n",
        "@interface %s : NSObject {\n" %(class_name),
        "\tint %s;\n" %(new_func_name),
        "\tfloat %s;\n" %(getOneName()),
        "}\n\n@end"
    ]
    return "".join(text)

#新创建的垃圾文件mm模板
def getOCMMFileText(class_name):
    text = [
        '#import "%s.h"\n\n' %(class_name),
        "@implementation %s\n" %(class_name),
        "\n\n@end"
    ]
    return "".join(text)

#添加垃圾文件到parent_folder/trash/
def addOCFile(parent_folder):
    global create_file_min, create_file_max
    file_list = []
    target_folder = os.path.join(parent_folder, "trash")
    if os.path.exists(target_folder):
        shutil.rmtree(target_folder)
    os.mkdir(target_folder)
    file_num = random.randint(create_file_min, create_file_max)
    for i in range(file_num):
        file_name = getOneName()
        file_list.append("#import \"" + file_name + ".h\"")
        print ("\t创建OC文件 trash/" + file_name)
        header_text = getOCHeaderFileText(file_name)
        full_path = os.path.join(target_folder, file_name + ".h")
        with open(full_path, "w") as fileObj:
            fileObj.write(header_text)
            fileObj.close()

        mm_text = getOCMMFileText(file_name)
        full_path = os.path.join(target_folder, file_name + ".mm")
        with open(full_path, "w") as fileObj:
            fileObj.write(mm_text)
    all_header_text = "\n".join(file_list)

    with open(os.path.join(parent_folder, "Trash.h"), "w") as fileObj:
        fileObj.write(all_header_text)
        fileObj.close()

#解析参数       
def parse_args():
    parser = argparse.ArgumentParser(description='oc垃圾代码生成工具.')
    parser.add_argument('--oc_folder', dest='oc_folder', type=str, required=True, help='OC代码所在目录')
    parser.add_argument('--replace', dest='replace_ios', required=False, help='直接替换oc源代码', action="store_true")

    args = parser.parse_args()
    return args

def main():
    app_args = parse_args()
    global ios_src_path, backup_ios_folder, target_ios_folder
    ios_src_path = app_args.oc_folder
    if not os.path.exists(ios_src_path):
        print ("oc_folder path not exist.")
        exit(0)

    print ("拷贝OC代码到target_ios")
    if os.path.exists(target_ios_folder):
        shutil.rmtree(target_ios_folder)
    shutil.copytree(ios_src_path, target_ios_folder)

    print ("开始创建oc文件到trash目录")
    addOCFile(target_ios_folder)
    print ("\n开始添加oc方法")
    addOCFunctions(target_ios_folder)

    if app_args.replace_ios:
        print ("\n用target_ios替换原目录")
        print ("\t备份OC代码到" + os.path.abspath(backup_ios_folder))
        if os.path.exists(backup_ios_folder):
            shutil.rmtree(backup_ios_folder)
        shutil.copytree(ios_src_path, backup_ios_folder)

        print ("\t开始替换")
        trash_folder = os.path.join(ios_src_path, "trash")
        if os.path.exists(trash_folder):
            shutil.rmtree(trash_folder)
        os.mkdir(trash_folder)

        for parent, folders, files in os.walk(target_ios_folder):
            for file in files:
                if file.endswith(".h") or file.endswith(".m") or file.endswith(".mm"):
                    full_path = os.path.join(parent, file)
                    target_path = full_path.replace(target_ios_folder, ios_src_path)
                    shutil.copy(full_path, target_path)
        print ("替换成功\n需要在Xcode上重新添加trash文件下的oc文件")
    else:
        print ("垃圾代码生成完毕，垃圾代码目录：" + os.path.abspath(target_ios_folder))

    print ("\nfinished")

if __name__ == "__main__":
    main()
