# (C) Copyright 2004-2023 Enthought, Inc., Austin, TX
# All rights reserved.
#
# This software is provided without warranty under the terms of the BSD
# license included in LICENSE.txt and may be redistributed only under
# the conditions described in the aforementioned license. The license
# is also available online at http://www.enthought.com/licenses/BSD.txt
#
# Thanks for using Enthought open source!

""" Defines the DockableViewElement class, which allows Traits UIs and
    Traits UI elements to be docked in external Pyface DockWindow windows.
"""

from traits.api import HasPrivateTraits, Instance, Bool

from .ui import UI

from .group import Group

from .view import View

from .view_element import ViewSubElement

from pyface.dock.idockable import IDockable

# -------------------------------------------------------------------------
#  'DockableViewElement' class:
# -------------------------------------------------------------------------


class DockableViewElement(HasPrivateTraits, IDockable):
    """Allows Traits UIs and Traits UI elements to be docked in external
    Pyface DockWindow windows.
    """

    # -------------------------------------------------------------------------
    #  Trait definitions:
    # -------------------------------------------------------------------------

    #: The Traits UI that can be docked with an external DockWindow
    ui = Instance(UI)

    #: The (optional) element of the Traits UI that can be docked
    element = Instance(ViewSubElement)

    #: Should the DockControl be closed on redocking?
    should_close = Bool(False)

    # -- IDockable interface --------------------------------------------------

    def dockable_should_close(self):
        """Should the current DockControl be closed before creating the new
        one?
        """
        element = self.element
        if element is None:
            element = self.ui.view.content

        if not isinstance(element, Group):
            element = Group().trait_set(content=[element])

        group = Group().trait_set(content=[element])
        self._view = (
            View()
            .trait_set(**self.ui.view.get())
            .trait_set(content=group, title="")
        )

        # FIXME: The following private traits are being set here to facilitate
        # rebuilding the ui (which will require the context and the handler).
        # When a current dock control is closed (close_dock_control method),
        # the contents of self.ui have been disposed of and self.ui is now
        # None. Now if a new UI needs to be created by calling
        # dockable_get_control (e.g., when doing an 'undock' action on a dock
        # window), we need to pass on the context and handler to the UI.
        # Therefore, we are setting these private traits here so
        # dockable_get_control can access them. In future, we need to
        # investigate if there is a better way to do this.

        self._context = self.ui.context.copy()
        # Make copy since context will be emptied when calling
        # self.ui.dispose()
        self._handler = self.ui.handler

        return self.should_close or (self.element is None)

    def dockable_get_control(self, parent):
        """Gets a control that can be docked into a DockWindow."""
        # Create the new UI:
        ui = self._view.ui(
            self._context,
            parent=parent,
            kind="subpanel",
            handler=self._handler,
        )

        # Discard the reference to the view created previously:
        self._view = None

        # If the old UI was closed, then switch to using the new one:
        if self.element is None:
            self.ui = ui
        else:
            self._ui = ui

        return ui.control

    def dockable_init_dockcontrol(self, dock_control):
        """Allows the object to override the default DockControl settings."""
        dockable = self
        if self.element is not None:
            dockable = DockableViewElement(
                ui=self._ui, element=self.element, should_close=True
            )
            self._ui = None

        dock_control.trait_set(
            dockable=dockable, on_close=dockable.close_dock_control
        )

    def close_dock_control(self, dock_control, abort):
        """Handles the closing of a DockControl containing a Traits UI."""
        ui = self.ui

        # Ask the traits UI handler if it is OK to close the window:
        if (not abort) and (not ui.handler.close(ui.info, True)):
            # If not, tell the DockWindow not to close it:
            return False

        # Otherwise, clean up and close the traits UI:
        ui.dispose(abort=abort)

        # Break our linkage to the UI and ViewElement object:
        self.ui = self.element = None

        # And tell the DockWindow to remove the DockControl:
        return True
