# Copyright (C) 2017-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 os
import sys
import time

from webkitcorepy import Timeout

from webkitpy.port.server_process import ServerProcess


class SimulatorProcess(ServerProcess):

    class Popen(object):

        def __init__(self, pid, stdin, stdout, stderr, device):
            self.stdin = stdin
            self.stdout = stdout
            self.stderr = stderr
            self.pid = pid
            self.returncode = None
            self._device = device

        def poll(self):
            if self.returncode:
                return self.returncode
            if self._device.executive.check_running_pid(self.pid):
                self.returncode = None
            else:
                self.returncode = 1
            return self.returncode

        def wait(self):
            while not self.poll():
                time.sleep(0.01)  # In seconds
            return self.returncode

    # Python 2's implementation of makefile does not return a non-blocking file.
    class NonBlockingFileFromSocket(object):

        def __init__(self, sock, type):
            self.socket = sock
            self._file = os.fdopen(sock.fileno(), type, 0)
            ServerProcess._set_file_nonblocking(self._file)

        def __getattr__(self, name):
            return getattr(self._file, name)

        def close(self):
            result = -1
            try:
                result = self._file.close()
            except IOError:
                # If the file descriptor is bad, we don't have to worry about closing it
                pass
            try:
                self.socket.close()
            except OSError:
                pass
            return result

    def __init__(self, port_obj, name, cmd, env=None, universal_newlines=False, treat_no_data_as_crash=False, target_host=None, crash_message=None):
        env['PORT'] = str(target_host.listening_port())  # The target_host should be a device.
        super(SimulatorProcess, self).__init__(port_obj, name, cmd, env, universal_newlines, treat_no_data_as_crash, target_host, crash_message, allow_emulation=False)

        self._bundle_id = port_obj.app_identifier_from_bundle(cmd[0])

    def process_name(self):
        return self._port.app_executable_from_bundle(self._cmd[0])

    @staticmethod
    def _accept_connection_create_file(server, type):
        connection, address = server.accept()
        assert address[0] == '127.0.0.1'
        return SimulatorProcess.NonBlockingFileFromSocket(connection, type)

    def _start(self):
        if self._proc:
            raise ValueError('{} already running'.format(self._name))
        self._reset()

        # Each device has a listening socket intitilaized during the port's setup_test_run.
        # 3 client connections will be accepted for stdin, stdout and stderr in that order.
        self._target_host.listening_socket.listen(3)
        self._pid = self._target_host.launch_app(self._bundle_id, self._cmd[1:], env=self._env)
        self._system_pid = self._pid

        # FIXME <rdar://problem/57032042>: This timeout should be 15 seconds
        with Timeout(30, handler=RuntimeError('Timed out waiting for pid {} to connect at port {}'.format(self._pid, self._target_host.listening_port())), patch=False):
            stdin = None
            stdout = None
            stderr = None
            try:
                # This order matches the client side connections in Tools/TestRunnerShared/IOSLayoutTestCommunication.cpp setUpIOSLayoutTestCommunication()
                stdin = SimulatorProcess._accept_connection_create_file(self._target_host.listening_socket, 'wb')
                stdout = SimulatorProcess._accept_connection_create_file(self._target_host.listening_socket, 'rb')
                stderr = SimulatorProcess._accept_connection_create_file(self._target_host.listening_socket, 'rb')
            except:
                # We set self._proc as _reset() and _kill() depend on it.
                self._proc = SimulatorProcess.Popen(self._pid, stdin, stdout, stderr, self._target_host)
                if self._proc.poll() is not None:
                    self._reset()
                    raise Exception('App {} with pid {} crashed before stdin could be attached'.format(os.path.basename(self._cmd[0]), self._pid))
                self._kill()
                self._reset()
                raise

        self._proc = SimulatorProcess.Popen(self._pid, stdin, stdout, stderr, self._target_host)

    def stop(self, timeout_secs=3.0):
        # Only bother to check for leaks or stderr if the process is still running.
        if self.poll() is None:
            self._port.check_for_leaks(self.process_name(), self.pid())
            for child_process_name in self._child_processes.keys():
                for child_process_id in self._child_processes[child_process_name]:
                    self._port.check_for_leaks(child_process_name, child_process_id)

        if self._proc and self._proc.pid:
            self._target_host.executive.kill_process(self._proc.pid)

        return self._wait_for_stop(timeout_secs)
