import xml.etree.ElementTree as ET
import os.path

namespaces = {'android' : 'http://schemas.android.com/apk/res/android'}
encoding = 'UTF-8'

def getPackageName(manifest):
    '''
    获取包名
    '''
    tree = ET.parse(manifest)
    root = tree.getroot()
    return root.attrib['package']

def changePackageName(manifest, packageName):
    '''
    更改包名
    '''
    for key in namespaces:
        ET.register_namespace(key, namespaces[key])

    tree = ET.parse(manifest)
    root = tree.getroot()
    root.attrib['package'] = packageName
    tree.write(manifest, encoding)

def removeLauncherActivity(manifest):
    '''
    删除启动的activity
    '''
    for key in namespaces:
        ET.register_namespace(key, namespaces[key])

    tree = ET.parse(manifest)
    root = tree.getroot()
    
    attrName = getNamespacesFormat('android:name', namespaces)
    for node in root.findall('application/activity'):
        if len(node.getchildren()) <= 0:
            continue

        for sub in node.getchildren():
            if sub.tag != 'intent-filter':
                continue

            for sub2 in sub.getchildren():
                if not (sub2.tag == 'category' and sub2.attrib[attrName] == 'android.intent.category.LAUNCHER'):
                    continue

                node.remove(sub)
                tree.write(manifest, encoding)
                return node.attrib[attrName]
    return 0

def getScreenOrientation(manifest):
    '''
    获取启动activity的方向
    '''
    for key in namespaces:
        ET.register_namespace(key, namespaces[key])

    tree = ET.parse(manifest)
    root = tree.getroot()
    
    attrName = getNamespacesFormat('android:name', namespaces)
    attrOrientation = getNamespacesFormat('android:screenOrientation', namespaces)
    for node in root.findall('application/activity'):
        if len(node.getchildren()) <= 0:
            continue

        for sub in node.getchildren():
            if sub.tag != 'intent-filter':
                continue

            for sub2 in sub.getchildren():
                if not (sub2.tag == 'category' and sub2.attrib[attrName] == 'android.intent.category.LAUNCHER'):
                    continue

                return node.attrib[attrOrientation]
    return 0

def addLauncherActivity(manifest, screenOrientation, activity):
    '''
    添加启动的activity
    '''
    for key in namespaces:
        ET.register_namespace(key, namespaces[key])

    tree = ET.parse(manifest)
    root = tree.getroot()

    # activity
    '''<activity android:name=".LauncherActivity"
            android:theme="@style/LauncherStyle">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>'''

    activity = ET.Element('activity', {'android:name' : activity,
    'android:theme' : '@android:style/Theme.Holo.Light.NoActionBar.Fullscreen',
    'android:launchMode' : 'singleTop',
    'android:configChanges' : 'orientation|screenSize|keyboardHidden',
    'android:screenOrientation' : screenOrientation})
    intent = ET.Element('intent-filter')
    action = ET.Element('action', {'android:name' : 'android.intent.action.MAIN'})
    category = ET.Element('category', {'android:name' : 'android.intent.category.LAUNCHER'})
    intent.append(action)
    intent.append(category)
    activity.append(intent)
    
    application = root.find('application')
    application.insert(0, activity)

    tree.write(manifest, encoding)

def changeAppName(manifest, stringRes):
    '''
    更改app名
    '''
    # 移除主activity的label
    removeLauncherAttr(manifest, 'label')
    return changeApplicationAttr(manifest, 'label', stringRes)

def getLauncherActivity(root):
    '''
    获取启动的activity
    '''
    attrName = getNamespacesFormat('android:name', namespaces)

    for node in root.findall('application/activity'):
        if len(node.getchildren()) <= 0:
            continue

        for sub in node.getchildren():
            if sub.tag != 'intent-filter':
                continue

            for sub2 in sub.getchildren():
                if sub2.tag == 'category' and sub2.attrib[attrName] == 'android.intent.category.LAUNCHER':
                    return node

    return None

def getLauncherActivityName(manifest):
    '''
    获取启动的activity
    '''
    for key in namespaces:
        ET.register_namespace(key, namespaces[key])

    tree = ET.parse(manifest)
    root = tree.getroot()

    launcherActivity = getLauncherActivity(root)
    attrName = getNamespacesFormat('android:name', namespaces)
    activityName = launcherActivity.attrib[attrName]
    return activityName

def addMoreIcon(manifest, icon, switchIcon):
    '''
    添加多图标
    '''
    for key in namespaces:
        ET.register_namespace(key, namespaces[key])

    tree = ET.parse(manifest)
    root = tree.getroot()

    launcherActivity = getLauncherActivity(root)
    if launcherActivity is None:
        return 1

    attrName = getNamespacesFormat('android:name', namespaces)
    activityName = launcherActivity.attrib[attrName]

    activityAlias = ET.Element('activity-alias', {'android:name' : 'com.jmhy.sdk.icon.normal',
    'android:enabled' : 'false',
    'android:icon' : icon,
    'android:targetActivity' : activityName})

    activityAlias2 = ET.Element('activity-alias', {'android:name' : 'com.jmhy.sdk.icon.switch',
    'android:enabled' : 'false',
    'android:icon' : switchIcon,
    'android:targetActivity' : activityName})

    for item in launcherActivity.getchildren():
        activityAlias.append(item)
        activityAlias2.append(item)

    application = root.find('application')
    application.append(activityAlias)
    application.append(activityAlias2)
    tree.write(manifest, encoding)
    return 0

def removeLauncherAttr(manifest, attrType):
    '''
    移除启动的activity的label
    '''
    for key in namespaces:
        ET.register_namespace(key, namespaces[key])

    tree = ET.parse(manifest)
    root = tree.getroot()

    launcherActivity = getLauncherActivity(root)
    if launcherActivity is None:
        return 1

    attrName = getNamespacesFormat('android:%s' % attrType, namespaces)
    if attrName in launcherActivity.attrib:
        del launcherActivity.attrib[attrName]
        tree.write(manifest, encoding)
    
    return 0

def changeLauncherAttr(manifest, attrType, attrValue):
    '''
    更改启动的activity的属性
    '''
    for key in namespaces:
        ET.register_namespace(key, namespaces[key])

    tree = ET.parse(manifest)
    root = tree.getroot()

    launcherActivity = getLauncherActivity(root)
    if launcherActivity is None:
        return 1

    attrName = getNamespacesFormat('android:%s' % attrType, namespaces)
    if attrName in launcherActivity.attrib:
        launcherActivity.attrib[attrName] = attrValue
        tree.write(manifest, encoding)

    return 0

def changeAppIcon(manifest, iconRes):
    '''
    更改app icon
    '''
    # 移除主activity的图标
    removeLauncherAttr(manifest, 'icon')
    return changeApplicationAttr(manifest, 'icon', iconRes)

def changeApplicationAttr(manifest, attrType, attrValue):
    '''
    更改Application的某个属性
    '''
    for key in namespaces:
        ET.register_namespace(key, namespaces[key])

    tree = ET.parse(manifest)
    root = tree.getroot()
    application = root.find('application')
    # Namespaces
    attrName = getNamespacesFormat('android:%s' % attrType, namespaces)
    application.attrib[attrName] = attrValue
    tree.write(manifest, encoding)
    return 0

def getApplicationAttr(manifest, attrType):
    '''
    获取Application的某个属性
    '''
    for key in namespaces:
        ET.register_namespace(key, namespaces[key])

    tree = ET.parse(manifest)
    root = tree.getroot()
    application = root.find('application')
    attrName = getNamespacesFormat('android:%s' % attrType, namespaces)
    if attrName in application.attrib:
        return application.attrib[attrName]
            
    return None

def getNamespacesFormat(text, namespaces):
    '''
    格式化带namespaces的属性
    '''
    for key in namespaces:
        text = text.replace('%s:' % key, '{%s}' % namespaces[key])
    return text

def mergeManifestRes(appManifest, libManifest):
    '''
    合并主文件
    '''
    if not os.path.exists(libManifest):
        print('file "%s" not exists' % libManifest)
        return 1

    if not os.path.exists(appManifest):
        print('file "%s" not exists' % appManifest)
        return 1

    libInfo = getLibManifestInfo(libManifest)
    appPermission = getManifestPermission(appManifest)
    diffPermission = mergeManifestPermission(appPermission, libInfo['permissionList'])

    mergeManifest(appManifest, diffPermission, libInfo['activityList'])
    return 0

def getLibManifestInfo(libManifest):
    '''
    获取框架的主文件参数
    '''
    for key in namespaces:
        ET.register_namespace(key, namespaces[key])

    tree = ET.parse(libManifest)
    root = tree.getroot()

    permissionList = root.findall('permissions/*')
    activityList = root.findall('application/*')

    info = {'permissionList' : permissionList, 'activityList' : activityList}
    return info

def getManifestPermission(appManifest):
    '''
    获取主文件参数
    '''
    for key in namespaces:
        ET.register_namespace(key, namespaces[key])

    tree = ET.parse(appManifest)
    root = tree.getroot()

    return root.findall('uses-permission')

def mergeManifestPermission(appPermission, libPermission):
    '''
    合并主文件参数
    '''
    newPermissionList = []

    for permission in libPermission:
        if contain(appPermission, permission):
            continue
        newPermissionList.append(permission)

    return newPermissionList

def contain(nodeList, item):
    '''
    是否存在
    '''
    attrName = getNamespacesFormat('android:name', namespaces)
    for node in nodeList:
        if node.attrib[attrName] == item.attrib[attrName]:
            return True
    return False

def mergeManifest(appManifest, permissionList, activityList):
    '''
    将权限和activity加入到主文件
    '''
    for key in namespaces:
        ET.register_namespace(key, namespaces[key])

    tree = ET.parse(appManifest)
    root = tree.getroot()

    # 权限
    for item in permissionList:
        root.insert(0, item)

    # activity
    application = root.find('application')
    # 删除不支持属性
    attrName = getNamespacesFormat('android:roundIcon', namespaces)
    if attrName in application.attrib:
        del application.attrib[attrName]
    # 删除不支持属性
    attrName = getNamespacesFormat('android:testOnly', namespaces)
    if attrName in application.attrib:
        del application.attrib[attrName]
    # 删除不支持属性
    attrName = getNamespacesFormat('android:debuggable', namespaces)
    if attrName in application.attrib:
        del application.attrib[attrName]

    # 覆盖
    # 移除相同的标签
    attrName = getNamespacesFormat('android:name', namespaces)
    for item in application.getchildren():
        if contain(activityList, item):
            application.remove(item)

    for item in activityList:
        application.insert(1, item)

    tree.write(appManifest, encoding)

def addMetaData(manifest, meta):
    '''
    添加meta-data
    '''
    for key in namespaces:
        ET.register_namespace(key, namespaces[key])

    tree = ET.parse(manifest)
    root = tree.getroot()

    application = root.find('application')
    for key in meta:
        val = meta[key]
        '''if type(val) == str and val.isdigit():
            element = ET.Element('meta-data', {'android:name' : key, 'android:value' : '\\ ' + val})
        else:
            element = ET.Element('meta-data', {'android:name' : key, 'android:value' : val})'''
        element = ET.Element('meta-data', {'android:name' : key, 'android:value' : val})
        application.append(element)

    tree.write(manifest, encoding)

def readAllRes(resFile, resList):
    '''
    读取资源文件
    '''
    tree = ET.parse(resFile)
    root = tree.getroot()

    resList += root.getchildren()
    return resList

def removeIdFromPublic(pubFile, removeList):
    '''
    删除重复的资源
    '''
    tree = ET.parse(pubFile)
    root = tree.getroot()

    same = False
    for node in root.getchildren():
        if containPublic(node, removeList):
            print('delete public node : type is %s, name is %s' % (node.attrib['type'], node.attrib['name']))
            root.remove(node)
            same = True
    if same:
        tree.write(pubFile, encoding)

def removeSameRes2(resFile, resList, removeList):
    '''
    删除重复的资源
    '''
    tree = ET.parse(resFile)
    root = tree.getroot()

    same = False
    for node in root.getchildren():
        if containRes(node, resList):
            print('delete node : tag is %s, name is %s' % (node.tag, node.attrib['name']))
            root.remove(node)
            removeList.append(node)
            same = True

    if same:
        tree.write(resFile, encoding)
    return removeList

def removeSameRes(resFile, resList):
    '''
    删除重复的资源
    '''
    tree = ET.parse(resFile)
    root = tree.getroot()

    same = False
    for node in root.getchildren():
        if containRes(node, resList):
            print('delete node : tag is %s, name is %s' % (node.tag, node.attrib['name']))
            root.remove(node)
            same = True

    if same:
        tree.write(resFile, encoding)

def containRes(node, resList):
    '''
    是否重复
    '''
    for item in resList:
         if item.tag == node.tag and item.attrib['name'] == node.attrib['name']:
            return True

    return False

def containPublic(node, removeList):
    '''
    是否重复
    '''
    for item in removeList:
         if item.tag == node.attrib['type'] and item.attrib['name'] == node.attrib['name']:
            return True

    return False


def removeRootAttr(manifest, attrType):
    for key in namespaces:
        ET.register_namespace(key, namespaces[key])

    tree = ET.parse(manifest)
    root = tree.getroot()

    attrName = getNamespacesFormat('android:%s' % attrType, namespaces)
    if attrName in root.attrib:
        del root.attrib[attrName]
        tree.write(manifest, encoding)
    
    return 0