# -*- 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)
