# -*- coding: utf-8 -*-
# Author: kelvinBen
# Github: https://github.com/kelvinBen/AppInfoScanner


import os
import re
import config
import threading
from queue import Queue
import libs.core as cores
from libs.core.parses import ParsesThreads

class AndroidTask(object):

    def __init__(self,path,no_resource,package):
        self.path = path
        self.no_resource = no_resource
        self.package = package

        self.file_queue = Queue()
        self.shell_flag=False
        self.packagename=""
        self.comp_list=[]
        
    def start(self):
        # 检查java环境是否存在
        if os.system("java -version") !=0 :
            raise Exception("Please install the Java environment!")
        
        input_file_path = self.path
        
        if os.path.isdir(input_file_path):
            self.__decode_dir__(input_file_path)
        else:
           if self.__decode_file__(input_file_path) == "error":
               raise Exception("Retrieval of this file type is not supported. Select APK file or DEX file.")
        
        return {"comp_list":self.comp_list,"shell_flag":self.shell_flag,"file_queue":self.file_queue,"packagename":self.packagename}

    def __decode_file__(self,file_path):
        apktool_path = str(cores.apktool_path)
        output_path = str(cores.output_path)
        backsmali_path = str(cores.backsmali_path)
        suffix_name = file_path.split(".")[-1]
        if suffix_name == "apk":
            self.__decode_apk__(file_path,apktool_path,output_path)
        elif suffix_name == "dex":
            self.__decode_dex__(file_path,backsmali_path,output_path)
        else:
            return "error"
    
    def __decode_dir__(self,root_dir):
        dir_or_files = os.listdir(root_dir)
        for dir_or_file in dir_or_files:
            dir_or_file_path = os.path.join(root_dir,dir_or_file) 
            if os.path.isdir(dir_or_file_path):
                self.__decode_dir__(dir_or_file_path)
            else: 
                if self.__decode_file__(dir_or_file_path) == "error":
                    continue

    # 分解apk
    def __decode_apk__(self,file_path,apktool_path,output_path):
        cmd_str = ("java -jar %s d -f %s -o %s --only-main-classe") % (apktool_path,str(file_path),output_path)
        if os.system(cmd_str) == 0:
            self.__shell_test__(output_path)
            self.__scanner_file_by_apktool__(output_path)
        else:
            print("Decompilation failed, please submit error information at https://github.com/kelvinBen/AppInfoScanner/issues")
            raise Exception(file_path + ", Decompilation failed.")
                

    # 分解dex
    def __decode_dex__(self,file_path,backsmali_path,output_path):
        cmd_str = ("java -jar %s d %s") % (backsmali_path,str(file_path))
        if os.system(cmd_str) == 0:
            self.__get_scanner_file__(output_path)
        else:
            print("Decompilation failed, please submit error information at https://github.com/kelvinBen/AppInfoScanner/issues")
            raise Exception(file_path + ", Decompilation failed.")
    

    # 初始化检测文件信息
    def __scanner_file_by_apktool__(self,output_path):
        if self.no_resource:
            scanner_dir_lists =  ["smali"]    
            scanner_file_suffixs = ["smali"]
        else:
            scanner_dir_lists =  ["smali","assets"]    
            scanner_file_suffixs = ["smali","js","xml"]

        for scanner_dir_list in scanner_dir_lists:
            scanner_dir =  os.path.join(output_path,scanner_dir_list)
            if os.path.exists(scanner_dir):
                self.__get_scanner_file__(scanner_dir,scanner_file_suffixs)

    def __get_scanner_file__(self,scanner_dir,scanner_file_suffixs=["smali"]):
        dir_or_files = os.listdir(scanner_dir)
        for dir_or_file in dir_or_files:
            dir_file_path = os.path.join(scanner_dir,dir_or_file)
            
            if os.path.isdir(dir_file_path):
                self.__get_scanner_file__(dir_file_path,scanner_file_suffixs)
            else:
                if ("." not in dir_or_file) or (len(dir_or_file.split(".")) < 1) or (dir_or_file.split(".")[-1] not in scanner_file_suffixs):
                    continue
                self.file_queue.put(dir_file_path)
                for component in config.filter_components:
                    comp = component.replace(".","/")
                    if(comp in dir_file_path):
                        if(component not in self.comp_list):
                            self.comp_list.append(component)

    def __shell_test__(self,output):
        am_path = os.path.join(output,"AndroidManifest.xml")
        
        with open(am_path,"r") as f:
            am_str = f.read()

            am_package=  re.compile(r'<manifest.*package=\"(.*?)\".*')
            apackage = am_package.findall(am_str)
            if len(apackage) >=1:
                self.packagename = apackage[0]

            am_name = re.compile(r'<application.*android:name=\"(.*?)\".*>') 
            aname = am_name.findall(am_str)
            if aname and len(aname)>=1:
                if aname[0] in config.shell_list:
                    self.shell_flag = True