# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.

import argparse
import ConfigParser
from StringIO import StringIO
import os
import re
import sys
import tempfile
import xml.dom.minidom
import zipfile

import mozfile
import mozlog

import errors


INI_DATA_MAPPING = (('application', 'App'), ('platform', 'Build'))


class Version(object):

    def __init__(self):
        self._info = {}
        self._logger = mozlog.get_default_logger(component='mozversion')
        if not self._logger:
            self._logger = mozlog.unstructured.getLogger('mozversion')

    def get_gecko_info(self, path):
        for type, section in INI_DATA_MAPPING:
            config_file = os.path.join(path, "%s.ini" % type)
            if os.path.exists(config_file):
                self._parse_ini_file(open(config_file), type, section)
            else:
                self._logger.warning('Unable to find %s' % config_file)

    def _parse_ini_file(self, fp, type, section):
        config = ConfigParser.RawConfigParser()
        config.readfp(fp)
        name_map = {'codename': 'display_name',
                    'milestone': 'version',
                    'sourcerepository': 'repository',
                    'sourcestamp': 'changeset'}
        for key, value in config.items(section):
            name = name_map.get(key, key).lower()
            self._info['%s_%s' % (type, name)] = config.has_option(
                section, key) and config.get(section, key) or None

        if not self._info.get('application_display_name'):
            self._info['application_display_name'] = \
                self._info.get('application_name')


class LocalFennecVersion(Version):

    def __init__(self, path, **kwargs):
        Version.__init__(self, **kwargs)
        self.get_gecko_info(path)

    def get_gecko_info(self, path):
        archive = zipfile.ZipFile(path, 'r')
        archive_list = archive.namelist()
        for type, section in INI_DATA_MAPPING:
            filename = "%s.ini" % type
            if filename in archive_list:
                self._parse_ini_file(archive.open(filename), type,
                                     section)
            else:
                self._logger.warning('Unable to find %s' % filename)

        if "package-name.txt" in archive_list:
            self._info["package_name"] = \
                archive.open("package-name.txt").readlines()[0].strip()


class LocalVersion(Version):

    def __init__(self, binary, **kwargs):
        Version.__init__(self, **kwargs)

        if binary:
            # on Windows, the binary may be specified with or without the
            # .exe extension
            if not os.path.exists(binary) and not os.path.exists(binary +
                                                                 '.exe'):
                raise IOError('Binary path does not exist: %s' % binary)
            path = os.path.dirname(os.path.realpath(binary))
        else:
            path = os.getcwd()

        if not self.check_location(path):
            if sys.platform == 'darwin':
                resources_path = os.path.join(os.path.dirname(path),
                                              'Resources')
                if self.check_location(resources_path):
                    path = resources_path
                else:
                    raise errors.LocalAppNotFoundError(path)
            else:
                raise errors.LocalAppNotFoundError(path)

        self.get_gecko_info(path)

    def check_location(self, path):
        return (os.path.exists(os.path.join(path, 'application.ini'))
                and os.path.exists(os.path.join(path, 'platform.ini')))


class B2GVersion(Version):

    def __init__(self, sources=None, **kwargs):
        Version.__init__(self, **kwargs)

        sources = sources or \
            os.path.exists(os.path.join(os.getcwd(), 'sources.xml')) and \
            os.path.join(os.getcwd(), 'sources.xml')

        if sources and os.path.exists(sources):
            sources_xml = xml.dom.minidom.parse(sources)
            for element in sources_xml.getElementsByTagName('project'):
                path = element.getAttribute('path')
                changeset = element.getAttribute('revision')
                if path in ['gaia', 'gecko', 'build']:
                    if path == 'gaia' and self._info.get('gaia_changeset'):
                        break
                    self._info['_'.join([path, 'changeset'])] = changeset

    def get_gaia_info(self, app_zip):
        tempdir = tempfile.mkdtemp()
        try:
            gaia_commit = os.path.join(tempdir, 'gaia_commit.txt')
            try:
                zip_file = zipfile.ZipFile(app_zip.name)
                with open(gaia_commit, 'w') as f:
                    f.write(zip_file.read('resources/gaia_commit.txt'))
            except zipfile.BadZipfile:
                self._logger.info('Unable to unzip application.zip, falling '
                                  'back to system unzip')
                from subprocess import call
                call(['unzip', '-j', app_zip.name, 'resources/gaia_commit.txt',
                      '-d', tempdir])

            with open(gaia_commit) as f:
                changeset, date = f.read().splitlines()
                self._info['gaia_changeset'] = re.match(
                    '^\w{40}$', changeset) and changeset or None
                self._info['gaia_date'] = date
        except KeyError:
                self._logger.warning(
                    'Unable to find resources/gaia_commit.txt in '
                    'application.zip')
        finally:
            mozfile.remove(tempdir)


class LocalB2GVersion(B2GVersion):

    def __init__(self, binary, sources=None, **kwargs):
        B2GVersion.__init__(self, sources, **kwargs)

        if binary:
            if not os.path.exists(binary):
                raise IOError('Binary path does not exist: %s' % binary)
            path = os.path.dirname(binary)
        else:
            if os.path.exists(os.path.join(os.getcwd(), 'application.ini')):
                path = os.getcwd()

        self.get_gecko_info(path)

        zip_path = os.path.join(
            path, 'gaia', 'profile', 'webapps',
            'settings.gaiamobile.org', 'application.zip')
        if os.path.exists(zip_path):
            with open(zip_path, 'rb') as zip_file:
                self.get_gaia_info(zip_file)
        else:
            self._logger.warning('Error pulling gaia file')


class RemoteB2GVersion(B2GVersion):

    def __init__(self, sources=None, dm_type='adb', host=None,
                 device_serial=None, adb_host=None, adb_port=None,
                 **kwargs):
        B2GVersion.__init__(self, sources, **kwargs)

        try:
            import mozdevice
        except ImportError:
            self._logger.critical("mozdevice is required to get the version"
                                  " of a remote device")
            raise

        if dm_type == 'adb':
            dm = mozdevice.DeviceManagerADB(deviceSerial=device_serial,
                                            serverHost=adb_host,
                                            serverPort=adb_port)
        elif dm_type == 'sut':
            if not host:
                raise errors.RemoteAppNotFoundError(
                    'A host for SUT must be supplied.')
            dm = mozdevice.DeviceManagerSUT(host=host)
        else:
            raise errors.RemoteAppNotFoundError(
                'Unknown device manager type: %s' % dm_type)

        if not sources:
            path = 'system/sources.xml'
            if dm.fileExists(path):
                sources = StringIO(dm.pullFile(path))
            else:
                self._logger.info('Unable to find %s' % path)

        tempdir = tempfile.mkdtemp()
        for ini in ('application', 'platform'):
            with open(os.path.join(tempdir, '%s.ini' % ini), 'w') as f:
                f.write(dm.pullFile('/system/b2g/%s.ini' % ini))
                f.flush()
        self.get_gecko_info(tempdir)
        mozfile.remove(tempdir)

        for path in ['/system/b2g', '/data/local']:
            path += '/webapps/settings.gaiamobile.org/application.zip'
            if dm.fileExists(path):
                with tempfile.NamedTemporaryFile() as f:
                    dm.getFile(path, f.name)
                    self.get_gaia_info(f)
                break
        else:
            self._logger.warning('Error pulling gaia file')

        build_props = dm.pullFile('/system/build.prop')
        desired_props = {
            'ro.build.version.incremental': 'device_firmware_version_incremental',
            'ro.build.version.release': 'device_firmware_version_release',
            'ro.build.date.utc': 'device_firmware_date',
            'ro.product.device': 'device_id'}
        for line in build_props.split('\n'):
            if not line.strip().startswith('#') and '=' in line:
                key, value = [s.strip() for s in line.split('=', 1)]
                if key in desired_props.keys():
                    self._info[desired_props[key]] = value

        if self._info.get('device_id', '').lower() == 'flame':
            for prop in ['ro.boot.bootloader', 't2m.sw.version']:
                value = dm.shellCheckOutput(['getprop', prop])
                if value:
                    self._info['device_firmware_version_base'] = value
                    break


def get_version(binary=None, sources=None, dm_type=None, host=None,
                device_serial=None, adb_host=None, adb_port=None):
    """
    Returns the application version information as a dict. You can specify
    a path to the binary of the application or an Android APK file (to get
    version information for Firefox for Android). If this is omitted then the
    current directory is checked for the existance of an application.ini
    file. If not found and that the binary path was not specified, then it is
    assumed the target application is a remote Firefox OS instance.

    :param binary: Path to the binary for the application or Android APK file
    :param sources: Path to the sources.xml file (Firefox OS)
    :param dm_type: Device manager type. Must be 'adb' or 'sut' (Firefox OS)
    :param host: Host address of remote Firefox OS instance (SUT)
    :param device_serial: Serial identifier of Firefox OS device (ADB)
    :param adb_host: Host address of ADB server
    :param adb_port: Port of ADB server
    """
    try:
        if binary and zipfile.is_zipfile(binary) and 'AndroidManifest.xml' in \
           zipfile.ZipFile(binary, 'r').namelist():
            version = LocalFennecVersion(binary)
        else:
            version = LocalVersion(binary)
            if version._info.get('application_name') == 'B2G':
                version = LocalB2GVersion(binary, sources=sources)
    except errors.LocalAppNotFoundError:
        if binary:
            # we had a binary argument, do not search for remote B2G
            raise
        version = RemoteB2GVersion(sources=sources,
                                   dm_type=dm_type,
                                   host=host,
                                   adb_host=adb_host,
                                   adb_port=adb_port,
                                   device_serial=device_serial)

    for (key, value) in sorted(version._info.items()):
        if value:
            version._logger.info('%s: %s' % (key, value))

    return version._info


def cli(args=sys.argv[1:]):
    parser = argparse.ArgumentParser(
        description='Display version information for Mozilla applications')
    parser.add_argument(
        '--binary',
        help='path to application binary or apk')
    fxos = parser.add_argument_group('Firefox OS')
    fxos.add_argument(
        '--sources',
        help='path to sources.xml')
    fxos.add_argument(
        '--device',
        help='serial identifier of device to target')
    fxos.add_argument(
        '--adb-host',
        help='host running adb')
    fxos.add_argument(
        '--adb-port',
        help='port running adb')
    mozlog.commandline.add_logging_group(
        parser,
        include_formatters=mozlog.commandline.TEXT_FORMATTERS
    )

    args = parser.parse_args()
    dm_type = os.environ.get('DM_TRANS', 'adb')
    host = os.environ.get('TEST_DEVICE')

    mozlog.commandline.setup_logging(
        'mozversion', args, {'mach': sys.stdout})

    get_version(binary=args.binary,
                sources=args.sources,
                dm_type=dm_type,
                host=host,
                device_serial=args.device,
                adb_host=args.adb_host,
                adb_port=args.adb_port)

if __name__ == '__main__':
    cli()
