#!/usr/bin/python
# Copyright (c) 2011 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

"""Creates a directory with with the unpacked contents of the remoting webapp.

The directory will contain a copy-of or a link-to to all remoting webapp
resources.  This includes HTML/JS and any plugin binaries. The script also
massages resulting files appropriately with host plugin data. Finally,
a zip archive for all of the above is produced.
"""

# Python 2.5 compatibility
from __future__ import with_statement

import os
import platform
import re
import shutil
import subprocess
import sys
import time
import zipfile

def findAndReplace(filepath, findString, replaceString):
  """Does a search and replace on the contents of a file."""
  oldFilename = os.path.basename(filepath) + '.old'
  oldFilepath = os.path.join(os.path.dirname(filepath), oldFilename)
  os.rename(filepath, oldFilepath)
  with open(oldFilepath) as input:
    with open(filepath, 'w') as output:
      for s in input:
        output.write(s.replace(findString, replaceString))
  os.remove(oldFilepath)


def createZip(zip_path, directory):
  """Creates a zipfile at zip_path for the given directory."""
  zipfile_base = os.path.splitext(os.path.basename(zip_path))[0]
  zip = zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED)
  for (root, dirs, files) in os.walk(directory):
    for f in files:
      full_path = os.path.join(root, f)
      rel_path = os.path.relpath(full_path, directory)
      zip.write(full_path, os.path.join(zipfile_base, rel_path))
  zip.close()


def buildWebApp(buildtype, mimetype, destination, zip_path, plugin, files,
                locales):
  """Does the main work of building the webapp directory and zipfile.

  Args:
    buildtype: the type of build ("Official" or "Dev")
    mimetype: A string with mimetype of plugin.
    destination: A string with path to directory where the webapp will be
                 written.
    zipfile: A string with path to the zipfile to create containing the
             contents of |destination|.
    plugin: A string with path to the binary plugin for this webapp.
    files: An array of strings listing the paths for resources to include
           in this webapp.
    locales: An array of strings listing locales, which are copied, along
             with their directory structure from the _locales directory down.
  """
  # Ensure a fresh directory.
  try:
    shutil.rmtree(destination)
  except OSError:
    if os.path.exists(destination):
      raise
    else:
      pass
  os.mkdir(destination, 0775)

  # Use symlinks on linux and mac for faster compile/edit cycle.
  #
  # On Windows Vista platform.system() can return 'Microsoft' with some
  # versions of Python, see http://bugs.python.org/issue1082
  # should_symlink = platform.system() not in ['Windows', 'Microsoft']
  #
  # TODO(ajwong): Pending decision on http://crbug.com/27185 we may not be
  # able to load symlinked resources.
  should_symlink = False

  # Copy all the files.
  for current_file in files:
    destination_file = os.path.join(destination, os.path.basename(current_file))
    destination_dir = os.path.dirname(destination_file)
    if not os.path.exists(destination_dir):
      os.makedirs(destination_dir, 0775)

    if should_symlink:
      # TODO(ajwong): Detect if we're vista or higher.  Then use win32file
      # to create a symlink in that case.
      targetname = os.path.relpath(os.path.realpath(current_file),
                                   os.path.realpath(destination_file))
      os.symlink(targetname, destination_file)
    else:
      shutil.copy2(current_file, destination_file)

  # Copy all the locales, preserving directory structure
  destination_locales = os.path.join(destination, "_locales")
  os.mkdir(destination_locales , 0775)
  chromium_locale_dir = "/_locales/"
  chrome_locale_dir = "/_locales.official/"
  for current_locale in locales:
    pos = current_locale.find(chromium_locale_dir)
    locale_len = len(chromium_locale_dir)
    if (pos == -1):
      pos = current_locale.find(chrome_locale_dir)
      locale_len = len(chrome_locale_dir)
    if (pos == -1):
      raise "Missing locales directory in " + current_locale
    subtree = current_locale[pos+locale_len:]
    pos = subtree.find("/")
    if (pos == -1):
      raise "Malformed locale: " + current_locale
    locale_id = subtree[:pos]
    messages = subtree[pos+1:]
    destination_dir = os.path.join(destination_locales, locale_id)
    destination_file = os.path.join(destination_dir, messages)
    os.mkdir(destination_dir, 0775)
    shutil.copy2(current_locale, destination_file)

  # Create fake plugin files to appease the manifest checker.
  # It requires that if there is a plugin listed in the manifest that
  # there be a file in the plugin with that name.
  names = [
    'remoting_host_plugin.dll',  # Windows
    'remoting_host_plugin.plugin',  # Mac
    'libremoting_host_plugin.ia32.so',  # Linux 32
    'libremoting_host_plugin.x64.so'  # Linux 64
  ]
  pluginName = os.path.basename(plugin)

  for name in names:
    if name != pluginName:
      path = os.path.join(destination, name)
      f = open(path, 'w')
      f.write("placeholder for %s" % (name))
      f.close()

  # Copy the plugin.
  pluginName = os.path.basename(plugin)
  newPluginPath = os.path.join(destination, pluginName)
  if os.path.isdir(plugin):
    # On Mac we have a directory.
    shutil.copytree(plugin, newPluginPath)
  else:
    shutil.copy2(plugin, newPluginPath)

  # Strip the linux build.
  if ((platform.system() == 'Linux') and (buildtype == 'Official')):
    subprocess.call(["strip", newPluginPath])

  # Add unique build numbers to manifest version.
  # For now, this is based on the system clock (seconds since 1/1/1970), since
  # a previous attempt (based on build/utils/lastchange.py) was failing on Mac.
  # TODO(lambroslambrou): Use the SVN revision number or an incrementing build
  # number (http://crbug.com/90110).
  timestamp = int(time.time())
  # Version string must be 1-4 numbers separated by dots, with each number
  # between 0 and 0xffff.
  version1 = timestamp / 0x10000
  version2 = timestamp % 0x10000
  findAndReplace(os.path.join(destination, 'manifest.json'),
                 'UNIQUE_VERSION',
                 '%d.%d' % (version1, version2))

  # Now massage files with our mimetype.
  findAndReplace(os.path.join(destination, 'plugin_settings.js'),
                 'HOST_PLUGIN_MIMETYPE',
                 mimetype)

  # Make the zipfile.
  createZip(zip_path, destination)


def main():
  if len(sys.argv) < 6:
    print ('Usage: build-webapp.py '
           '<build-type> <mime-type> <dst> <zip-path> <plugin> '
           '<other files...> --locales <locales...>')
    sys.exit(1)

  reading_locales = False
  files = []
  locales = []
  for arg in sys.argv[6:]:
    if arg == "--locales":
      reading_locales = True;
    elif reading_locales:
      locales.append(arg)
    else:
      files.append(arg)

  buildWebApp(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4], sys.argv[5],
              files, locales)


if __name__ == '__main__':
  main()