# (c) 2018 Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)

from __future__ import (absolute_import, division, print_function)
__metaclass__ = type

import base64
import errno
import json
import os
import pkgutil
import random
import re

from distutils.version import LooseVersion

from ansible import constants as C
from ansible.errors import AnsibleError
from ansible.module_utils._text import to_bytes, to_native, to_text
from ansible.module_utils.compat.importlib import import_module
from ansible.plugins.loader import ps_module_utils_loader
from ansible.utils.collection_loader import resource_from_fqcr

class PSModuleDepFinder(object):

    def __init__(self):
        # This is also used by validate-modules to get a module's required utils in base and a collection.
        self.ps_modules = dict()
        self.exec_scripts = dict()

        # by defining an explicit dict of cs utils and where they are used, we
        # can potentially save time by not adding the type multiple times if it
        # isn't needed
        self.cs_utils_wrapper = dict()
        self.cs_utils_module = dict()

        self.ps_version = None
        self.os_version = None
        self.become = False

        self._re_cs_module = [
            # Reference C# module_util in another C# util, this must always be the fully qualified name.
            # 'using ansible_collections.{namespace}.{collection}.plugins.module_utils.{name}'
            re.compile(to_bytes(r'(?i)^using\s((Ansible\..+)|'
                                r'(ansible_collections\.\w+\.\w+\.plugins\.module_utils\.[\w\.]+));\s*$')),
        ]

        self._re_cs_in_ps_module = [
            # Reference C# module_util in a PowerShell module
            # '#AnsibleRequires -CSharpUtil Ansible.{name}'
            # '#AnsibleRequires -CSharpUtil ansible_collections.{namespace}.{collection}.plugins.module_utils.{name}'
            # '#AnsibleRequires -CSharpUtil ..module_utils.{name}'
            re.compile(to_bytes(r'(?i)^#\s*ansiblerequires\s+-csharputil\s+((Ansible\..+)|'
                                r'(ansible_collections\.\w+\.\w+\.plugins\.module_utils\.[\w\.]+)|'
                                r'(\.[\w\.]+))')),
        ]

        self._re_ps_module = [
            # Original way of referencing a builtin module_util
            # '#Requires -Module Ansible.ModuleUtils.{name}
            re.compile(to_bytes(r'(?i)^#\s*requires\s+\-module(?:s?)\s*(Ansible\.ModuleUtils\..+)')),
            # New way of referencing a builtin and collection module_util
            # '#AnsibleRequires -PowerShell Ansible.ModuleUtils.{name}'
            # '#AnsibleRequires -PowerShell ansible_collections.{namespace}.{collection}.plugins.module_utils.{name}'
            # '#AnsibleRequires -PowerShell ..module_utils.{name}'
            re.compile(to_bytes(r'(?i)^#\s*ansiblerequires\s+-powershell\s+((Ansible\.ModuleUtils\..+)|'
                                r'(ansible_collections\.\w+\.\w+\.plugins\.module_utils\.[\w\.]+)|'
                                r'(\.[\w\.]+))')),
        ]

        self._re_wrapper = re.compile(to_bytes(r'(?i)^#\s*ansiblerequires\s+-wrapper\s+(\w*)'))
        self._re_ps_version = re.compile(to_bytes(r'(?i)^#requires\s+\-version\s+([0-9]+(\.[0-9]+){0,3})$'))
        self._re_os_version = re.compile(to_bytes(r'(?i)^#ansiblerequires\s+\-osversion\s+([0-9]+(\.[0-9]+){0,3})$'))
        self._re_become = re.compile(to_bytes(r'(?i)^#ansiblerequires\s+\-become$'))

    def scan_module(self, module_data, fqn=None, wrapper=False, powershell=True):
        lines = module_data.split(b'\n')
        module_utils = set()
        if wrapper:
            cs_utils = self.cs_utils_wrapper
        else:
            cs_utils = self.cs_utils_module

        if powershell:
            checks = [
                # PS module contains '#Requires -Module Ansible.ModuleUtils.*'
                # PS module contains '#AnsibleRequires -Powershell Ansible.*' (or collections module_utils ref)
                (self._re_ps_module, self.ps_modules, ".psm1"),
                # PS module contains '#AnsibleRequires -CSharpUtil Ansible.*' (or collections module_utils ref)
                (self._re_cs_in_ps_module, cs_utils, ".cs"),
            ]
        else:
            checks = [
                # CS module contains 'using Ansible.*;' or 'using ansible_collections.ns.coll.plugins.module_utils.*;'
                (self._re_cs_module, cs_utils, ".cs"),
            ]

        for line in lines:
            for check in checks:
                for pattern in check[0]:
                    match = pattern.match(line)
                    if match:
                        # tolerate windows line endings by stripping any remaining
                        # newline chars
                        module_util_name = to_text(match.group(1).rstrip())

                        if module_util_name not in check[1].keys():
                            module_utils.add((module_util_name, check[2], fqn))

                        break

            if powershell:
                ps_version_match = self._re_ps_version.match(line)
                if ps_version_match:
                    self._parse_version_match(ps_version_match, "ps_version")

                os_version_match = self._re_os_version.match(line)
                if os_version_match:
                    self._parse_version_match(os_version_match, "os_version")

                # once become is set, no need to keep on checking recursively
                if not self.become:
                    become_match = self._re_become.match(line)
                    if become_match:
                        self.become = True

            if wrapper:
                wrapper_match = self._re_wrapper.match(line)
                if wrapper_match:
                    self.scan_exec_script(wrapper_match.group(1).rstrip())

        # recursively drill into each Requires to see if there are any more
        # requirements
        for m in set(module_utils):
            self._add_module(m, wrapper=wrapper)

    def scan_exec_script(self, name):
        # scans lib/ansible/executor/powershell for scripts used in the module
        # exec side. It also scans these scripts for any dependencies
        name = to_text(name)
        if name in self.exec_scripts.keys():
            return

        data = pkgutil.get_data("ansible.executor.powershell", to_native(name + ".ps1"))
        if data is None:
            raise AnsibleError("Could not find executor powershell script "
                               "for '%s'" % name)

        b_data = to_bytes(data)

        # remove comments to reduce the payload size in the exec wrappers
        if C.DEFAULT_DEBUG:
            exec_script = b_data
        else:
            exec_script = _strip_comments(b_data)
        self.exec_scripts[name] = to_bytes(exec_script)
        self.scan_module(b_data, wrapper=True, powershell=True)

    def _add_module(self, name, wrapper=False):
        m, ext, fqn = name
        m = to_text(m)

        util_fqn = None

        if m.startswith("Ansible."):
            # Builtin util, use plugin loader to get the data
            mu_path = ps_module_utils_loader.find_plugin(m, ext)

            if not mu_path:
                raise AnsibleError('Could not find imported module support code '
                                   'for \'%s\'' % m)

            module_util_data = to_bytes(_slurp(mu_path))
        else:
            # Collection util, load the package data based on the util import.

            submodules = m.split(".")
            if m.startswith('.'):
                fqn_submodules = fqn.split('.')
                for submodule in submodules:
                    if submodule:
                        break
                    del fqn_submodules[-1]

                submodules = fqn_submodules + [s for s in submodules if s]

            n_package_name = to_native('.'.join(submodules[:-1]), errors='surrogate_or_strict')
            n_resource_name = to_native(submodules[-1] + ext, errors='surrogate_or_strict')

            try:
                module_util = import_module(n_package_name)
                module_util_data = to_bytes(pkgutil.get_data(n_package_name, n_resource_name),
                                            errors='surrogate_or_strict')
                util_fqn = to_text("%s.%s " % (n_package_name, submodules[-1]), errors='surrogate_or_strict')

                # Get the path of the util which is required for coverage collection.
                resource_paths = list(module_util.__path__)
                if len(resource_paths) != 1:
                    # This should never happen with a collection but we are just being defensive about it.
                    raise AnsibleError("Internal error: Referenced module_util package '%s' contains 0 or multiple "
                                       "import locations when we only expect 1." % n_package_name)
                mu_path = os.path.join(resource_paths[0], n_resource_name)
            except OSError as err:
                if err.errno == errno.ENOENT:
                    raise AnsibleError('Could not find collection imported module support code for \'%s\''
                                       % to_native(m))
                else:
                    raise

        util_info = {
            'data': module_util_data,
            'path': to_text(mu_path),
        }
        if ext == ".psm1":
            self.ps_modules[m] = util_info
        else:
            if wrapper:
                self.cs_utils_wrapper[m] = util_info
            else:
                self.cs_utils_module[m] = util_info
        self.scan_module(module_util_data, fqn=util_fqn, wrapper=wrapper, powershell=(ext == ".psm1"))

    def _parse_version_match(self, match, attribute):
        new_version = to_text(match.group(1)).rstrip()

        # PowerShell cannot cast a string of "1" to Version, it must have at
        # least the major.minor for it to be valid so we append 0
        if match.group(2) is None:
            new_version = "%s.0" % new_version

        existing_version = getattr(self, attribute, None)
        if existing_version is None:
            setattr(self, attribute, new_version)
        else:
            # determine which is the latest version and set that
            if LooseVersion(new_version) > LooseVersion(existing_version):
                setattr(self, attribute, new_version)

def _slurp(path):
    if not os.path.exists(path):
        raise AnsibleError("imported module support code does not exist at %s"
                           % os.path.abspath(path))
    fd = open(path, 'rb')
    data = fd.read()
    fd.close()
    return data

def _strip_comments(source):
    # Strip comments and blank lines from the wrapper
    buf = []
    start_block = False
    for line in source.splitlines():
        l = line.strip()

        if start_block and l.endswith(b'#>'):
            start_block = False
            continue
        elif start_block:
            continue
        elif l.startswith(b'<#'):
            start_block = True
            continue
        elif not l or l.startswith(b'#'):
            continue

        buf.append(line)
    return b'\n'.join(buf)

def _create_powershell_wrapper(b_module_data, module_path, module_args,
                               environment, async_timeout, become,
                               become_method, become_user, become_password,
                               become_flags, substyle, task_vars, module_fqn):
    # creates the manifest/wrapper used in PowerShell/C# modules to enable
    # things like become and async - this is also called in action/script.py

    # FUTURE: add process_wrapper.ps1 to run module_wrapper in a new process
    # if running under a persistent connection and substyle is C# so we
    # don't have type conflicts
    finder = PSModuleDepFinder()
    if substyle != 'script':
        # don't scan the module for util dependencies and other Ansible related
        # flags if the substyle is 'script' which is set by action/script
        finder.scan_module(b_module_data, fqn=module_fqn, powershell=(substyle == "powershell"))

    module_wrapper = "module_%s_wrapper" % substyle
    exec_manifest = dict(
        module_entry=to_text(base64.b64encode(b_module_data)),
        powershell_modules=dict(),
        csharp_utils=dict(),
        csharp_utils_module=list(),  # csharp_utils only required by a module
        module_args=module_args,
        actions=[module_wrapper],
        environment=environment,
        encoded_output=False,
    )
    finder.scan_exec_script(module_wrapper)

    if async_timeout > 0:
        finder.scan_exec_script('exec_wrapper')
        finder.scan_exec_script('async_watchdog')
        finder.scan_exec_script('async_wrapper')

        exec_manifest["actions"].insert(0, 'async_watchdog')
        exec_manifest["actions"].insert(0, 'async_wrapper')
        exec_manifest["async_jid"] = str(random.randint(0, 999999999999))
        exec_manifest["async_timeout_sec"] = async_timeout
        exec_manifest["async_startup_timeout"] = C.config.get_config_value("WIN_ASYNC_STARTUP_TIMEOUT", variables=task_vars)

    if become and resource_from_fqcr(become_method) == 'runas':  # runas and namespace.collection.runas
        finder.scan_exec_script('exec_wrapper')
        finder.scan_exec_script('become_wrapper')

        exec_manifest["actions"].insert(0, 'become_wrapper')
        exec_manifest["become_user"] = become_user
        exec_manifest["become_password"] = become_password
        exec_manifest['become_flags'] = become_flags

    exec_manifest['min_ps_version'] = finder.ps_version
    exec_manifest['min_os_version'] = finder.os_version
    if finder.become and 'become_wrapper' not in exec_manifest['actions']:
        finder.scan_exec_script('exec_wrapper')
        finder.scan_exec_script('become_wrapper')

        exec_manifest['actions'].insert(0, 'become_wrapper')
        exec_manifest['become_user'] = 'SYSTEM'
        exec_manifest['become_password'] = None
        exec_manifest['become_flags'] = None

    coverage_manifest = dict(
        module_path=module_path,
        module_util_paths=dict(),
        output=None,
    )
    coverage_output = C.config.get_config_value('COVERAGE_REMOTE_OUTPUT', variables=task_vars)
    if coverage_output and substyle == 'powershell':
        finder.scan_exec_script('coverage_wrapper')
        coverage_manifest['output'] = coverage_output

        coverage_path_filter = C.config.get_config_value('COVERAGE_REMOTE_PATH_FILTER', variables=task_vars)
        coverage_manifest['path_filter'] = coverage_path_filter

    # make sure Ansible.ModuleUtils.AddType is added if any C# utils are used
    if len(finder.cs_utils_wrapper) > 0 or len(finder.cs_utils_module) > 0:
        finder._add_module((b"Ansible.ModuleUtils.AddType", ".psm1", None),
                           wrapper=False)

    # exec_wrapper is only required to be part of the payload if using
    # become or async, to save on payload space we check if exec_wrapper has
    # already been added, and remove it manually if it hasn't later
    exec_required = "exec_wrapper" in finder.exec_scripts.keys()
    finder.scan_exec_script("exec_wrapper")
    # must contain an empty newline so it runs the begin/process/end block
    finder.exec_scripts["exec_wrapper"] += b"\n\n"

    exec_wrapper = finder.exec_scripts["exec_wrapper"]
    if not exec_required:
        finder.exec_scripts.pop("exec_wrapper")

    for name, data in finder.exec_scripts.items():
        b64_data = to_text(base64.b64encode(data))
        exec_manifest[name] = b64_data

    for name, data in finder.ps_modules.items():
        b64_data = to_text(base64.b64encode(data['data']))
        exec_manifest['powershell_modules'][name] = b64_data
        coverage_manifest['module_util_paths'][name] = data['path']

    cs_utils = {}
    for cs_util in [finder.cs_utils_wrapper, finder.cs_utils_module]:
        for name, data in cs_util.items():
            cs_utils[name] = data['data']

    for name, data in cs_utils.items():


# -*- coding: utf-8 -*-
# Copyright 2019 Red Hat
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
"""
The eos_lacp_interfaces class
It is in this file where the current configuration (as dict)
is compared to the provided configuration (as dict) and the command set
necessary to bring the current configuration to it's desired end-state is
created
"""

from __future__ import (absolute_import, division, print_function)
__metaclass__ = type

from ansible.module_utils.network.common.cfg.base import ConfigBase
from ansible.module_utils.network.common.utils import to_list, dict_diff, param_list_to_dict
from ansible.module_utils.network.eos.facts.facts import Facts
from ansible.module_utils.network.eos.utils.utils import normalize_interface

class Lacp_interfaces(ConfigBase):
    """
    The eos_lacp_interfaces class
    """

    gather_subset = [
        '!all',
        '!min',
    ]

    gather_network_resources = [
        'lacp_interfaces',
    ]

    def get_lacp_interfaces_facts(self):
        """ Get the 'facts' (the current configuration)

        :rtype: A dictionary
        :returns: The current configuration as a dictionary
        """
        facts, _warnings = Facts(self._module).get_facts(self.gather_subset, self.gather_network_resources)
        lacp_interfaces_facts = facts['ansible_network_resources'].get('lacp_interfaces')
        if not lacp_interfaces_facts:
            return []
        return lacp_interfaces_facts

    def execute_module(self):
        """ Execute the module

        :rtype: A dictionary
        :returns: The result from module execution
        """
        result = {'changed': False}
        warnings = list()
        commands = list()

        existing_lacp_interfaces_facts = self.get_lacp_interfaces_facts()
        commands.extend(self.set_config(existing_lacp_interfaces_facts))
        if commands:
            if not self._module.check_mode:
                self._connection.edit_config(commands)
            result['changed'] = True
        result['commands'] = commands

        changed_lacp_interfaces_facts = self.get_lacp_interfaces_facts()

        result['before'] = existing_lacp_interfaces_facts
        if result['changed']:
            result['after'] = changed_lacp_interfaces_facts

        result['warnings'] = warnings
        return result

    def set_config(self, existing_lacp_interfaces_facts):
        """ Collect the configuration from the args passed to the module,
            collect the current configuration (as a dict from facts)

        :rtype: A list
        :returns: the commands necessary to migrate the current configuration
                  to the desired configuration
        """
        want = self._module.params['config']
        have = existing_lacp_interfaces_facts
        resp = self.set_state(want, have)
        return to_list(resp)

    def set_state(self, want, have):
        """ Select the appropriate function based on the state provided

        :param want: the desired configuration as a dictionary
        :param have: the current configuration as a dictionary
        :rtype: A list
        :returns: the commands necessary to migrate the current configuration
                  to the desired configuration
        """
        state = self._module.params['state']
        want = param_list_to_dict(want)
        have = param_list_to_dict(have)
        if state == 'overridden':
            commands = self._state_overridden(want, have)
        elif state == 'deleted':
            commands = self._state_deleted(want, have)
        elif state == 'merged':
            commands = self._state_merged(want, have)
        elif state == 'replaced':
            commands = self._state_replaced(want, have)
        return commands

    @staticmethod
    def _state_replaced(want, have):
        """ The command generator when state is replaced

        :rtype: A list
        :returns: the commands necessary to migrate the current configuration
                  to the desired configuration
        """
        commands = []
        for key, desired in want.items():
            interface_name = normalize_interface(key)
            if interface_name in have:
                extant = have[interface_name]
            else:
                extant = dict()

            add_config = dict_diff(extant, desired)
            del_config = dict_diff(desired, extant)

            commands.extend(generate_commands(key, add_config, del_config))

        return commands

    @staticmethod
    def _state_overridden(want, have):
        """ The command generator when state is overridden

        :rtype: A list
        :returns: the commands necessary to migrate the current configuration
                  to the desired configuration
        """
        commands = []
        for key, extant in have.items():
            if key in want:
                desired = want[key]
            else:
                desired = dict()

            add_config = dict_diff(extant, desired)
            del_config = dict_diff(desired, extant)

            commands.extend(generate_commands(key, add_config, del_config))

        return commands

    @staticmethod
    def _state_merged(want, have):
        """ The command generator when state is merged

        :rtype: A list
        :returns: the commands necessary to merge the provided into
                  the current configuration
        """
        commands = []
        for key, desired in want.items():
            interface_name = normalize_interface(key)
            if interface_name in have:
                extant = have[interface_name]
            else:
                extant = dict()

            add_config = dict_diff(extant, desired)

            commands.extend(generate_commands(key, add_config, {}))

        return commands

    @staticmethod
    def _state_deleted(want, have):
        """ The command generator when state is deleted

        :rtype: A list
        :returns: the commands necessary to remove the current configuration
                  of the provided objects
        """
        commands = []
        for key in want:
            desired = dict()
            if key in have:
                extant = have[key]
            else:
                continue

            del_config = dict_diff(desired, extant)

            commands.extend(generate_commands(key, {}, del_config))

        return commands

def generate_commands(interface, to_set, to_remove):
    commands = []


# Base classes for the graphical user interface.
#
# Copyright (C) 2011-2012  Red Hat, Inc.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions of
# the GNU General Public License v.2, or (at your option) any later version.
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY expressed or implied, including the implied warranties of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
# Public License for more details.  You should have received a copy of the
# GNU General Public License along with this program; if not, write to the
# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.  Any Red Hat trademarks that are incorporated in the
# source code or documentation are not subject to the GNU General Public
# License and may only be used or replicated with the express permission of
# Red Hat, Inc.
#
# Red Hat Author(s): Chris Lumens <clumens@redhat.com>
#
import inspect, os, sys, time, site, signal
import meh.ui.gui

from contextlib import contextmanager

import gi
gi.require_version("Gdk", "3.0")
gi.require_version("Gtk", "3.0")
gi.require_version("AnacondaWidgets", "3.3")
gi.require_version("Keybinder", "3.0")
gi.require_version("GdkPixbuf", "2.0")
gi.require_version("GLib", "2.0")
gi.require_version("GObject", "2.0")

from gi.repository import Gdk, Gtk, AnacondaWidgets, Keybinder, GdkPixbuf, GLib, GObject

from pyanaconda.i18n import _, C_
from pyanaconda.constants import IPMI_ABORTED, WINDOW_TITLE_TEXT
from pyanaconda import product, iutil, constants
from pyanaconda import threads

from pyanaconda.ui import UserInterface, common
from pyanaconda.ui.gui.utils import gtk_action_wait, gtk_call_once, unbusyCursor
from pyanaconda import ihelp
import os.path

import logging
log = logging.getLogger("anaconda")

__all__ = ["GraphicalUserInterface", "QuitDialog"]

_screenshotIndex = 0
_last_screenshot_timestamp = 0
SCREENSHOT_DELAY = 1  # in seconds

ANACONDA_WINDOW_GROUP = Gtk.WindowGroup()

# Stylesheet priorities to use for product-specific stylesheets.
# installclass stylesheets should be higher than our base stylesheet, and
# stylesheets from updates.img and product.img should be higher than that.  All
# levels should be lower than GTK_STYLE_PROVIDER_PRIORITY_USER.
STYLE_PROVIDER_PRIORITY_INSTALLCLASS = Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION + 15
STYLE_PROVIDER_PRIORITY_UPDATES = Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION + 20
assert STYLE_PROVIDER_PRIORITY_UPDATES < Gtk.STYLE_PROVIDER_PRIORITY_USER

class GUIObject(common.UIObject):
    """This is the base class from which all other GUI classes are derived.  It
       thus contains only attributes and methods that are common to everything
       else.  It should not be directly instantiated.

       Class attributes:

       builderObjects   -- A list of UI object names that should be extracted from
                           uiFile and exposed for this class to use.  If this list
                           is empty, all objects will be exposed.

                           Only the following kinds of objects need to be exported:

                           (1) Top-level objects (like GtkDialogs) that are directly
                           used in Python.

                           (2) Top-level objects that are not directly used in
                           Python, but are used by another object somewhere down
                           in the hierarchy.  This includes things like a custom
                           GtkImage used by a button that is part of an exported
                           dialog, and a GtkListStore that is the model of a
                           Gtk*View that is part of an exported object.
       mainWidgetName   -- The name of the top-level widget this object
                           object implements.  This will be the widget searched
                           for in uiFile by the window property.
       focusWidgetName  -- The name of the widget to focus when the object is entered,
                           or None.
       uiFile           -- The location of an XML file that describes the layout
                           of widgets shown by this object.  UI files are
                           searched for relative to the same directory as this
                           object's module.
       translationDomain-- The gettext translation domain for the given GUIObject
                           subclass. By default the "anaconda" translation domain
                           is used, but external applications, such as Initial Setup,
                           that use GUI elements (Hubs & Spokes) from Anaconda
                           can override the translation domain with their own,
                           so that their subclasses are properly translated.
       helpFile         -- The location of the yelp-compatible help file for the
                           given GUI object. The default value of "" indicates
                           that the object has not specific help file assigned
                           and the default help file should be used.
    """
    builderObjects = []
    mainWidgetName = None

    # Since many of the builder files do not define top-level widgets, the usual
    # {get,can,is,has}_{focus,default} properties don't work real good. Define the
    # widget to be focused in python, instead.
    focusWidgetName = None

    uiFile = ""
    helpFile = None
    translationDomain = "anaconda"

    handles_autostep = False

    def __init__(self, data):
        """Create a new UIObject instance, including loading its uiFile and
           all UI-related objects.

           Instance attributes:

           data     -- An instance of a pykickstart Handler object.  The Hub
                       never directly uses this instance.  Instead, it passes
                       it down into Spokes when they are created and applied.
                       The Hub simply stores this instance so it doesn't need
                       to be passed by the user.
           skipTo   -- If this attribute is set to something other than None,
                       it must be the name of a class (as a string).  Then,
                       the interface will skip to the first instance of that
                       class in the action list instead of going on to
                       whatever the next action is normally.

                       Note that actions may only skip ahead, never backwards.
                       Also, standalone spokes may not skip to an individual
                       spoke off a hub.  They can only skip to the hub
                       itself.
        """
        common.UIObject.__init__(self, data)

        if self.__class__ is GUIObject:
            raise TypeError("GUIObject is an abstract class")

        self.skipTo = None
        self.applyOnSkip = False

        self.builder = Gtk.Builder()
        self.builder.set_translation_domain(self.translationDomain)
        self._window = None

        if self.builderObjects:
            self.builder.add_objects_from_file(self._findUIFile(), self.builderObjects)
        else:
            self.builder.add_from_file(self._findUIFile())

        self.builder.connect_signals(self)

        # Keybinder from GI needs to be initialized before use
        Keybinder.init()
        Keybinder.bind("<Shift>Print", self._handlePrntScreen, [])

        self._automaticEntry = False
        self._autostepRunning = False
        self._autostepDone = False
        self._autostepDoneCallback = None

        # this indicates if the screen is the last spoke to be processed for a hub
        self.lastAutostepSpoke = False

    def _findUIFile(self):
        path = os.environ.get("UIPATH", "./:/tmp/updates/:/tmp/updates/ui/:/usr/share/anaconda/ui/")
        dirs = path.split(":")

        # append the directory where this UIObject is defined
        dirs.append(os.path.dirname(inspect.getfile(self.__class__)))

        for d in dirs:
            testPath = os.path.join(d, self.uiFile)
            if os.path.isfile(testPath) and os.access(testPath, os.R_OK):
                return testPath

        raise IOError("Could not load UI file '%s' for object '%s'" % (self.uiFile, self))

    def _handlePrntScreen(self, *args, **kwargs):
        global _last_screenshot_timestamp
        # as a single press of the assigned key generates
        # multiple callbacks, we need to skip additional
        # callbacks for some time once a screenshot is taken
        if (time.time() - _last_screenshot_timestamp) >= SCREENSHOT_DELAY:
            self.take_screenshot()
            # start counting from the time the screenshot operation is done
            _last_screenshot_timestamp = time.time()

    def take_screenshot(self, name=None):
        """Take a screenshot of the whole screen (works even with multiple displays)

        :param name: optional name for the screenshot that will be appended to the filename,
                     after the standard prefix & screenshot number
        :type name: str or NoneType
        """
        global _screenshotIndex
        # Make sure the screenshot directory exists.
        iutil.mkdirChain(constants.SCREENSHOTS_DIRECTORY)

        if name is None:
            screenshot_filename = "screenshot-%04d.png" % _screenshotIndex
        else:
            screenshot_filename = "screenshot-%04d-%s.png" % (_screenshotIndex, name)

        fn = os.path.join(constants.SCREENSHOTS_DIRECTORY, screenshot_filename)

        root_window = self.main_window.get_window()
        pixbuf = Gdk.pixbuf_get_from_window(root_window, 0, 0,
                                            root_window.get_width(),
                                            root_window.get_height())
        pixbuf.savev(fn, 'png', [], [])
        log.info("%s taken", screenshot_filename)
        _screenshotIndex += 1

    @property
    def automaticEntry(self):
        """Report if the given GUIObject has been displayed under automatic control

        This is needed for example for installations with an incomplete kickstart,
        as we need to differentiate the automatic screenshot pass from the user
        entering a spoke to manually configure things. We also need to skip applying
        changes if the spoke is entered automatically.
        """
        return self._automaticEntry

    @automaticEntry.setter
    def automaticEntry(self, value):
        self._automaticEntry = value

    @property
    def autostepRunning(self):
        """Report if the GUIObject is currently running autostep"""
        return self._autostepRunning

    @autostepRunning.setter
    def autostepRunning(self, value):
        self._autostepRunning = value

    @property
    def autostepDone(self):
        """Report if autostep for this GUIObject has been finished"""
        return self._autostepDone

    @autostepDone.setter
    def autostepDone(self, value):
        self._autostepDone = value

    @property
    def autostepDoneCallback(self):
        """A callback to be run once autostep has been finished"""
        return self._autostepDoneCallback

    @autostepDoneCallback.setter
    def autostepDoneCallback(self, callback):
        self._autostepDoneCallback = callback

    def autostep(self):
        """Autostep through this graphical object and through
        any graphical objects managed by it (such as through spokes for a hub)
        """
        # report that autostep is running to prevent another from starting
        self.autostepRunning = True
        # take a screenshot of the current graphical object
        if self.data.autostep.autoscreenshot:
            # as autostep is triggered just before leaving a screen,
            # we can safely take a screenshot of the "parent" object at once
            # without using idle_add
            self.take_screenshot(self.__class__.__name__)
        self._doAutostep()
        # done
        self.autostepRunning = False
        self.autostepDone = True
        self._doPostAutostep()

        # run the autostep-done callback (if any)
        # pylint: disable=not-callable
        if self.autostepDoneCallback:
            self.autostepDoneCallback(self)

    def _doPostAutostep(self):
        """To be overridden by the given GUIObject sub-class with custom code
        that brings the GUI from the autostepping mode back to the normal mode.
        This usually means to "click" the continue button or its equivalent.
        """
        pass

    def _doAutostep(self):
        """To be overridden by the given GUIObject sub-class with customized
        autostepping code - if needed
        (this is for example used to step through spokes in a hub)
        """
        pass

    @property
    def window(self):
        """Return the object out of the GtkBuilder representation
           previously loaded by the load method.
        """

        # This will raise an AttributeError if the subclass failed to set a
        # mainWidgetName attribute, which is exactly what I want.
        if not self._window:
            self._window = self.builder.get_object(self.mainWidgetName)

        return self._window

    @property
    def main_window(self):
        """Return the top-level window containing this GUIObject."""
        return self.window.get_toplevel()

    def clear_info(self):
        """Clear any info bar from the bottom of the screen."""
        self.window.clear_info()

    def set_error(self, msg):
        """Display an info bar along the bottom of the screen with the provided
           message.  This method is used to display critical errors anaconda
           may not be able to do anything about, but that the user may.  A
           suitable background color and icon will be displayed.
        """
        self.window.set_error(msg)

    def set_info(self, msg):
        """Display an info bar along the bottom of the screen with the provided
           message.  This method is used to display informational text -
           non-critical warnings during partitioning, for instance.  The user
           should investigate these messages but doesn't have to.  A suitable
           background color and icon will be displayed.
        """
        self.window.set_info(msg)

    def set_warning(self, msg):
        """Display an info bar along the bottom of the screen with the provided
           message.  This method is used to display errors the user needs to
           attend to in order to continue installation.  This is the bulk of
           messages.  A suitable background color and icon will be displayed.
        """
        self.window.set_warning(msg)

class QuitDialog(GUIObject):
    builderObjects = ["quitDialog"]
    mainWidgetName = "quitDialog"
    uiFile = "main.glade"

    MESSAGE = ""

    def run(self):
        if self.MESSAGE:
            self.builder.get_object("quit_message").set_label(_(self.MESSAGE))
        rc = self.window.run()
        return rc

class ErrorDialog(GUIObject):
    builderObjects = ["errorDialog", "errorTextBuffer"]
    mainWidgetName = "errorDialog"
    uiFile = "main.glade"

    # pylint: disable=arguments-differ
    def refresh(self, msg):
        buf = self.builder.get_object("errorTextBuffer")
        buf.set_text(msg, -1)

    def run(self):
        rc = self.window.run()
        return rc

class MainWindow(Gtk.Window):
    """This is a top-level, full size window containing the Anaconda screens."""

    def __init__(self, fullscreen):
        """Create a new anaconda main window.

          :param bool fullscreen: if True, fullscreen the window, if false maximize
        """
        Gtk.Window.__init__(self)

        # Hide the titlebar when maximized if the window manager allows it.
        # This makes anaconda look full-screenish but without covering parts
        # needed to interact with the window manager, like the GNOME top bar.
        self.set_hide_titlebar_when_maximized(True)

        # The Anaconda and Initial Setup windows might sometimes get decorated with
        # a titlebar which contains the __init__.py header text by default.
        # As all Anaconda and Initial Setup usually have a very distinct title text
        # inside the window, the titlebar text is redundant and should be disabled.
        self.set_title(_(WINDOW_TITLE_TEXT))

        # Set the icon used in the taskbar of window managers that have a taskbar
        # The "anaconda" icon is part of fedora-logos
        self.set_icon_name("anaconda")

        # Treat an attempt to close the window the same as hitting quit
        self.connect("delete-event", self._on_delete_event)

        # Create a black, 50% opacity pixel that will be scaled to fit the lightbox overlay
        # The confusing list of unnamed parameters is:
        # bytes, colorspace (there is no other colorspace), has-alpha,
        # bits-per-sample (has to be 8), width, height,
        # rowstride (bytes between row starts, but we only have one row)
        self._transparent_base = GdkPixbuf.Pixbuf.new_from_bytes(GLib.Bytes.new([0, 0, 0, 127]),
                GdkPixbuf.Colorspace.RGB, True, 8, 1, 1, 1)

        # Contain everything in an overlay so the window can be overlayed with the transparency
        # for the lightbox effect
        self._overlay = Gtk.Overlay()
        self._overlay_img = None
        self._overlay.connect("get-child-position", self._on_overlay_get_child_position)

        self._overlay_depth = 0

        # Create a stack and a list of what's been added to the stack
        # Double the stack transition duration since the default 200ms is too
        # quick to get the point across
        self._stack = Gtk.Stack(transition_duration=400)
        self._stack_contents = set()

        # Create an accel group for the F12 accelerators added after window transitions
        self._accel_group = Gtk.AccelGroup()
        self.add_accel_group(self._accel_group)

        # Make the window big
        if fullscreen:
            self.fullscreen()
        else:
            self.maximize()

        self._overlay.add(self._stack)
        self.add(self._overlay)
        self.show_all()

        self._current_action = None

        # Help button mnemonics handling
        self._mnemonic_signal = None
        # we have a sensible initial value, just in case
        self._saved_help_button_label = _("Help!")

    def _on_delete_event(self, widget, event, user_data=None):
        # Use the quit-clicked signal on the the current standalone, even if the
        # standalone is not currently displayed.
        if self.current_action:
            self.current_action.window.emit("quit-clicked")

        # Stop the window from being closed here
        return True

    def _on_overlay_get_child_position(self, overlay_container, overlayed_widget, allocation, user_data=None):
        overlay_allocation = overlay_container.get_allocation()

        # Scale the overlayed image's pixbuf to the size of the GtkOverlay
        overlayed_widget.set_from_pixbuf(self._transparent_base.scale_simple(
            overlay_allocation.width, overlay_allocation.height, GdkPixbuf.InterpType.NEAREST))

        # Return False to indicate that the child allocation is not yet set
        return False

    def _on_mnemonics_visible_changed(self, window, property_type, obj):
        # mnemonics display has been activated or deactivated,
        # add or remove the F1 mnemonics display from the help button
        help_button = obj.window.get_help_button()
        if window.props.mnemonics_visible:
            # save current label
            old_label = help_button.get_label()
            self._saved_help_button_label = old_label
            # add the (F1) "mnemonics" to the help button
            help_button.set_label("%s (F1)" % old_label)
        else:
            # restore the old label
            help_button.set_label(self._saved_help_button_label)

    @property
    def current_action(self):
        return self._current_action

    def _setVisibleChild(self, child):
        # Remove the F12 accelerator from the old window
        old_screen = self._stack.get_visible_child()
        if old_screen:
            old_screen.remove_accelerator(self._accel_group, Gdk.KEY_F12, 0)
            old_screen.remove_accelerator(self._accel_group, Gdk.KEY_F1, 0)
            old_screen.remove_accelerator(self._accel_group, Gdk.KEY_F1, Gdk.ModifierType.MOD1_MASK)

        # Check if the widget is already on the stack
        if child not in self._stack_contents:
            self._stack.add(child.window)
            self._stack_contents.add(child)
            child.window.show_all()

        # It would be handy for F12 to continue to work like it did in the old
        # UI, by skipping you to the next screen or sending you back to the hub
        if isinstance(child.window, AnacondaWidgets.BaseStandalone):
            child.window.add_accelerator("continue-clicked", self._accel_group,
                    Gdk.KEY_F12, 0, 0)
        elif isinstance(child.window, AnacondaWidgets.SpokeWindow):
            child.window.add_accelerator("button-clicked", self._accel_group,
                    Gdk.KEY_F12, 0, 0)

        # Configure the help button
        child.window.add_accelerator("help-button-clicked", self._accel_group,
                Gdk.KEY_F1, 0, 0)
        child.window.add_accelerator("help-button-clicked", self._accel_group,
                Gdk.KEY_F1, Gdk.ModifierType.MOD1_MASK, 0)

        # Connect to mnemonics-visible to add the (F1) mnemonic to the button label
        if self._mnemonic_signal:
            self.disconnect(self._mnemonic_signal)
        self._mnemonic_signal = self.connect("notify::mnemonics-visible", self._on_mnemonics_visible_changed, child)

        self._stack.set_visible_child(child.window)

        if child.focusWidgetName:
            child.builder.get_object(child.focusWidgetName).grab_focus()

    def setCurrentAction(self, standalone):
        """Set the current standalone widget.

           This changes the currently displayed screen and, if the standalone
           is a hub, sets the hub as the screen to which spokes will return.

           :param AnacondaWidgets.BaseStandalone standalone: the new standalone action
        """
        # Slide the old hub/standalone off of the new one
        self._stack.set_transition_type(Gtk.StackTransitionType.UNDER_LEFT)

        self._current_action = standalone
        self._setVisibleChild(standalone)

    def enterSpoke(self, spoke):
        """Enter a spoke.

           The spoke will be displayed as the current screen, but the current-action
           to which the spoke will return will not be changed.

           :param AnacondaWidgets.SpokeWindow spoke: a spoke to enter
        """
        # Slide up, as if the spoke is under the hub
        self._stack.set_transition_type(Gtk.StackTransitionType.UNDER_UP)

        self._setVisibleChild(spoke)

        # autostep through the spoke if required
        if spoke.automaticEntry:
            # we need to use idle_add here to give GTK time to render the spoke
            gtk_call_once(self._autostep_spoke, spoke)

    def _autostep_spoke(self, spoke):
        """Step through a spoke and make a screenshot if required.
        If this is the last spoke to be autostepped on a hub return to
        the hub so that we can proceed to the next one.
        """
        # it might be possible that autostep is specified, but autoscreenshot isn't
        if spoke.data.autostep.autoscreenshot:
            spoke.take_screenshot(spoke.__class__.__name__)

        if spoke.autostepDoneCallback:
            spoke.autostepDoneCallback(spoke)

        # if this is the last spoke then return to hub
        if spoke.lastAutostepSpoke:
            self.returnToHub()

    def returnToHub(self):
        """Exit a spoke and return to a hub."""
        # Slide back down over the spoke
        self._stack.set_transition_type(Gtk.StackTransitionType.OVER_DOWN)

        self._setVisibleChild(self._current_action)

    def lightbox_on(self):
        self._overlay_depth += 1
        if not self._overlay_img:
            # Add an overlay image that will be filled and scaled in get-child-position
            self._overlay_img = Gtk.Image()
            self._overlay_img.show_all()
            self._overlay.add_overlay(self._overlay_img)

    def lightbox_off(self):
        self._overlay_depth -= 1
        if self._overlay_depth == 0 and self._overlay_img:
            # Remove the overlay image
            self._overlay_img.destroy()
            self._overlay_img = None

    @contextmanager
    def enlightbox(self, dialog):
        """Display a dialog in a lightbox over the main window.

           :param GtkDialog: the dialog to display
        """
        self.lightbox_on()

        # Set the dialog as transient for ourself
        ANACONDA_WINDOW_GROUP.add_window(dialog)
        dialog.set_position(Gtk.WindowPosition.CENTER_ALWAYS)
        dialog.set_transient_for(self)

        yield

        self.lightbox_off()

class GraphicalUserInterface(UserInterface):
    """This is the standard GTK+ interface we try to steer everything to using.
       It is suitable for use both directly and via VNC.
    """
    def __init__(self, storage, payload, instclass,
                 distributionText=product.distributionText, isFinal=product.isFinal,
                 quitDialog=QuitDialog, gui_lock=None, fullscreen=False):

        UserInterface.__init__(self, storage, payload, instclass)

        self._actions = []
        self._currentAction = None
        self._ui = None
        self._gui_lock = gui_lock

        self.data = None

        self.mainWindow = MainWindow(fullscreen=fullscreen)

        self._distributionText = distributionText
        self._isFinal = isFinal
        self._quitDialog = quitDialog
        self._mehInterface = GraphicalExceptionHandlingIface(
                                    self.mainWindow.lightbox_on)

        ANACONDA_WINDOW_GROUP.add_window(self.mainWindow)

    basemask = "pyanaconda.ui"
    basepath = os.path.dirname(os.path.dirname(__file__))
    updatepath = "/tmp/updates/pyanaconda/ui"
    sitepackages = [os.path.join(dir, "pyanaconda", "ui")
                    for dir in site.getsitepackages()]
    pathlist = set([updatepath, basepath] + sitepackages)

    _categories = []
    _spokes = []
    _hubs = []

    # as list comprehension can't reference class level variables in Python 3 we
    # need to use a for cycle (http://bugs.python.org/issue21161)
    for path in pathlist:
        _categories.append((basemask + ".categories.%s", os.path.join(path, "categories")))
        _spokes.append((basemask + ".gui.spokes.%s", os.path.join(path, "gui/spokes")))
        _hubs.append((basemask + ".gui.hubs.%s", os.path.join(path, "gui/hubs")))

    paths = UserInterface.paths + {
        "categories": _categories,
        "spokes": _spokes,
        "hubs": _hubs,
    }

    def _widgetScale(self):
        # First, check if the GDK_SCALE environment variable is already set. If so,
        # leave it alone.
        if "GDK_SCALE" in os.environ:
            log.debug("GDK_SCALE already set to %s, not scaling", os.environ["GDK_SCALE"])
            return

        # Next, check if a scaling factor is already being applied via XSETTINGS,
        # such as by gnome-settings-daemon
        display = Gdk.Display.get_default()
        screen = display.get_default_screen()
        val = GObject.Value()
        val.init(GObject.TYPE_INT)
        if screen.get_setting("gdk-window-scaling-factor", val):
            log.debug("Window scale set to %s by XSETTINGS, not scaling", val.get_int())
            return

        # Get the primary monitor dimensions in pixels and mm from Gdk
        primary = screen.get_primary_monitor()
        monitor_geometry = screen.get_monitor_geometry(primary)
        monitor_scale = screen.get_monitor_scale_factor(primary)
        monitor_width_mm = screen.get_monitor_width_mm(primary)
        monitor_height_mm = screen.get_monitor_height_mm(primary)

        # Sometimes gdk returns 0 for physical widths and heights
        if monitor_height_mm == 0 or monitor_width_mm == 0:
            return

        # Check if this monitor is high DPI, using heuristics from gnome-settings-dpi.
        # If the monitor has a height >= 1200 pixels and a resolution > 192 dpi in both
        # x and y directions, apply a scaling factor of 2 so that anaconda isn't all tiny
        monitor_width_px = monitor_geometry.width * monitor_scale
        monitor_height_px = monitor_geometry.height * monitor_scale
        monitor_dpi_x = monitor_width_px / (monitor_width_mm / 25.4)
        monitor_dpi_y = monitor_height_px / (monitor_height_mm / 25.4)

        log.debug("Detected primary monitor: %dx%d %ddpix %ddpiy", monitor_width_px,
                monitor_height_px, monitor_dpi_x, monitor_dpi_y)
        if monitor_height_px >= 1200 and monitor_dpi_x > 192 and monitor_dpi_y > 192:
            display.set_window_scale(2)
            # Export the scale so that Gtk programs launched by anaconda are also scaled
            iutil.setenv("GDK_SCALE", "2")

    def _convertSignals(self):
        # What tends to happen when we receive a signal is that the signal will
        # be received by the python interpreter's C handler, python will do
        # what it needs to do to set the python handler we registered to run,
        # the C handler returns, and then nothing happens because Gtk is
        # holding the global interpreter lock. The signal then gets delivered
        # to our python code when you move the mouse or something. We can get
        # around this by doing signals the GLib way. The conversion assumes
        # that none of our signal handlers care about the frame parameter,
        # which is generally true.
        #
        # After the unix_signal_add call, signal.getsignal will tell a half
        # truth: the method returned will still be called, by way of
        # _signal_converter, but GLib will have replaced the actual signal
        # handler for that signal.

        # Convert everything except SIGCHLD, because that's a different can of worms

        def _signal_converter(user_data):
            (handler, signum) = user_data
            handler(signum, None)

        for signum in (s for s in range(1, signal.NSIG) if s != signal.SIGCHLD):
            handler = signal.getsignal(signum)
            if handler and handler not in (signal.SIG_DFL, signal.SIG_IGN):
                # NB: if you are looking at the glib documentation you are in for
                # some surprises because gobject-introspection is a minefield.
                # g_unix_signal_add_full comes out as GLib.unix_signal_add, and
                # g_unix_signal_add doesn't come out at all.
                GLib.unix_signal_add(GLib.PRIORITY_DEFAULT, signum,
                        _signal_converter, (handler, signum))

    @property
    def tty_num(self):
        return 6

    @property
    def meh_interface(self):
        return self._mehInterface

    def _list_hubs(self):
        """Return a list of Hub classes to be imported to this interface"""
        from pyanaconda.ui.gui.hubs.summary import SummaryHub
        from pyanaconda.ui.gui.hubs.progress import ProgressHub
        return [SummaryHub, ProgressHub]

    def _is_standalone(self, obj):
        """Is the spoke passed as obj standalone?"""
        from pyanaconda.ui.gui.spokes import StandaloneSpoke
        return isinstance(obj, StandaloneSpoke)

    def setup(self, data):
        self._actions = self.getActionClasses(self._list_hubs())
        self.data = data

    def getActionClasses(self, hubs):
        """Grab all relevant standalone spokes, add them to the passed
           list of hubs and order the list according to the
           relationships between hubs and standalones."""
        from pyanaconda.ui.gui.spokes import StandaloneSpoke

        # First, grab a list of all the standalone spokes.
        standalones = self._collectActionClasses(self.paths["spokes"], StandaloneSpoke)

        # Second, order them according to their relationship
        return self._orderActionClasses(standalones, hubs)

    def _instantiateAction(self, actionClass):
        # Instantiate an action on-demand, passing the arguments defining our
        # spoke API and setting up continue/quit signal handlers.
        obj = actionClass(self.data, self.storage, self.payload, self.instclass)

        # set spoke search paths in Hubs
        if hasattr(obj, "set_path"):
            obj.set_path("spokes", self.paths["spokes"])
            obj.set_path("categories", self.paths["categories"])

        # If we are doing a kickstart install, some standalone spokes
        # could already be filled out.  In that case, we do not want
        # to display them.
        if self._is_standalone(obj) and obj.completed:
            del(obj)
            return None

        # Use connect_after so classes can add actions before we change screens
        obj.window.connect_after("continue-clicked", self._on_continue_clicked)
        obj.window.connect_after("help-button-clicked", self._on_help_clicked, obj)
        obj.window.connect_after("quit-clicked", self._on_quit_clicked)

        return obj

    def run(self):
        (success, _args) = Gtk.init_check(None)
        if not success:
            raise RuntimeError("Failed to initialize Gtk")

        # Check if the GUI lock has already been taken
        if self._gui_lock and not self._gui_lock.acquire(False):
            # Gtk main loop running. That means python-meh caught exception
            # and runs its main loop. Do not crash Gtk by running another one
            # from a different thread and just wait until python-meh is
            # finished, then quit.
            unbusyCursor()
            log.error("Unhandled exception caught, waiting for python-meh to "\
                      "exit")

            threads.threadMgr.wait_for_error_threads()
            sys.exit(1)

        try:
            # Apply a widget-scale to hidpi monitors
            self._widgetScale()

            while not self._currentAction:
                self._currentAction = self._instantiateAction(self._actions[0])
                if not self._currentAction:
                    self._actions.pop(0)

                if not self._actions:
                    return

            self._currentAction.initialize()
            self._currentAction.entry_logger()
            self._currentAction.refresh()

            self._currentAction.window.set_beta(not self._isFinal)
            self._currentAction.window.set_property("distribution", self._distributionText().upper())

            # Set some program-wide settings.
            settings = Gtk.Settings.get_default()
            settings.set_property("gtk-font-name", "Cantarell")
            settings.set_property("gtk-icon-theme-name", "gnome")

            # Apply the application stylesheet
            css_path = os.environ.get("ANACONDA_DATA", "/usr/share/anaconda")
            css_path = os.path.join(css_path, "anaconda-gtk.css")
            provider = Gtk.CssProvider()
            provider.load_from_path(css_path)
            Gtk.StyleContext.add_provider_for_screen(Gdk.Screen.get_default(), provider,
                    Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)

            # Apply the installclass stylesheet
            if self.instclass.stylesheet:
                provider = Gtk.CssProvider()
                provider.load_from_path(self.instclass.stylesheet)
                Gtk.StyleContext.add_provider_for_screen(Gdk.Screen.get_default(), provider,
                        STYLE_PROVIDER_PRIORITY_INSTALLCLASS)

            # Look for updates to the stylesheet and apply them at a higher priority
            for updates_dir in ("updates", "product"):
                updates_css = "/run/install/%s/anaconda-gtk.css" % updates_dir
                if os.path.exists(updates_css):
                    provider = Gtk.CssProvider()
                    provider.load_from_path(updates_css)
                    Gtk.StyleContext.add_provider_for_screen(Gdk.Screen.get_default(), provider,
                            STYLE_PROVIDER_PRIORITY_UPDATES)

            self.mainWindow.setCurrentAction(self._currentAction)

            # Do this at the last possible minute.
            unbusyCursor()
        # If anything went wrong before we start the Gtk main loop, release
        # the gui lock and re-raise the exception so that meh can take over
        except Exception:
            self._gui_lock.release()
            raise

        Gtk.main()

    ###
    ### MESSAGE HANDLING METHODS
    ###
    @gtk_action_wait
    def showError(self, message):


# Copyright (C) 2014-2015 The BET Development Team

"""
This module provides methods for plotting probabilities.
"""

from bet.Comm import comm, MPI
import matplotlib.pyplot as plt
#plt.rc('text', usetex=True)
#plt.rc('font', family='serif')
import numpy as np
import copy, math

def calculate_1D_marginal_probs(P_samples, samples, lam_domain, nbins=20):

    """
    This calculates every single marginal of
    input probability measure defined by P_samples on a 1D grid.

    :param P_samples: Probabilities.
    :type P_samples: :class:`~numpy.ndarray` of shape (num_samples,)
    :param samples: The samples in parameter space for which the model was run.
    :type samples: :class:`~numpy.ndarray` of shape (num_samples, ndim)
    :param lam_domain: The domain for each parameter for the model.
    :type lam_domain: :class:`~numpy.ndarray` of shape (ndim, 2)
    :param nbins: Number of bins in each direction.
    :type nbins: :int or :class:`~numpy.ndarray` of shape (ndim,)
    :rtype: tuple
    :returns: (bins, marginals)

    """
    if len(samples.shape) == 1:
        samples = np.expand_dims(samples, axis=1)
    num_dim = samples.shape[1]

    # Make list of bins if only an integer is given
    if isinstance(nbins, int):
        nbins = nbins*np.ones(num_dim, dtype=np.int)

    # Create bins
    bins = []
    for i in range(num_dim):
        bins.append(np.linspace(lam_domain[i][0], lam_domain[i][1], nbins[i]+1))

    # Calculate marginals
    marginals = {}
    for i in range(num_dim):
        [marg, _] = np.histogram(samples[:, i], bins=bins[i],
                                 weights=P_samples)
        marg_temp = np.copy(marg)
        comm.Allreduce([marg, MPI.DOUBLE], [marg_temp, MPI.DOUBLE], op=MPI.SUM)
        marginals[i] = marg_temp

    return (bins, marginals)

def calculate_2D_marginal_probs(P_samples, samples, lam_domain, nbins=20):

    """
    This calculates every pair of marginals (or joint in 2d case) of
    input probability measure defined by P_samples on a rectangular grid.

    :param P_samples: Probabilities.
    :type P_samples: :class:`~numpy.ndarray` of shape (num_samples,)
    :param samples: The samples in parameter space for which the model was run.
    :type samples: :class:`~numpy.ndarray` of shape (num_samples, ndim)
    :param lam_domain: The domain for each parameter for the model.
    :type lam_domain: :class:`~numpy.ndarray` of shape (ndim, 2)
    :param nbins: Number of bins in each direction.
    :type nbins: :int or :class:`~numpy.ndarray` of shape (ndim,)
    :rtype: tuple
    :returns: (bins, marginals)

    """
    if len(samples.shape) == 1:
        samples = np.expand_dims(samples, axis=1)
    num_dim = samples.shape[1]

    # Make list of bins if only an integer is given
    if isinstance(nbins, int):
        nbins = nbins*np.ones(num_dim, dtype=np.int)

    # Create bins
    bins = []
    for i in range(num_dim):
        bins.append(np.linspace(lam_domain[i][0], lam_domain[i][1], nbins[i]+1))

    # Calculate marginals
    marginals = {}
    for i in range(num_dim):
        for j in range(i+1, num_dim):
            (marg, _) = np.histogramdd(samples[:, [i, j]], bins=[bins[i],
                                       bins[j]], weights=P_samples)
            marg = np.ascontiguousarray(marg)
            marg_temp = np.copy(marg)
            comm.Allreduce([marg, MPI.DOUBLE], [marg_temp, MPI.DOUBLE],
                    op=MPI.SUM)
            marginals[(i, j)] = marg_temp

    return (bins, marginals)

def plot_1D_marginal_probs(marginals, bins, lam_domain,
        filename="file", lam_ref=None, interactive=False,
        lambda_label=None):

    """
    This makes plots of every single marginal probability of
    input probability measure defined by P_samples on a 1D  grid.

    :param marginals: 1D marginal probabilities
    :type marginals: dictionary with int as keys and :class:`~numpy.ndarray` of
        shape (nbins+1,) as values :param bins: Endpoints of bins used in
        calculating marginals
    :type bins: :class:`~numpy.ndarray` of shape (nbins+1,)
    :param lam_domain: The domain for each parameter for the model.
    :type lam_domain: :class:`~numpy.ndarray` of shape (ndim, 2)
    :param filename: Prefix for output files.
    :type filename: str
    :param lam_ref: True parameters.
    :type lam_ref: :class:`~numpy.ndarray` of shape (ndim,) or None
    :param interactive: Whether or not to display interactive plots.
    :type interactive: bool
    :param lambda_label: Label for each parameter for plots.
    :type lambda_label: list of length nbins of strings or None

    """
    if comm.rank == 0:
        index = copy.deepcopy(marginals.keys())
        index.sort()
        for i in index:
            x_range = np.linspace(lam_domain[i, 0], lam_domain[i, 1],
                    len(bins[i])-1)
            fig = plt.figure(i)
            ax = fig.add_subplot(111)
            ax.plot(x_range, marginals[i]/(bins[i][1]-bins[i][0]))
            ax.set_ylim([0, 1.05*np.max(marginals[i]/(bins[i][1]-bins[i][0]))])
            if lam_ref is not None:
                ax.plot(lam_ref[i], 0.0, 'ko', markersize=10)
            if lambda_label == None:
                label1 = r'$\lambda_{' + str(i+1) + '}$'
            else:
                label1 = lambda_label[i]
            ax.set_xlabel(label1)
            ax.set_ylabel(r'$\rho$')
            fig.savefig(filename + "_1D_" + str(i) + ".eps", transparent=True)
            if interactive:
                plt.show()
            else:
                plt.close()
            plt.clf()

def plot_2D_marginal_probs(marginals, bins, lam_domain,
        filename="file", lam_ref=None, plot_surface=False, interactive=False,
        lambda_label=None):

    """
    This makes plots of every pair of marginals (or joint in 2d case) of
    input probability measure defined by P_samples on a rectangular grid.

    :param marginals: 2D marginal probabilities
    :type marginals: dictionary with tuples of 2 integers as keys and
        :class:`~numpy.ndarray` of shape (nbins+1,) as values
    :param bins: Endpoints of bins used in calculating marginals
    :type bins: :class:`~numpy.ndarray` of shape (nbins+1,2)
    :param lam_domain: The domain for each parameter for the model.
    :type lam_domain: :class:`~numpy.ndarray` of shape (ndim, 2)
    :param filename: Prefix for output files.
    :type filename: str
    :param lam_ref: True parameters.
    :type lam_ref: :class:`~numpy.ndarray` of shape (ndim,) or None
    :param interactive: Whether or not to display interactive plots.
    :type interactive: bool
    :param lambda_label: Label for each parameter for plots.
    :type lambda_label: list of length nbins of strings or None

    """
    '''
    marginals_list = []
    for key,value in marginals.iteritems():
        temp=[value]
        marginals_list.append(temp)
    marginals_array = np.resize(np.array(marginals_list), [bins[0].shape[0]-1, bins[0].shape[0]-1])
    marginals_array = np.round(marginals_array + .49999)
    key = marginals.keys()
    marginals[key[0]] = marginals_array
    '''

    from matplotlib import cm
    if plot_surface:
        from mpl_toolkits.mplot3d import Axes3D
        from matplotlib.ticker import LinearLocator, FormatStrFormatter
    if comm.rank == 0:
        pairs = copy.deepcopy(marginals.keys())
        pairs.sort()
        for k, (i, j) in enumerate(pairs):
            fig = plt.figure(k)
            ax = fig.add_subplot(111)
            boxSize = (bins[i][1]-bins[i][0])*(bins[j][1]-bins[j][0])
            quadmesh = ax.imshow(marginals[(i, j)].transpose()/boxSize,
                    interpolation='bicubic', cmap=cm.CMRmap_r,
                    extent=[lam_domain[i][0], lam_domain[i][1],
                    lam_domain[j][0], lam_domain[j][1]], origin='lower',
                    vmax=marginals[(i, j)].max()/boxSize, vmin=0, aspect='auto')
            if lam_ref is not None:
                ax.plot(lam_ref[i], lam_ref[j], 'wo', markersize=10)
            if lambda_label == None:
                label1 = r'$\lambda_{' + str(i+1) + '}$'
                label2 = r'$\lambda_{' + str(j+1) + '}$'
            else:
                label1 = lambda_label[i]
                label2 = lambda_label[j]
            ax.set_xlabel(label1)
            ax.set_ylabel(label2)
            label_cbar = r'$\rho_{\lambda_{' + str(i+1) + '}, '
            label_cbar += r'\lambda_{' + str(j+1) + '}' + '}$ (Lesbesgue)'
            #fig.colorbar(quadmesh, ax=ax, label=label_cbar)
            plt.axis([lam_domain[i][0], lam_domain[i][1], lam_domain[j][0],
                lam_domain[j][1]])
            fig.savefig(filename + "_2D_" + str(i) + "_" + str(j) + ".eps",
                        transparent=True)
            if interactive:
                plt.show()
            else:
                plt.close()

        if plot_surface:
            for k, (i, j) in enumerate(pairs):
                fig = plt.figure(k)
                ax = fig.gca(projection='3d')
                X = bins[i]
                Y = bins[j]
                X, Y = np.meshgrid(X, Y, indexing='ij')
                surf = ax.plot_surface(X, Y, marginals[(i, j)], rstride=1,
                        cstride=1, cmap=cm.coolwarm, linewidth=0,
                        antialiased=False)
                ax.zaxis.set_major_locator(LinearLocator(10))
                ax.zaxis.set_major_formatter(FormatStrFormatter('%.02f'))
                ax.set_xlabel(r'$\lambda_{' + str(i+1) + '}$')
                ax.set_ylabel(r'$\lambda_{' + str(j+1) + '}$')
                ax.set_zlabel(r'$P$')
                plt.backgroundcolor = 'w'
                fig.colorbar(surf, shrink=0.5, aspect=5, label=r'$P$')
                fig.savefig(filename + "_surf_"+str(i)+"_"+str(j)+".eps",
                            transparent=True)
                if interactive:
                    plt.show()
                else:
                    plt.close()
                plt.clf()

def smooth_marginals_1D(marginals, bins, sigma=10.0):
    """
    This function smooths 1D marginal probabilities.

    :param marginals: 1D marginal probabilities
    :type marginals: dictionary with int as keys and :class:`~numpy.ndarray` of
        shape (nbins+1,) as values
    :param bins: Endpoints of bins used in calculating marginals
    :type bins: :class:`~numpy.ndarray` of shape (nbins+1,)
    :param sigma: Smoothing parameter in each direction.
    :type sigma: float or :class:`~numpy.ndarray` of shape (ndim,)
    :rtype: dict
    :returns: marginals_smooth
    """
    from scipy.fftpack import fftshift, ifft, fft

    if isinstance(sigma, float):
        sigma = sigma*np.ones(len(bins), dtype=np.int)
    marginals_smooth = {}
    index = copy.deepcopy(marginals.keys())
    index.sort()
    for i in index:
        nx = len(bins[i])-1
        dx = bins[i][1] - bins[i][0]
        augx = math.ceil(3*sigma[i]/dx)
        x_kernel = np.linspace(-nx*dx/2, nx*dx/2, nx)
        kernel = np.exp(-(x_kernel/sigma[i])**2)
        aug_kernel = np.zeros((nx+2*augx,))


import numpy as np
from numpy.linalg import norm
from numpy.random import random
#from polytope_conversion_utils import cone_span_to_face
from pinocchio_inv_dyn.robot_wrapper import RobotWrapper
import pinocchio as se3
from pinocchio.utils import zero as zeros
from acc_bounds_util_multi_dof import computeAccLimits
from sot_utils import compute6dContactInequalities, crossMatrix
from first_order_low_pass_filter import FirstOrderLowPassFilter
#from convex_hull_util import compute_convex_hull, plot_convex_hull
from geom_utils import plot_polytope
#from multi_contact.utils import compute_GIWC, compute_support_polygon

EPS = 1e-4;

class InvDynFormulation (object):
    name = '';
    verb = 0;

    ENABLE_JOINT_LIMITS         = True;
    ENABLE_CAPTURE_POINT_LIMITS = False;
    ENABLE_TORQUE_LIMITS        = True;
    ENABLE_FORCE_LIMITS         = True;

    USE_JOINT_VELOCITY_ESTIMATOR = False;
    BASE_VEL_FILTER_CUT_FREQ = 5;
    JOINT_VEL_ESTIMATOR_DELAY = 0.02;
    COMPUTE_SUPPORT_POLYGON = 1;

    ACCOUNT_FOR_ROTOR_INERTIAS = True;

    JOINT_FRICTION_COMPENSATION_PERCENTAGE = 1.0;
    MAX_JOINT_ACC = 100.0;      # maximum acceleration upper bound
    MAX_MIN_JOINT_ACC = 10.0;   # maximum acceleration lower bound
    JOINT_POS_PREVIEW = 1; # preview window to convert joint pos limits into joint acc limits
    JOINT_VEL_PREVIEW = 1;  # preview window to convert joint vel limits into joint acc limits

    na=0;    # number of actuated joints
    nq=0;    # number of position DoFs
    nv=0;   # number of velocity DoFs
    m_in=0; # number of inequalities
    k=0;    # number of contact constraints (i.e. size of contact force vector)

    ind_force_in = [];  # indeces of force inequalities
    ind_acc_in = [];    # indeces of acceleration inequalities
    ind_cp_in = [];     # indeces of capture point inequalities

    tauMax=[];  # torque limits

    dt = 0;     # time step used to compute joint acceleration bounds
    qMin = [];  # joint lower bounds
    qMax = [];  # joint upper bounds
    dqMax = []; # max joint velocities
    ddqMax = []; # max joint accelerations

    ddqMaxFinal = [];   # max joint accelerations resulting from pos/vel/acc limits
    ddqMinFinal = [];   # min joint accelerations resulting from pos/vel/acc limits

    ''' Classic inverse dynamics formulation
            minimize    ||A*y-a||^2
            subject to  B*y+b >= 0
                        dynamics(y) = 0
        where y=[dv, f, tau]
    '''
    A = [];
    a = [];
    B = [];
    b = [];

    ''' Mapping between y and tau: y = C*tau+c '''
    C = [];
    c = [];

    ''' Reformulation of the inverse dynamics optimization problem
        in terms of tau only:
            minimize    ||D*tau-d||^2
            subject to  G*tau+g >= 0
    '''
    D = [];
    d = [];
    G = [];
    g = [];

    M = [];         # mass matrix
    h = [];         # dynamic drift
    q = [];
    v = [];

    x_com = [];     # com 3d position
    dx_com = [];    # com 3d velocity
    ddx_com = [];   # com 3d acceleration
    cp = [];        # capture point

    J_com = [];     # com Jacobian
    Jc = [];        # contact Jacobian
    x_c = [];       # contact points
    dx_c = [];      # contact points velocities

    Minv = [];      # inverse of the mass matrix
    Jc_Minv = [];   # Jc*Minv
    Lambda_c = [];  # task-space mass matrix (Jc*Minv*Jc^T)^-1
    Jc_T_pinv = []; # Lambda_c*Jc_Minv
    Nc_T = [];      # I - Jc^T*Jc_T_pinv
    S_T = [];       # selection matrix
    dJc_v = [];     # product of contact Jacobian time derivative and velocity vector: dJc*v

    rigidContactConstraints = [];   # tasks associated to the contact constraints
    rigidContactConstraints_p = []; # contact points in local frame
    rigidContactConstraints_N = []; # contact normals in local frame
    rigidContactConstraints_fMin = [];  # minimum normal forces
    rigidContactConstraints_mu = [];    # friction coefficients
    rigidContactConstraints_m_in = [];  # number of inequalities
    bilateralContactConstraints = [];

    tasks = [];
    task_weights = [];

    B_sp = None;     # 2d support polygon: B_sp*x + b_sp >= 0
    b_sp = None;
    support_polygon_computed = False;

    contact_points = None;  # 3xN matrix containing the contact points in world frame
    contact_normals = None; # 3xN matrix containing the contact normals in world frame

    def updateInequalityData(self, updateConstrainedDynamics=True, doNotUpdateForceLimits=False):
        self.updateSupportPolygon();

        self.m_in = 0;                              # number of inequalities
        c = len(self.rigidContactConstraints);      # number of unilateral contacts
        self.k = int(np.sum([con.dim for con in self.rigidContactConstraints]));
        self.k += int(np.sum([con.dim for con in self.bilateralContactConstraints]));
        if(doNotUpdateForceLimits==False):
            if(self.ENABLE_FORCE_LIMITS):
                self.rigidContactConstraints_m_in = np.zeros(c, np.int);
                Bf = zeros((0,self.k));
                bf = zeros(0);
                ii = 0;
                for i in range(c):
                    (Bfi, bfi) = self.createContactForceInequalities(self.rigidContactConstraints_fMin[i], self.rigidContactConstraints_mu[i], \
                                                                     self.rigidContactConstraints_p[i], self.rigidContactConstraints_N[i], \
                                                                     self.rigidContactConstraints[i].framePosition().rotation);
                    self.rigidContactConstraints_m_in[i] = Bfi.shape[0];
                    tmp = zeros((Bfi.shape[0], self.k));
                    dim = self.rigidContactConstraints[i].dim;
                    mask = self.rigidContactConstraints[i]._mask;
                    tmp[:,ii:ii+dim] = Bfi[:,mask];
                    ii += dim;
                    Bf = np.vstack((Bf, tmp));
                    bf = np.vstack((bf, bfi));
                self.ind_force_in = range(self.m_in, self.m_in + np.sum(self.rigidContactConstraints_m_in));
                self.m_in += np.sum(self.rigidContactConstraints_m_in);
            else:
                self.ind_force_in = [];
        elif(self.ENABLE_FORCE_LIMITS):
            self.m_in += np.sum(self.rigidContactConstraints_m_in);

        if(self.ENABLE_JOINT_LIMITS):
            self.ind_acc_in = range(self.m_in, self.m_in+2*self.na);
            self.m_in += 2*self.na;
        else:
            self.ind_acc_in = [];

        if(self.ENABLE_TORQUE_LIMITS):
            self.lb = -self.tauMax;
            self.ub = self.tauMax;
        else:
            self.lb = zeros(self.na) - 1e100;
            self.ub = zeros(self.na) + 1e100;

        if(self.ENABLE_CAPTURE_POINT_LIMITS):
            self.ind_cp_in = range(self.m_in, self.m_in+self.b_sp.size);
            self.m_in += self.b_sp.size;
        else:
            self.ind_cp_in = [];

        (A,a) = self.computeConstraintTasks(0.0);
        if(A.shape[0]>0):
            self.ind_task_constr = range(self.m_in, self.m_in+A.shape[0]);
            self.m_in += A.shape[0];
        else:
            self.ind_task_constr = [];

        if(doNotUpdateForceLimits):
            B_old = np.copy(self.B);
            b_old = np.copy(self.b);
            self.B          = zeros((self.m_in, self.nv+self.k+self.na));
            self.b          = zeros(self.m_in);
            self.B[self.ind_force_in, self.nv:self.nv+self.k] = B_old[self.ind_force_in, self.nv:self.nv+self.k];
            self.b[self.ind_force_in] = b_old[self.ind_force_in];
        else:
            # resize all data that depends on k
            self.B          = zeros((self.m_in, self.nv+self.k+self.na));
            self.b          = zeros(self.m_in);
            self.Jc         = zeros((self.k,self.nv));
            self.dJc_v      = zeros(self.k);
            self.dx_c       = zeros(self.k);
            self.ddx_c_des  = zeros(self.k);
            self.Jc_Minv    = zeros((self.k,self.nv));
            self.Lambda_c   = zeros((self.k,self.k));
            self.Jc_T_pinv  = zeros((self.k,self.nv));
            self.C           = zeros((self.nv+self.k+self.na, self.na));
            self.c           = zeros(self.nv+self.k+self.na);

            if(self.ENABLE_FORCE_LIMITS and self.k>0):
                self.B[self.ind_force_in, self.nv:self.nv+self.k] = np.copy(Bf);
                self.b[self.ind_force_in] = np.copy(bf);
#               print c, "contact inequality constraints:\n", self.B[self.ind_force_in, self.nv:self.nv+self.k], "\n", bf.T;

        if(updateConstrainedDynamics):
            self.updateConstrainedDynamics();

    def __init__(self, name, q, v, dt, mesh_dir, urdfFileName, freeFlyer=True):
        if(freeFlyer):
            self.r = RobotWrapper(urdfFileName, mesh_dir, root_joint=se3.JointModelFreeFlyer());
        else:
            self.r = RobotWrapper(urdfFileName, mesh_dir, None);
        self.freeFlyer = freeFlyer;
        self.nq = self.r.nq;
        self.nv = self.r.nv;
        self.na = self.nv-6 if self.freeFlyer else self.nv;
        self.k = 0;        # number of constraints
        self.dt = dt;
        self.t = 0.0;
        self.name = name;
        self.Md = zeros((self.na,self.na));

        ''' create low-pass filter for base velocities '''
        self.baseVelocityFilter = FirstOrderLowPassFilter(dt, self.BASE_VEL_FILTER_CUT_FREQ , zeros(6));
        if(freeFlyer):
            self.S_T         = zeros((self.nv,self.na));
            self.S_T[6:, :]  = np.matlib.eye(self.na);
        else:
            self.S_T    = np.matlib.eye(self.na);
        self.Nc_T       = np.matlib.eye(self.nv);

        self.qMin       = self.r.model.lowerPositionLimit;
        self.qMax       = self.r.model.upperPositionLimit;
        self.dqMax      = self.r.model.velocityLimit;
        self.ddqMax     = zeros(self.na);
        self.ddqStop    = zeros(self.na);
        if(self.freeFlyer):
            self.qMin[:6]   = -1e100;   # set bounds for the floating base
            self.qMax[:6]   = +1e100;
            self.tauMax     = self.r.model.effortLimit[6:];
        else:
            self.tauMax     = self.r.model.effortLimit;

        self.contact_points = zeros((0,3));
        self.updateInequalityData(updateConstrainedDynamics=False);
        self.setNewSensorData(0, q, v);

    def setRotorInertias(self, rotor_inertias, gear_ratios):
        self.Md = np.diag([ g*g*i for (i,g) in zip(rotor_inertias, gear_ratios) ]);

    def getFrameId(self, frameName):
        if(self.r.model.existFrame(frameName)==False):
            raise NameError("[InvDynFormUtil] ERROR: frame %s does not exist!"%frameName);
        return self.r.model.getFrameId(frameName);

    ''' ********** ENABLE OR DISABLE CONTACT CONSTRAINTS ********** '''

    def removeUnilateralContactConstraint(self, constr_name):
        found = False;
        for i in range(len(self.rigidContactConstraints)):
            if(self.rigidContactConstraints[i].name==constr_name):
                del self.rigidContactConstraints[i];
                del self.rigidContactConstraints_p[i];
                del self.rigidContactConstraints_N[i];
                del self.rigidContactConstraints_fMin[i];
                del self.rigidContactConstraints_mu[i];
                found = True;
                break;
        if(found==False):
            for i in range(len(self.bilateralContactConstraints)):
                if(self.bilateralContactConstraints[i].name==constr_name):
                    del self.bilateralContactConstraints[i];
                    found=True;
                    break;
            if(found==False):
                raise ValueError("[InvDynForm] ERROR: constraint %s cannot be removed because it does not exist!" % constr_name);
        self.updateInequalityData();

    def addUnilateralContactConstraint(self, constr, contact_points, contact_normals, fMin, mu):
        self.rigidContactConstraints        += [constr];
        self.rigidContactConstraints_p      += [contact_points];
        self.rigidContactConstraints_N      += [contact_normals];
        self.rigidContactConstraints_fMin   += [fMin];
        self.rigidContactConstraints_mu     += [mu];
        self.updateInequalityData();

    def existUnilateralContactConstraint(self, constr_name):
        res = [c.name for c in self.rigidContactConstraints if c.name==constr_name];
        return True if len(res)>0 else False;

    def addTask(self, task, weight):
        self.tasks        += [task];
        self.task_weights += [weight];
        if(weight<0.0):
            self.updateInequalityData(doNotUpdateForceLimits=True);

    def removeTask(self, task_name):
        for (i,t) in enumerate(self.tasks):
            if t.name==task_name:
                w = self.task_weights[i];
                del self.tasks[i];
                del self.task_weights[i];
                if(w<0.0):
                    self.updateInequalityData(doNotUpdateForceLimits=True);
                return True;
        raise ValueError("[InvDynForm] ERROR: task %s cannot be removed because it does not exist!" % task_name);

    def setTaskWeight(self, task_name, weight):
        for (i,t) in enumerate(self.tasks):
            if t.name==task_name:
                if(weight<0.0 or self.task_weights[i]<0.0):
                    self.task_weights[i] = weight;
                    self.updateInequalityData(doNotUpdateForceLimits=True);
                else:
                    self.task_weights[i] = weight;
                return True;
        raise ValueError("[InvDynForm] ERROR: task %s does not exist!" % task_name);

    def updateSupportPolygon(self):
        ''' Compute contact points and contact normals in world frame '''
        ncp = int(np.sum([p.shape[1] for p in self.rigidContactConstraints_p]));
        self.contact_points  = zeros((3,ncp));
        self.contact_normals = zeros((3,ncp));
        mu_s = zeros(ncp);

        i = 0;
        for (constr, P, N, mu) in zip(self.rigidContactConstraints, self.rigidContactConstraints_p,
                                      self.rigidContactConstraints_N, self.rigidContactConstraints_mu):
            oMi = self.r.framePosition(constr._frame_id);
            for j in range(P.shape[1]):
                self.contact_points[:,i]  = oMi.act(P[:,j]);
                self.contact_normals[:,i] = oMi.rotation * N[:,j];
                mu_s[i,0] = mu[0];
                i += 1;

        if(ncp==0 or not self.COMPUTE_SUPPORT_POLYGON):


from __future__ import absolute_import
from gi.repository import Gtk
from gi.repository import Pango
from gi.repository import GObject
from gi.repository import GdkPixbuf
import math
import random

#from Gtk.gdk import pixbuf_new_from_file

from pychess.Players.Human import Human
from pychess.Players.engineNest import discoverer
from pychess.System import uistuff, conf
from pychess.System.glock import glock_connect_after
from pychess.System.prefix import addDataPrefix
from pychess.Utils.GameModel import GameModel
from pychess.Utils.IconLoader import load_icon
from pychess.Utils.TimeModel import TimeModel
from pychess.Utils.const import LOCAL, ARTIFICIAL, WHITE, BLACK, NORMALCHESS
from pychess.Variants import variants
from pychess.ic import ICLogon
from pychess.widgets import ionest, newGameDialog

from .Background import giveBackground
from .ToggleComboBox import ToggleComboBox
import traceback
class TaskerManager (Gtk.Table):

    def __init__ (self):
        GObject.GObject.__init__(self)
        self.border = 20
        giveBackground(self)
        self.connect("draw", self.expose)
        #self.set_homogeneous(True)

    def expose (self, widget, ctx):
        cr = widget.get_window().cairo_create()

        for widget in self.widgets:
            x = widget.get_allocation().x
            y = widget.get_allocation().y
            width = widget.get_allocation().width
            height = widget.get_allocation().height

            cr.move_to  (x-self.border, y)
            cr.curve_to (x-self.border, y-self.border/2.,
                         x-self.border/2., y-self.border,
                         x, y-self.border)
            cr.line_to  (x+width, y-self.border)
            cr.curve_to (x+width+self.border/2., y-self.border,
                         x+width+self.border, y-self.border/2.,
                         x+width+self.border, y)
            cr.line_to  (x+width+self.border, y+height)
            cr.curve_to (x+width+self.border, y+height+self.border/2.,
                         x+width+self.border/2., y+height+self.border,
                         x+width, y+height+self.border)
            cr.line_to  (x, y+height+self.border)
            cr.curve_to (x-self.border/2., y+height+self.border,
                         x-self.border, y+height+self.border/2.,
                         x-self.border, y+height)

            sc = self.get_style_context()
            bool1, bgcolor = sc.lookup_color("p_bg_color")
            bool1, darkcolor = sc.lookup_color("p_dark_color")

            cr.set_source_rgba(bgcolor.red, bgcolor.green, bgcolor.blue, bgcolor.alpha)
            cr.fill()

            cr.rectangle (x-self.border, y+height-30, width+self.border*2, 30)
            cr.set_source_rgba(darkcolor.red, darkcolor.green, darkcolor.blue, darkcolor.alpha)
            cr.fill()

    def calcSpacings (self, n):
        """ Will yield ranges like
            ((.50,.50),)
            ((.66,.33), (.33,.66))
            ((.75,.25), (.50,.50), (.25,.75))
            ((.80,.20), (.60,.40), (.40,.60), (.20,.80))
            Used to create the centering in the table """

        first = next = (n)/float(n+1)
        for i in range(n):
            yield (next, 1-next)
            next = first-(1-next)

    def packTaskers (self, *widgets):
        self.widgets = widgets

        for widget in widgets:
            widget.connect("size-allocate", lambda *a:
                           self.get_window().invalidate_rect(self.get_allocation(), False))
        root = math.sqrt(len(widgets))
        # Calculate number of rows
        rows = int(math.ceil(root))
        # Calculate number of filled out rows
        rrows = int(math.floor(root))
        # Calculate number of cols in filled out rows
        cols = int(math.ceil( len(widgets)/float(rows) ))

        # Calculate spacings

        vspac = [s[0] for s in self.calcSpacings(rows)]
        hspac = [s[0] for s in self.calcSpacings(cols)]

        # Clear and set up new size

        for child in self.get_children():
            self.remove(child)

        self.props.n_columns = cols
        self.props.n_rows = rows

        # Add filled out rows

        for row in range(rrows):
            for col in range(cols):
                widget = widgets[row*cols + col]
                alignment = Gtk.Alignment.new(hspac[col], vspac[row], 0, 0)
                alignment.add(widget)
                self.attach(alignment, col, col+1, row, row+1)

        # Add last row

        if rows > rrows:
            lastrow = Gtk.HBox()
            # Calculate number of widgets in last row
            numw = len(widgets) - cols*rrows
            hspac = [s[0] for s in self.calcSpacings(numw)]
            for col, widget in enumerate(widgets[-numw:]):
                alignment = Gtk.Alignment.new(hspac[col], vspac[-1], 0, 0)
                alignment.add(widget)
                alignment.set_padding(self.border, self.border, self.border, self.border)
                lastrow.pack_start(alignment, True, True, 0)

            self.attach(lastrow, 0, cols, rrows, rrows+1)

class NewGameTasker (Gtk.Alignment):

    def __init__ (self):
        #GObject.GObject.__init__(self,0,0,0,0)
        GObject.GObject.__init__(self)
        self.widgets = widgets = uistuff.GladeWidgets("taskers.glade")
        tasker = widgets["newGameTasker"]
        tasker.unparent()
        self.add(tasker)

        combo = ToggleComboBox()
        combo.addItem(_("White"), GdkPixbuf.Pixbuf.new_from_file(addDataPrefix("glade/white.png")))
        combo.addItem(_("Black"), GdkPixbuf.Pixbuf.new_from_file(addDataPrefix("glade/black.png")))
        combo.addItem(_("Random"), GdkPixbuf.Pixbuf.new_from_file(addDataPrefix("glade/random.png")))
        combo.setMarkup("", "")
        widgets["colorDock"].add(combo)
        uistuff.keep(combo, "newgametasker_colorcombo")
        widgets['yourColorLabel'].set_mnemonic_widget(combo)

        # We need to wait until after engines have been discovered, to init the
        # playerCombos. We use connect_after to make sure, that newGameDialog
        # has also had time to init the constants we share with them.
        self.playerCombo = ToggleComboBox()
        widgets["opponentDock"].add(self.playerCombo)
        glock_connect_after(discoverer, "all_engines_discovered",
                            self.__initPlayerCombo, widgets)
        widgets['opponentLabel'].set_mnemonic_widget(self.playerCombo)

        def on_skill_changed (scale):
            pix = newGameDialog.skillToIconLarge[int(scale.get_value())]
            widgets["skillImage"].set_from_pixbuf(pix)
        widgets["skillSlider"].connect("value-changed", on_skill_changed)
        on_skill_changed(widgets["skillSlider"])

        widgets["startButton"].connect("clicked", self.startClicked)
        self.widgets["opendialog1"].connect("clicked", self.openDialogClicked)

    def __initPlayerCombo (self, discoverer, widgets):
        combo = self.playerCombo
        combo.update(newGameDialog.smallPlayerItems[0])
        if combo.active < 0:
            combo.label.set_ellipsize(Pango.EllipsizeMode.MIDDLE)
            combo.setMarkup("", "")
            combo.active = 1
            uistuff.keep(self.playerCombo, "newgametasker_playercombo")

            def on_playerCombobox_changed (widget, event):
                widgets["skillSlider"].props.visible = widget.active > 0
            combo.connect("changed", on_playerCombobox_changed)

            uistuff.keep(widgets["skillSlider"], "taskerSkillSlider")
            widgets["skillSlider"].set_no_show_all(True)
            on_playerCombobox_changed(self.playerCombo, None)

    def openDialogClicked (self, button):
        newGameDialog.NewGameMode.run()

    def startClicked (self, button):
        color = self.widgets["colorDock"].get_child().active
        if color == 2:
            color = random.choice([WHITE, BLACK])
        opponent = self.widgets["opponentDock"].get_child().active
        difficulty = int(self.widgets["skillSlider"].get_value())

        gamemodel = GameModel(TimeModel(5*60, 0))