# Copyright (C) 2018-2019 Apple Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1.  Redistributions of source code must retain the above copyright
#     notice, this list of conditions and the following disclaimer.
# 2.  Redistributions in binary form must reproduce the above copyright
#     notice, this list of conditions and the following disclaimer in the
#     documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

import logging
import traceback

from webkitpy.common.version_name_map import VersionNameMap, PUBLIC_TABLE, INTERNAL_TABLE
from webkitpy.layout_tests.models.test_configuration import TestConfiguration
from webkitpy.port.darwin import DarwinPort
from webkitpy.port.simulator_process import SimulatorProcess
from webkitpy.results.upload import Upload
from webkitpy.xcode.device_type import DeviceType
from webkitpy.xcode.simulated_device import DeviceRequest, SimulatedDeviceManager


_log = logging.getLogger(__name__)


class DevicePort(DarwinPort):

    DEVICE_MANAGER = None
    NO_DEVICE_MANAGER = 'No device manager found for port'

    def __init__(self, *args, **kwargs):
        super(DevicePort, self).__init__(*args, **kwargs)
        self._test_runner_process_constructor = SimulatorProcess
        self._printing_cmd_line = False

    def driver_cmd_line_for_logging(self):
        # Avoid creating/connecting to devices just for command line logging.
        self._printing_cmd_line = True
        result = super(DevicePort, self).driver_cmd_line_for_logging()
        self._printing_cmd_line = False
        return result

    def _generate_all_test_configurations(self):
        configurations = []
        for build_type in self.ALL_BUILD_TYPES:
            for architecture in self.ARCHITECTURES:
                configurations.append(TestConfiguration(version=self.version_name(), architecture=architecture, build_type=build_type))
        return configurations

    def child_processes(self):
        return int(self.get_option('child_processes'))

    def driver_name(self):
        if self.get_option('driver_name'):
            return self.get_option('driver_name')
        if self.get_option('webkit_test_runner'):
            return 'WebKitTestRunnerApp.app'
        return 'DumpRenderTree.app'

    # A device is the target host for a specific worker number.
    def target_host(self, worker_number=None):
        if self._printing_cmd_line or worker_number is None:
            return self.host
        if self.DEVICE_MANAGER is None:
            raise RuntimeError('No device manager for specified port')
        if self.DEVICE_MANAGER.INITIALIZED_DEVICES is None:
            raise RuntimeError('No initialized devices for testing')
        return self.DEVICE_MANAGER.INITIALIZED_DEVICES[worker_number]

    def devices(self):
        if self.DEVICE_MANAGER is None:
            return []
        if self.DEVICE_MANAGER.INITIALIZED_DEVICES is None:
            return []
        return self.DEVICE_MANAGER.INITIALIZED_DEVICES

    # Despite their names, these flags do not actually get passed all the way down to webkit-build.
    def _build_driver_flags(self):
        return ['--sdk', self.SDK] + (['ARCHS=%s' % self.architecture()] if self.architecture() else [])

    def _install(self):
        if not self.get_option('install'):
            _log.debug('Skipping installation')
            return

        for i in xrange(self.child_processes()):
            device = self.target_host(i)
            _log.debug(u'Installing to {}'.format(device))
            # Without passing DYLD_LIBRARY_PATH, libWebCoreTestSupport cannot be loaded and DRT/WKTR will crash pre-launch,
            # leaving a crash log which will be picked up in results. DYLD_FRAMEWORK_PATH is needed to prevent an early crash.
            if not device.install_app(self._path_to_driver(), {'DYLD_LIBRARY_PATH': self._build_path(), 'DYLD_FRAMEWORK_PATH': self._build_path()}):
                raise RuntimeError('Failed to install app {} on device {}'.format(self._path_to_driver(), device.udid))
            if not device.install_dylibs(self._build_path()):
                raise RuntimeError('Failed to install dylibs at {} on device {}'.format(self._build_path(), device.udid))

    def _device_type_with_version(self, device_type=None):
        device_type = device_type if device_type else self.DEVICE_TYPE
        return DeviceType(
            hardware_family=device_type.hardware_family,
            hardware_type=device_type.hardware_type,
            software_version=self.device_version(),
            software_variant=device_type.software_variant,
        )

    def default_child_processes(self, device_type=None):
        if not self.DEVICE_MANAGER:
            raise RuntimeError(self.NO_DEVICE_MANAGER)

        device_type = self._device_type_with_version(device_type)
        if device_type not in self.DEVICE_TYPE:
            return 0

        if self.get_option('force'):
            device_type.hardware_family = None
            device_type.hardware_type = None

        return self.DEVICE_MANAGER.device_count_for_type(
            self._device_type_with_version(device_type),
            host=self.host,
            use_booted_simulator=not self.get_option('dedicated_simulators', False),
        )

    def max_child_processes(self, device_type=None):
        result = self.default_child_processes(device_type=device_type)
        if result and self.DEVICE_MANAGER == SimulatedDeviceManager:
            return super(DevicePort, self).max_child_processes(device_type=None)
        return result

    def supported_device_types(self):
        types = set()
        for device in self.DEVICE_MANAGER.available_devices(host=self.host):
            if self.DEVICE_MANAGER == SimulatedDeviceManager and not device.platform_device.is_booted_or_booting():
                continue
            if device.device_type in self.DEVICE_TYPE:
                types.add(device.device_type)
        if types and not self.get_option('dedicated_simulators', False):

            def sorted_by_default_device_type(type):
                try:
                    return self.DEFAULT_DEVICE_TYPES.index(type)
                except ValueError:
                    return len(self.DEFAULT_DEVICE_TYPES)

            return sorted(types, key=sorted_by_default_device_type)

        return self.DEFAULT_DEVICE_TYPES or [self.DEVICE_TYPE]

    def setup_test_run(self, device_type=None):
        if not self.DEVICE_MANAGER:
            raise RuntimeError(self.NO_DEVICE_MANAGER)

        device_type = self._device_type_with_version(device_type)
        _log.debug(u'\nCreating devices for {}'.format(device_type))

        request = DeviceRequest(
            device_type,
            use_booted_simulator=not self.get_option('dedicated_simulators', False),
            use_existing_simulator=False,
            allow_incomplete_match=self.get_option('force'),
        )
        self.DEVICE_MANAGER.initialize_devices(
            [request] * self.child_processes(),
            self.host,
            layout_test_dir=self.layout_tests_dir(),
            pin=self.get_option('pin', None),
            use_nfs=self.get_option('use_nfs', True),
            reboot=self.get_option('reboot', False),
        )

        if not self.devices():
            raise RuntimeError('No devices are available for testing')
        if len(self.DEVICE_MANAGER.INITIALIZED_DEVICES) < self.child_processes():
            raise RuntimeError('To few connected devices for {} processes'.format(self.child_processes()))

        self._install()

        for i in xrange(self.child_processes()):
            host = self.target_host(i)
            host.prepare_for_testing(
                self.ports_to_forward(),
                self.app_identifier_from_bundle(self._path_to_driver()),
                self.layout_tests_dir(),
            )
            self._crash_logs_to_skip_for_host[host] = host.filesystem.files_under(self.path_to_crash_logs())

    def clean_up_test_run(self):
        super(DevicePort, self).clean_up_test_run()

        # Best effort to let every device teardown before throwing any exceptions here.
        # Failure to teardown devices can leave things in a bad state.
        exception_list = []
        for i in xrange(self.child_processes()):
            device = self.target_host(i)
            if not device:
                continue
            try:
                device.finished_testing()
            except BaseException as e:
                trace = traceback.format_exc()
                if isinstance(e, Exception):
                    exception_list.append([e, trace])
                else:
                    exception_list.append([Exception(u'Exception while tearing down {}'.format(device)), trace])

        if len(exception_list) == 1:
            raise
        if len(exception_list) > 1:
            print('\n')
            for exception in exception_list:
                _log.error('{} raised: {}'.format(exception[0].__class__.__name__, exception[0]))
                _log.error(exception[1])
                _log.error('--------------------------------------------------')

            raise RuntimeError('Multiple failures when teardown devices')

    def did_spawn_worker(self, worker_number):
        super(DevicePort, self).did_spawn_worker(worker_number)

        self.target_host(worker_number).release_worker_resources()

    def setup_environ_for_server(self, server_name=None):
        env = super(DevicePort, self).setup_environ_for_server(server_name)
        if server_name == self.driver_name() and self.get_option('guard_malloc'):
            self._append_value_colon_separated(env, 'DYLD_INSERT_LIBRARIES', '/usr/lib/libgmalloc.dylib')
            self._append_value_colon_separated(env, '__XPC_DYLD_INSERT_LIBRARIES', '/usr/lib/libgmalloc.dylib')
        env['XML_CATALOG_FILES'] = ''  # work around missing /etc/catalog <rdar://problem/4292995>
        return env

    def device_version(self):
        raise NotImplementedError

    def configuration_for_upload(self, host=None):
        configuration = self.test_configuration()

        device_type = host.device_type if host else self.DEVICE_TYPE
        model = device_type.hardware_family
        if model and device_type.hardware_type:
            model += u' {}'.format(device_type.hardware_type)

        version = self.device_version()
        version_name = None
        for table in [INTERNAL_TABLE, PUBLIC_TABLE]:
            version_name = VersionNameMap.map(self.host.platform).to_name(version, platform=device_type.software_variant.lower(), table=table)
            if version_name:
                break

        if self.get_option('guard_malloc'):
            style = 'guard-malloc'
        elif self._config.asan:
            style = 'asan'
        else:
            style = configuration.build_type

        return Upload.create_configuration(
            platform=device_type.software_variant.lower(),
            is_simulator=self.DEVICE_MANAGER == SimulatedDeviceManager,
            version=str(version),
            version_name=version_name,
            architecture=configuration.architecture,
            style=style,
            model=model,
            sdk=host.build_version if host else None,
        )
