# -*- coding: utf-8 -*-

#-------------------------------------------------------------------------
# drawElements Quality Program utilities
# --------------------------------------
#
# Copyright 2017 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#-------------------------------------------------------------------------

import os
import re
import sys
import argparse
import threading
import subprocess

from build_apk import findSDK
from build_apk import getDefaultBuildRoot
from build_apk import getPackageAndLibrariesForTarget
from build_apk import getBuildRootRelativeAPKPath
from build_apk import parsePackageName

# Import from <root>/scripts
sys.path.append(os.path.join(os.path.dirname(__file__), ".."))

from build.common import *

class Device:
	def __init__(self, serial, product, model, device):
		self.serial		= serial
		self.product	= product
		self.model		= model
		self.device		= device

	def __str__ (self):
		return "%s: {product: %s, model: %s, device: %s}" % (self.serial, self.product, self.model, self.device)

def getDevices (adbPath):
	proc = subprocess.Popen([adbPath, 'devices', '-l'], stdout=subprocess.PIPE)
	(stdout, stderr) = proc.communicate()

	if proc.returncode != 0:
		raise Exception("adb devices -l failed, got %d" % proc.returncode)

	ptrn = re.compile(r'^([a-zA-Z0-9\.\-:]+)\s+.*product:([^\s]+)\s+model:([^\s]+)\s+device:([^\s]+)')
	devices = []
	for line in stdout.splitlines()[1:]:
		if len(line.strip()) == 0:
			continue

		m = ptrn.match(line)
		if m == None:
			print "WARNING: Failed to parse device info '%s'" % line
			continue

		devices.append(Device(m.group(1), m.group(2), m.group(3), m.group(4)))

	return devices

def execWithPrintPrefix (args, linePrefix="", failOnNonZeroExit=True):

	def readApplyPrefixAndPrint (source, prefix, sink):
		while True:
			line = source.readline()
			if len(line) == 0: # EOF
				break;
			sink.write(prefix + line)

	process = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
	stdoutJob = threading.Thread(target=readApplyPrefixAndPrint, args=(process.stdout, linePrefix, sys.stdout))
	stderrJob = threading.Thread(target=readApplyPrefixAndPrint, args=(process.stderr, linePrefix, sys.stderr))
	stdoutJob.start()
	stderrJob.start()
	retcode = process.wait()
	if failOnNonZeroExit and retcode != 0:
		raise Exception("Failed to execute '%s', got %d" % (str(args), retcode))

def serialApply (f, argsList):
	for args in argsList:
		f(*args)

def parallelApply (f, argsList):
	class ErrorCode:
		def __init__ (self):
			self.error = None;

	def applyAndCaptureError (func, args, errorCode):
		try:
			func(*args)
		except:
			errorCode.error = sys.exc_info()

	errorCode = ErrorCode()
	jobs = []
	for args in argsList:
		job = threading.Thread(target=applyAndCaptureError, args=(f, args, errorCode))
		job.start()
		jobs.append(job)

	for job in jobs:
		job.join()

	if errorCode.error:
		raise errorCode.error[0], errorCode.error[1], errorCode.error[2]

def uninstall (adbPath, packageName, extraArgs = [], printPrefix=""):
	print printPrefix + "Removing existing %s...\n" % packageName,
	execWithPrintPrefix([adbPath] + extraArgs + [
			'uninstall',
			packageName
		], printPrefix, failOnNonZeroExit=False)
	print printPrefix + "Remove complete\n",

def install (adbPath, apkPath, extraArgs = [], printPrefix=""):
	print printPrefix + "Installing %s...\n" % apkPath,
	execWithPrintPrefix([adbPath] + extraArgs + [
			'install',
			apkPath
		], printPrefix)
	print printPrefix + "Install complete\n",

def installToDevice (device, adbPath, packageName, apkPath, printPrefix=""):
	if len(printPrefix) == 0:
		print "Installing to %s (%s)...\n" % (device.serial, device.model),
	else:
		print printPrefix + "Installing to %s\n" % device.serial,

	uninstall(adbPath, packageName, ['-s', device.serial], printPrefix)
	install(adbPath, apkPath, ['-s', device.serial], printPrefix)

def installToDevices (devices, doParallel, adbPath, packageName, apkPath):
	padLen = max([len(device.model) for device in devices])+1
	if doParallel:
		parallelApply(installToDevice, [(device, adbPath, packageName, apkPath, ("(%s):%s" % (device.model, ' ' * (padLen - len(device.model))))) for device in devices]);
	else:
		serialApply(installToDevice, [(device, adbPath, packageName, apkPath) for device in devices]);

def installToAllDevices (doParallel, adbPath, packageName, apkPath):
	devices = getDevices(adbPath)
	installToDevices(devices, doParallel, adbPath, packageName, apkPath)

def getAPKPath (buildRootPath, target):
	package = getPackageAndLibrariesForTarget(target)[0]
	return os.path.join(buildRootPath, getBuildRootRelativeAPKPath(package))

def getPackageName (target):
	package			= getPackageAndLibrariesForTarget(target)[0]
	manifestPath	= os.path.join(DEQP_DIR, "android", package.appDirName, "AndroidManifest.xml")

	return parsePackageName(manifestPath)

def findADB ():
	adbInPath = which("adb")
	if adbInPath != None:
		return adbInPath

	sdkPath = findSDK()
	if sdkPath != None:
		adbInSDK = os.path.join(sdkPath, "platform-tools", "adb")
		if os.path.isfile(adbInSDK):
			return adbInSDK

	return None

def parseArgs ():
	defaultADBPath		= findADB()
	defaultBuildRoot	= getDefaultBuildRoot()

	parser = argparse.ArgumentParser(os.path.basename(__file__),
		formatter_class=argparse.ArgumentDefaultsHelpFormatter)
	parser.add_argument('--build-root',
		dest='buildRoot',
		default=defaultBuildRoot,
		help="Root build directory")
	parser.add_argument('--adb',
		dest='adbPath',
		default=defaultADBPath,
		help="ADB binary path",
		required=(True if defaultADBPath == None else False))
	parser.add_argument('--target',
		dest='target',
		help='Build target',
		choices=['deqp', 'openglcts'],
		default='deqp')
	parser.add_argument('-p', '--parallel',
		dest='doParallel',
		action="store_true",
		help="Install package in parallel")
	parser.add_argument('-s', '--serial',
		dest='serial',
		type=str,
		nargs='+',
		help="Install package to device with serial number")
	parser.add_argument('-a', '--all',
		dest='all',
		action="store_true",
		help="Install to all devices")

	return parser.parse_args()

if __name__ == "__main__":
	args		= parseArgs()
	packageName	= getPackageName(args.target)
	apkPath		= getAPKPath(args.buildRoot, args.target)

	if not os.path.isfile(apkPath):
		die("%s does not exist" % apkPath)

	if args.all:
		installToAllDevices(args.doParallel, args.adbPath, packageName, apkPath)
	else:
		if args.serial == None:
			devices = getDevices(args.adbPath)
			if len(devices) == 0:
				die('No devices connected')
			elif len(devices) == 1:
				installToDevice(devices[0], args.adbPath, packageName, apkPath)
			else:
				print "More than one device connected:"
				for i in range(0, len(devices)):
					print "%3d: %16s %s" % ((i+1), devices[i].serial, devices[i].model)

				deviceNdx = int(raw_input("Choose device (1-%d): " % len(devices)))
				installToDevice(devices[deviceNdx-1], args.adbPath, packageName, apkPath)
		else:
			devices = getDevices(args.adbPath)

			devices = [dev for dev in devices if dev.serial in args.serial]
			devSerials = [dev.serial for dev in devices]
			notFounds = [serial for serial in args.serial if not serial in devSerials]

			for notFound in notFounds:
				print("Couldn't find device matching serial '%s'" % notFound)

			installToDevices(devices, args.doParallel, args.adbPath, packageName, apkPath)
