# Copyright (C) 2016 Igalia S.L. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
#     * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
#     * 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
# OWNER OR 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 tempfile
import logging
import subprocess
try:
    import psutil
except ImportError:
    pass
from webkitpy.benchmark_runner.utils import force_remove
from webkitpy.benchmark_runner.browser_driver.browser_driver import BrowserDriver


_log = logging.getLogger(__name__)


class LinuxBrowserDriver(BrowserDriver):
    browser_name = None
    process_search_list = []
    platform = 'linux'

    def __init__(self):
        self.process_name = self._get_first_executable_path_from_list(self.process_search_list)
        if self.process_name is None:
            raise ValueError('Cant find executable for browser {browser_name}. Searched list: {browser_process_list}'.format(
                              browser_name=self.browser_name, browser_process_list=self.process_search_list))

    def prepare_env(self, config):
        self._browser_process = None
        self._browser_arguments = None
        self._temp_profiledir = tempfile.mkdtemp()
        self._test_environ = dict(os.environ)
        self._test_environ['HOME'] = self._temp_profiledir

    def prepare_initial_env(self, config):
        pass

    def restore_env(self):
        force_remove(self._temp_profiledir)

    def restore_env_after_all_testing(self):
        pass

    def close_browsers(self):
        if self._browser_process:
            if self._browser_process.poll() is None:  # still running
                if 'psutil' in sys.modules:
                    main_browser_process = psutil.Process(self._browser_process.pid)
                    browser_children = main_browser_process.children(recursive=True)
                    _log.info('Killing browser {browser_name} with pid {browser_pid} and cmd: {browser_cmd}'.format(
                               browser_name=self.browser_name, browser_pid=self._browser_process.pid,
                               browser_cmd=' '.join(main_browser_process.cmdline()).strip() or main_browser_process.name()))
                    main_browser_process.kill()
                    for browser_child in browser_children:
                        if browser_child.is_running():
                            _log.info('Killing still alive {browser_name} child with pid {browser_pid} and cmd: {browser_cmd}'.format(
                                       browser_name=self.browser_name, browser_pid=browser_child.pid,
                                       browser_cmd=' '.join(browser_child.cmdline()).strip() or browser_child.name()))
                            browser_child.kill()
                else:
                    _log.info('Killing browser {browser_name} with pid {browser_pid}'.format(
                               browser_name=self.browser_name, browser_pid=self._browser_process.pid))
                    self._browser_process.kill()
                    _log.warning('python psutil not found, cant check for '
                                 'still-alive browser childs to kill.')
            else:
                _log.error('Browser {browser_name} with pid {browser_pid} ended prematurely with return code {browser_retcode}.'.format(
                            browser_name=self.browser_name, browser_pid=self._browser_process.pid,
                            browser_retcode=self._browser_process.returncode))

    def launch_url(self, url, options, browser_build_path, browser_path):
        if not self._browser_arguments:
            self._browser_arguments = [url]
        exec_args = [self.process_name] + self._browser_arguments
        _log.info('Executing: {browser_cmdline}'.format(browser_cmdline=' '.join(exec_args)))
        self._browser_process = subprocess.Popen(exec_args, env=self._test_environ,
                                                 stdout=subprocess.PIPE,
                                                 stderr=subprocess.STDOUT)

    def launch_webdriver(self, url, driver):
        try:
            driver.maximize_window()
        except Exception as error:
            _log.error('Failed to maximize {browser} window - Error: {error}'.format(browser=driver.name, error=error))
        _log.info('Launching "%s" with url "%s"' % (driver.name, url))
        driver.get(url)

    def _get_first_executable_path_from_list(self, searchlist):
        searchpath = [os.path.curdir] + os.environ['PATH'].split(os.pathsep)
        for program in searchlist:
            for path in searchpath:
                fullpath = os.path.abspath(os.path.join(path, program))
                if  os.path.isfile(fullpath) and os.access(fullpath, os.X_OK):
                    return fullpath
        return None

    def _screen_size(self):
        # load_subclasses() from __init__.py will load this file to
        # check the platform defined. Do here a lazy import instead of
        # trying to import the Gtk module on the global scope of this
        # file to avoid ImportError errors on other platforms.
        # Python imports are cached and only run once, so this should be ok.
        import gi
        gi.require_version('Gtk', '3.0')
        gi.require_version('Gdk', '3.0')
        from gi.repository import Gtk, Gdk
        if Gtk.get_major_version() == 3 and Gtk.get_minor_version() < 22:
            screen = Gtk.Window().get_screen()
            return screen.get_monitor_geometry(screen.get_primary_monitor())
        else:
            display = Gdk.Display.get_default()
            monitor = display.get_primary_monitor()
            return monitor.get_geometry()
