# -*- coding: UTF-8 -*-
import ksbase
import sys, os, time, json, subprocess, re, zipfile, tempfile, urllib2, threading, shutil
import webbrowser, requests

############################################################
#Init code
############################################################
#Current encoding
g_encoding = sys.getfilesystemencoding()

#android version
g_androidsdk = {
	"22": "Android 5.1+",
	"21": "Android 5.0+",
	"20": "Android 4.4W+",
	"19": "Android 4.4+",
	"18": "Android 4.3+",
	"17": "Android 4.2+",
	"16": "Android 4.1+",
	"15": "Android 4.0.3+",
	"14": "Android 4.0+",
	"13": "Android 3.2+",
	"12": "Android 3.1+",
	"11": "Android 3.0+",
	"10": "Android 2.3.4+",
	"9": "Android 2.3.2+",
	"8": "Android 2.2+",
	"7": "Android 2.1+",
	"6": "Android 2.0.1+",
	"5": "Android 2.0+",
	"4": "Android 1.6+",
	"3": "Android 1.5+",
	"2": "Android 1.1+",
	"1": "Android 1.0+"
}

#Load Package.json
g_pkgjson = json.load(open(ksbase.currentpath()+os.sep+'package.json', 'r'))

#Temprory files, deleted after exit
g_tmpfiles = []

#Information when installing
g_info = ""

ksbase.measuretime("Python start...")

############################################################
#Base function
############################################################
def OpenAPK(filename):
	localfile = filename.decode('utf-8').encode(g_encoding)
	aapt= ksbase.currentpath() + os.sep + 'tools' + os.sep + 'aapt'
	if not os.path.isfile(localfile):
		return {'err':'Can not find '+filename}
	try:
		out = subprocess.check_output([aapt, "dump", "badging", localfile], shell=True)
	except:
		return {'err':filename+' is not a valid APK file'}
	lists = out.split('\r\n')
	props = {}
	obj   = {}
	for item in lists:
		kv = item.split(':')
		if len(kv) == 1:
			props[kv[0]] = ''
			continue
		key = kv[0]
		if props.has_key(key) and key == "uses-permission":
			old = props[key]
			props[key] = []
			props[key].append(old)
			props[key].append(key)
			continue
		props[key] = kv[1]
	#Get the name of apk
	key1 = 'application-label-'+ksbase.languagecode()+'_'+ksbase.countrycode()
	key2 = 'application-label-'+ksbase.languagecode()
	key3 = 'application-label-en'
	key4 = 'application-label'
	if props.has_key(key1):
		obj['name'] = props[key1][1:-1]
	elif props.has_key(key2):
		obj['name'] = props[key2][1:-1]
	elif props.has_key(key3):
		obj['name'] = props[key3][1:-1]
	elif props.has_key(key4):
		obj['name'] = props[key4][1:-1]
	else:
		return {'err':'Can not get application name'}
	#Get sdk version
	if not props.has_key('sdkVersion'):
		return {'err':'Can not get application version'}
	ver = props['sdkVersion'][1:-1]
	print props['sdkVersion']
	obj['android_sdk'] = g_androidsdk[ver]
	#Get package name
	if not props.has_key('package'):
		return {'err':'Can not get package information'}
	pattern = re.compile("name='(.+?)'")
	pkg = pattern.search(props['package'])
	obj['pkgname'] = pkg.group(1)
	#Get apk version
	pattern = re.compile("versionName='(.+?)'")
	pkg = pattern.search(props['package'])
	obj['version'] = pkg.group(1)
	#Get apk icon
	if not props.has_key('application'):
		return {'err':'Can not get application information'}
	pattern = re.compile("icon='(.+?)'")
	pkg = pattern.search(props['application'])
	#Extract apk icon file
	extname = os.path.splitext(pkg.group(1))
	tmpfile = tempfile.mktemp(suffix=extname[1])
	zfobj	= zipfile.ZipFile(localfile)
	outfile = open(tmpfile, 'wb')
	outfile.write(zfobj.read(pkg.group(1)))
	outfile.close()
	g_tmpfiles.append(tmpfile)
	obj['icon'] = tmpfile
	obj['err']  = 'ok'
	obj['ext']  = 'apk'
	obj['size'] = os.path.getsize(localfile)
	return obj

############################################################
#Use ADB to install APK
############################################################
def InstallAPK(filename, location):
	global g_info
	localfile = filename.decode('utf-8').encode(g_encoding)
	#Detect ADB connection
	adb = ksbase.currentpath() + os.sep + 'tools' + os.sep + 'adb'
	if not os.path.isfile(localfile):
		return False,'Can not find '+filename
	# Do we need to check APK sign?
	info = 'Pure APK Install has checked your APK signture and find it is not a offical version. It\'s unsafe.\
			If you want to continue, please uncheck the option "Scan APK before installtion" in the setting panel'
	inifile = getinipath()
	jsonobj = {'scanapk':1,'autoupdate':1}
	if os.path.exists(inifile):
		try:
			jsonobj = json.loads(open(inifile, 'r').read())
		except:
			pass
	if jsonobj['scanapk'] == 1:
		apkinfo		= OpenAPK(filename)
		if apkinfo['err'] != 'ok':
			return False, info
		# Unzip the cert file
		myzip		= zipfile.ZipFile(localfile)
		myfilelist	= myzip.namelist()
		pattern 	= re.compile("META-INF/(\w+?)\.(RSA|DSA|EC)", re.I)
		certfile	= None
		for zipfilename in myfilelist:
			pkg = pattern.match(zipfilename)
			if pkg != None:
				certfile = pkg.group(0)
				break
		if certfile == None:
			return False, info
		try:
			verify = requests.post('http://download.apkpure.com/verify/cert/'+apkinfo['pkgname'], files={'file': myzip.open(certfile)})
			verify = json.loads(verify.text)
		except:
			return False,"Can not connect server to verify APK. You can uncheck the option \"Scan APK before installtion\" in the setting panel to continue."
		if verify['is_official'] != True:
			return False, info

	# Connect to android
	info = 'Your android device can not be connected, please check you\'ve installed\
			USB driver and open the USB debugging mode. <a href="javascript:$$.callpy(\'do_openurl\',\
			\'http://www.apkpure.com/usb-debugging.htm\')">See more</a>'
	try:
		out = subprocess.check_output([adb, "devices"], shell=True)
	except:
		return False,info
	lists = out.split('\r\n')
	if len(lists) < 2:
		return False,info
	if lists[1].find('device') == -1:
		return False,info
	#Set APK install location
	try:
		subprocess.check_output([adb, "shell", "pm", "set-install-location", str(location)], shell=True)
	except:
		return False,"Can not set the location that APK will be installed to."
	#Start to install
	g_info	= "Installing APK, please check your Android device, maybe it needs your confirm on your device."
	try:
		out = subprocess.check_output([adb, "install", "-r", localfile], shell=True)
	except:
		return False,"There is a error while installing APK, please check the connection bewteen PC and Android."
	g_info  = ""
	return True,'The APK have been installed to your mobile.'

############################################################
#Handle XAPK file
############################################################
def CheckXAPK(filename, extracticon):
	localfile = filename.decode('utf-8').encode(g_encoding)
	if not os.path.isfile(localfile):
		return {'err':'Can not find '+filename}
	myzip		= zipfile.ZipFile(localfile)
	myfilelist	= myzip.namelist()
	if 'icon.png' in myfilelist and 'manifest.json' in myfilelist:
		info 	= json.loads(myzip.read('manifest.json'))
		if info['package_name']+'.apk' in myfilelist:
			obj = {}
			if extracticon:
				#Extract icon.png
				tmpfile = tempfile.mktemp(suffix=".png")
				f_handle= open(tmpfile, "wb") 
				f_handle.write(myzip.read('icon.png'))
				f_handle.close()
				g_tmpfiles.append(tmpfile)
				obj['icon']			= tmpfile
		
			#Get apk name
			key1 = ksbase.languagecode()+'_'+ksbase.countrycode()
			key2 = ksbase.languagecode()
			key3 = 'name'
			if info.has_key(key1):
				obj['name'] = info[key1]
			elif info.has_key(key2):
				obj['name'] = info[key2]
			elif info.has_key(key3):
				obj['name'] = info[key3]
			else:
				return {'err':'Can not get application name'}
			obj['version']		= info['version_name']
			obj['android_sdk']	= g_androidsdk[info['min_sdk_version']]
			obj['err']  		= 'ok'
			obj['ext']			= 'xapk'
			obj['size']			= os.path.getsize(localfile)
			myzip.close()
			return obj
	myzip.close()
	return {'err':filename+' is not a valid xAPK file'}

def OpenXAPK(filename):
	return CheckXAPK(filename, True)

def InstallXAPK(filename, location):
	global g_info
	obj = CheckXAPK(filename, False)
	if obj['err'] != 'ok':
		return False,obj['err']
	#Extract XAPK to temprory directory
	localfile	= filename.decode('utf-8').encode(g_encoding)
	tmpdir		= tempfile.mkdtemp()+os.sep
	myzip		= zipfile.ZipFile(localfile)
	info 		= json.loads(myzip.read('manifest.json'))
	myfilelist	= myzip.namelist()
	for name in myfilelist: 
		myzip.extract(name, tmpdir)  
	myzip.close()
	#Install APK
	print "Install APK: "+info['package_name']
	ok, msg = InstallAPK(tmpdir.decode(g_encoding).encode('utf-8')+info['package_name']+'.apk', location)
	if ok == False:
		shutil.rmtree(tmpdir)
		return False,msg
	#Get base path for obb
	adb = ksbase.currentpath() + os.sep + 'tools' + os.sep + 'adb'
	errinfo = "There is a error while installing APK, please check the connection bewteen PC and Android."
	try:
		sdcardpath = subprocess.check_output([adb, "shell", "echo", "$EXTERNAL_STORAGE"], shell=True)
		sdcardpath = sdcardpath.strip()
	except:
		return False, errinfo + " ERR: Can not get $EXTERNAL_STORAGE"
	print "Now got sdcard path: "+sdcardpath
	# Is this just a link?
	try:
		sdcardinfo = subprocess.check_output([adb, "shell", "ls", "-l", "$EXTERNAL_STORAGE"], shell=True)
	except:
		return False, errinfo + " ERR: Can not get $EXTERNAL_STORAGE"
	obbpath    = sdcardpath+"/Android/obb/"
	sdcardinfo = sdcardinfo.split("\n")
	if len(sdcardinfo) <= 2 and sdcardinfo[0][0:1] == 'l':
		#Sure, we should put the path to /mnt/shell/emulated/obb/
		obbpath = "/mnt/shell/emulated/obb/"
	#Make directory
	obbpath = obbpath+info['package_name']+"/"
	print "Mkdir for: "+obbpath
	try:
		subprocess.check_output([adb, "shell", "mkdir", "-p", obbpath], shell=True)
	except:
		return False, errinfo + " ERR: Can not make obb path"
	#Copy obb
	g_info = "Copy obb files now, maybe it needs several minutes, please wait..."
	for item in info['expansions']:
		basename = os.path.basename(item['file'])
		try:
			out = subprocess.check_output([adb, "push", tmpdir+item['file'], obbpath+basename], shell=True)
		except:
			g_info = ''
			shutil.rmtree(tmpdir)
			return False, errinfo + " ERR: Can not copy obb files"
	g_info = ''
	shutil.rmtree(tmpdir)
	return ok, msg

############################################################
#Get setting file path
############################################################
def getinipath():
	inipath = os.environ['APPDATA']+os.sep+'apkpure'
	if not os.path.exists(inipath):
		os.makedirs(inipath)
	return inipath+os.sep+'apkinstall.json'	

############################################################
#API for javascript
############################################################
def do_close(param):
	#Delete all temprory files
	for item in g_tmpfiles:
		os.remove(item)
	ksbase.exit()

def do_openapk(filename):
	extname = os.path.splitext(filename)[1]
	if extname == '.xapk':
		obj = OpenXAPK(filename)
	else:
		obj = OpenAPK(filename)
	return json.dumps(obj)

def do_installapk(param):
	info = json.loads(param)
	extname = os.path.splitext(info['file'])[1]
	if extname == '.apk':
		ok, msg = InstallAPK(info['file'].encode("utf-8"), info['location'])
	elif extname == '.xapk':
		ok, msg = InstallXAPK(info['file'].encode("utf-8"), info['location'])
	else:
		return json.dumps({'err':False,'msg':'The file extension name must be .apk or .xapk'})
	return json.dumps({'err':ok,'msg':msg})

def do_getprogress(param):
	global g_info;
	return json.dumps({"msg":g_info})

def do_loadsetting(param):
	inifile = getinipath()
	jsonobj = {'scanapk':1,'autoupdate':1}
	if os.path.exists(inifile):
		try:
			jsonobj = json.loads(open(inifile, 'r').read())
		except:
			pass
	return json.dumps(jsonobj)

def do_savesetting(json):
	inifile = getinipath()
	open(inifile, 'w').write(json)

def do_checkupdate(url):
	try:
		response = urllib2.urlopen(url, timeout=10);
	except:
		return '0'
	version  = response.read();
	if version > g_pkgjson['app_ver']:
		return '1'
	print '0'

def do_openurl(url):
	webbrowser.open_new(url)

def do_checkcommandline(param):
	# Check is there a command argument?
	for arg in sys.argv:
		if arg[0:2] == '-A':
			filename = arg[2:].decode(g_encoding).encode('utf-8')
			return filename
	return ""
