# 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 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 restore_env(self):
        force_remove(self._temp_profiledir)

    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):
        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()
