# 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 webkitpy.common.timeout_context 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):
            try:
                result = self._file.close()
                # Closing the file implicitly closes the socket in Python 3
                if sys.version_info < (3, 0):
                    self.socket.close()
                return result
            except IOError:
                # If the file descriptor is bad, we don't have to worry about closing it
                pass

    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)

        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, RuntimeError('Timed out waiting for pid {} to connect at port {}'.format(self._pid, self._target_host.listening_port()))):
            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)
