#!/usr/bin/env python

# Copyright (c) 2013 Intel Corporation. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
# pylint: disable=F0401

import operator
import optparse
import os
import re
import shutil
import subprocess
import sys

sys.path.append('scripts/gyp')
from customize import ReplaceInvalidChars
from dex import AddExeExtensions
from manifest_json_parser import HandlePermissionList
from manifest_json_parser import ManifestJsonParser

def CleanDir(path):
  if os.path.exists(path):
    shutil.rmtree(path)


def RunCommand(command, shell=False):
  """Runs the command list, print the output, and propagate its result."""
  proc = subprocess.Popen(command, stdout=subprocess.PIPE,
                          stderr=subprocess.STDOUT, shell=shell)
  if not shell:
    output = proc.communicate()[0]
    result = proc.returncode
    print output
    if result != 0:
      print ('Command "%s" exited with non-zero exit code %d'
             % (' '.join(command), result))
      sys.exit(result)


def Which(name):
  """Search PATH for executable files with the given name."""
  result = []
  exts = filter(None, os.environ.get('PATHEXT', '').split(os.pathsep))
  path = os.environ.get('PATH', None)
  if path is None:
    return []
  for p in os.environ.get('PATH', '').split(os.pathsep):
    p = os.path.join(p, name)
    if os.access(p, os.X_OK):
      result.append(p)
    for e in exts:
      pext = p + e
      if os.access(pext, os.X_OK):
        result.append(pext)
  return result


def Find(name, path):
  """Find executable file with the given name
  and maximum API level under specific path."""
  result = {}
  for root, _, files in os.walk(path):
    if name in files:
      key = os.path.join(root, name)
      sdk_version = os.path.basename(os.path.dirname(key))
      str_num = re.search(r'\d+', sdk_version)
      if str_num:
        result[key] = int(str_num.group())
      else:
        result[key] = 0
  if not result:
    raise Exception()
  return max(result.iteritems(), key=operator.itemgetter(1))[0]


def GetVersion(path):
  """Get the version of this python tool."""
  version_str = 'XWalk packaging tool version '
  file_handle = open(path, 'r')
  src_content = file_handle.read()
  version_nums = re.findall(r'\d+', src_content)
  version_str += ('.').join(version_nums)
  file_handle.close()
  return version_str


def ParseManifest(options):
  parser = ManifestJsonParser(os.path.expanduser(options.manifest))
  if not options.package:
    options.package = 'org.xwalk.' + parser.GetAppName().lower()
  if not options.name:
    options.name = parser.GetAppName()
  if not options.app_version:
    options.app_version = parser.GetVersion()
  if parser.GetDescription():
    options.description = parser.GetDescription()
  if parser.GetPermissions():
    options.permissions = parser.GetPermissions()
  if parser.GetAppUrl():
    options.app_url = parser.GetAppUrl()
  elif parser.GetAppLocalPath():
    options.app_local_path = parser.GetAppLocalPath()
  else:
    print 'Error: there is no app launch path defined in manifest.json.'
    sys.exit(9)
  if parser.GetAppRoot():
    options.app_root = parser.GetAppRoot()
    temp_dict = parser.GetIcons()
    try:
      icon_dict = dict((int(k), v) for k, v in temp_dict.iteritems())
    except ValueError:
      print 'The key of icon in the manifest file should be a number.'
    # TODO(junmin): add multiple icons support.
    if icon_dict:
      icon_file = max(icon_dict.iteritems(), key=operator.itemgetter(0))[1]
      options.icon = os.path.join(options.app_root, icon_file)
  options.enable_remote_debugging = False
  if parser.GetFullScreenFlag().lower() == 'true':
    options.fullscreen = True
  elif parser.GetFullScreenFlag().lower() == 'false':
    options.fullscreen = False


def ParseXPK(options, out_dir):
  cmd = ['python', 'parse_xpk.py',
         '--file=%s' % os.path.expanduser(options.xpk),
         '--out=%s' % out_dir]
  RunCommand(cmd)
  if options.manifest:
    print ('Use the manifest from XPK by default '
           'when "--xpk" option is specified, and '
           'the "--manifest" option would be ignored.')
    sys.exit(7)

  if os.path.isfile(os.path.join(out_dir, 'manifest.json')):
    options.manifest = os.path.join(out_dir, 'manifest.json')
  else:
    print 'XPK doesn\'t contain manifest file.'
    sys.exit(8)


def FindExtensionJars(root_path):
  ''' Find all .jar files for external extensions. '''
  extension_jars = []
  if not os.path.exists(root_path):
    return extension_jars

  for afile in os.listdir(root_path):
    if os.path.isdir(os.path.join(root_path, afile)):
      base_name = os.path.basename(afile)
      extension_jar = os.path.join(root_path, afile, base_name + '.jar')
      if os.path.isfile(extension_jar):
        extension_jars.append(extension_jar)
  return extension_jars


def Customize(options):
  package = '--package=org.xwalk.app.template'
  if options.package:
    package = '--package=%s' % options.package
  name = '--name=AppTemplate'
  if options.name:
    name = '--name=%s' % options.name
  app_version = '--app-version=1.0.0'
  if options.app_version:
    app_version = '--app-version=%s' % options.app_version
  description = ''
  if options.description:
    description = '--description=%s' % options.description
  permissions = ''
  if options.permissions:
    permissions = '--permissions=%s' % options.permissions
  icon = ''
  if options.icon:
    icon = '--icon=%s' % os.path.expanduser(options.icon)
  app_url =  ''
  if options.app_url:
    app_url = '--app-url=%s' % options.app_url
  app_root = ''
  if options.app_root:
    app_root = '--app-root=%s' % os.path.expanduser(options.app_root)
  app_local_path = ''
  if options.app_local_path:
    app_local_path = '--app-local-path=%s' % options.app_local_path
  remote_debugging = ''
  if options.enable_remote_debugging:
    remote_debugging = '--enable-remote-debugging'
  fullscreen_flag = ''
  if options.fullscreen:
    fullscreen_flag = '-f'
  extensions_list = ''
  if options.extensions:
    extensions_list = '--extensions=%s' % options.extensions
  orientation = '--orientation=unspecified'
  if options.orientation:
    orientation = '--orientation=%s' % options.orientation
  cmd = ['python', 'customize.py', package,
          name, app_version, description, icon, permissions, app_url,
          remote_debugging, app_root, app_local_path, fullscreen_flag,
          extensions_list, orientation]
  RunCommand(cmd)


def Execution(options, sanitized_name):
  android_path_array = Which('android')
  if not android_path_array:
    print 'Please install Android SDK first.'
    sys.exit(1)

  sdk_root_path = os.path.dirname(os.path.dirname(android_path_array[0]))

  try:
    sdk_jar_path = Find('android.jar', os.path.join(sdk_root_path, 'platforms'))
  except Exception:
    print 'Your Android SDK may be ruined, please reinstall it.'
    sys.exit(2)

  level_string = os.path.basename(os.path.dirname(sdk_jar_path))
  api_level = int(re.search(r'\d+', level_string).group())
  if api_level < 14:
    print 'Please install Android API level (>=14) first.'
    sys.exit(3)

  if options.keystore_path:
    key_store = os.path.expanduser(options.keystore_path)
    if options.keystore_alias:
      key_alias = options.keystore_alias
    else:
      print 'Please provide an alias name of the developer key.'
      sys.exit(6)
    if options.keystore_passcode:
      key_code = options.keystore_passcode
    else:
      print 'Please provide the passcode of the developer key.'
      sys.exit(6)
  else:
    print ('Use xwalk\'s keystore by default for debugging. '
           'Please switch to your keystore when distributing it to app market.')
    key_store = 'scripts/ant/xwalk-debug.keystore'
    key_alias = 'xwalkdebugkey'
    key_code = 'xwalkdebug'

  if not os.path.exists('out'):
    os.mkdir('out')

  # Make sure to use ant-tasks.jar correctly.
  # Default Android SDK names it as ant-tasks.jar
  # Chrome third party Android SDk names it as anttasks.jar
  ant_tasks_jar_path = os.path.join(sdk_root_path,
                                    'tools', 'lib', 'ant-tasks.jar')
  if not os.path.exists(ant_tasks_jar_path):
    ant_tasks_jar_path = os.path.join(sdk_root_path,
                                      'tools', 'lib' ,'anttasks.jar')

  aapt_path = ''
  for aapt_str in AddExeExtensions('aapt'):
    try:
      aapt_path = Find(aapt_str, sdk_root_path)
      print 'Use %s in %s.' % (aapt_str, sdk_root_path)
      break
    except Exception:
      print 'There doesn\'t exist %s in %s.' % (aapt_str, sdk_root_path)
  if not aapt_path:
    print 'Your Android SDK may be ruined, please reinstall it.'
    sys.exit(2)

  # Check whether ant is installed.
  try:
    cmd = ['ant', '-version']
    RunCommand(cmd, True)
  except EnvironmentError:
    print 'Please install ant first.'
    sys.exit(4)

  res_dirs = '-DADDITIONAL_RES_DIRS=\'\''
  res_packages = '-DADDITIONAL_RES_PACKAGES=\'\''
  res_r_text_files = '-DADDITIONAL_R_TEXT_FILES=\'\''
  if options.mode == 'embedded':
    # Prepare the .pak file for embedded mode.
    pak_src_path = os.path.join('native_libs_res', 'xwalk.pak')
    pak_des_path = os.path.join(sanitized_name, 'assets', 'xwalk.pak')
    shutil.copy(pak_src_path, pak_des_path)

    js_src_dir = os.path.join('native_libs_res', 'jsapi')
    js_des_dir = os.path.join(sanitized_name, 'assets', 'jsapi')
    if os.path.exists(js_des_dir):
      shutil.rmtree(js_des_dir)
    shutil.copytree(js_src_dir, js_des_dir)

    res_ui_java = os.path.join('gen', 'ui_java')
    res_content_java = os.path.join('gen', 'content_java')
    res_xwalk_java = os.path.join('gen', 'xwalk_core_java')
    res_dirs = ('-DADDITIONAL_RES_DIRS='
                + os.path.join(res_ui_java, 'res_crunched') + ' '
                + os.path.join(res_ui_java, 'res_v14_compatibility') + ' '
                + os.path.join(res_ui_java, 'res_grit') + ' '
                + os.path.join('libs_res', 'ui') + ' '
                + os.path.join(res_content_java, 'res_crunched') + ' '
                + os.path.join(res_content_java, 'res_v14_compatibility') + ' '
                + os.path.join('libs_res', 'content') + ' '
                + os.path.join(res_content_java, 'res_grit') + ' '