#------------------------------------------------------------------------------
#
#  Copyright (c) 2005, Enthought, Inc.
#  All rights reserved.
#
#  This software is provided without warranty under the terms of the BSD
#  license included in enthought/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!
#
#  Author: David C. Morrill
#  Date:   08/25/2005
#
#------------------------------------------------------------------------------

""" Defines the various instance descriptors used by the instance editor and
    instance editor factory classes.
"""

#-------------------------------------------------------------------------
#  Imports:
#-------------------------------------------------------------------------

from __future__ import absolute_import

from traits.api import HasPrivateTraits, Str, Any, Dict, Tuple, Callable, Bool

from .ui_traits import AView

from .helper import user_name_for
import six

#-------------------------------------------------------------------------
#  'InstanceChoiceItem' class:
#-------------------------------------------------------------------------


class InstanceChoiceItem(HasPrivateTraits):

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

    # User interface name for the item
    name = Str

    # View associated with this item
    view = AView

    # Does this item create new instances?
    is_factory = Bool(False)

    #-------------------------------------------------------------------------
    #  Returns the name of the item:
    #-------------------------------------------------------------------------

    def get_name(self, object=None):
        """ Returns the name of the item.
        """
        return self.name

    #-------------------------------------------------------------------------
    #  Return the view associated with the object:
    #-------------------------------------------------------------------------

    def get_view(self):
        """ Returns the view associated with the object.
        """
        return self.view

    #-------------------------------------------------------------------------
    #  Returns the object associated with the item:
    #-------------------------------------------------------------------------

    def get_object(self):
        """ Returns the object associated with the item.
        """
        raise NotImplementedError

    #-------------------------------------------------------------------------
    #  Indicates whether a specified object is compatible with the item:
    #-------------------------------------------------------------------------

    def is_compatible(self, object):
        """ Indicates whether a specified object is compatible with the item.
        """
        raise NotImplementedError

    #-------------------------------------------------------------------------
    #  Indicates whether the item can be selected by the user:
    #-------------------------------------------------------------------------

    def is_selectable(self):
        """ Indicates whether the item can be selected by the user.
        """
        return True

    #-------------------------------------------------------------------------
    #  Indicates whether the item supports drag and drop:
    #-------------------------------------------------------------------------

    def is_droppable(self):
        """ Indicates whether the item supports drag and drop.
        """
        return False

#-------------------------------------------------------------------------
#  'InstanceChoice' class:
#-------------------------------------------------------------------------


class InstanceChoice(InstanceChoiceItem):

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

    # Object associated with the item
    object = Any

    # The name of the object trait containing its user interface name:
    name_trait = Str('name')

    #-------------------------------------------------------------------------
    #  Returns the name of the item:
    #-------------------------------------------------------------------------

    def get_name(self, object=None):
        """ Returns the name of the item.
        """
        if self.name != '':
            return self.name

        name = getattr(self.object, self.name_trait, None)
        if isinstance(name, six.string_types):
            return name

        return user_name_for(self.object.__class__.__name__)

    #-------------------------------------------------------------------------
    #  Returns the object associated with the item:
    #-------------------------------------------------------------------------

    def get_object(self):
        """ Returns the object associated with the item.
        """
        return self.object

    #-------------------------------------------------------------------------
    #  Indicates whether a specified object is compatible with the item:
    #-------------------------------------------------------------------------

    def is_compatible(self, object):
        """ Indicates whether a specified object is compatible with the item.
        """
        return (object is self.object)

#-------------------------------------------------------------------------
#  'InstanceFactoryChoice' class:
#-------------------------------------------------------------------------


class InstanceFactoryChoice(InstanceChoiceItem):

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

    # Indicates whether an instance compatible with this item can be dragged and
    # dropped rather than created
    droppable = Bool(False)

    # Indicates whether the item can be selected by the user
    selectable = Bool(True)

    # A class (or other callable) that can be used to create an item compatible
    # with this item
    klass = Callable

    # Tuple of arguments to pass to **klass** to create an instance
    args = Tuple

    # Dictionary of arguments to pass to **klass** to create an instance
    kw_args = Dict(Str, Any)

    # Does this item create new instances? This value overrides the default.
    is_factory = True

    #-------------------------------------------------------------------------
    #  Returns the name of the item:
    #-------------------------------------------------------------------------

    def get_name(self, object=None):
        """ Returns the name of the item.
        """
        if self.name != '':
            return self.name

        name = getattr(object, 'name', None)
        if isinstance(name, six.string_types):
            return name

        if issubclass(type(self.klass), type):
            klass = self.klass
        else:
            klass = self.get_object().__class__

        return user_name_for(klass.__name__)

    #-------------------------------------------------------------------------
    #  Returns the object associated with the item:
    #-------------------------------------------------------------------------

    def get_object(self):
        """ Returns the object associated with the item.
        """
        return self.klass(*self.args, **self.kw_args)

    #-------------------------------------------------------------------------
    #  Indicates whether the item supports drag and drop:
    #-------------------------------------------------------------------------

    def is_droppable(self):
        """ Indicates whether the item supports drag and drop.
        """
        return self.droppable

    #-------------------------------------------------------------------------
    #  Indicates whether a specified object is compatible with the item:
    #-------------------------------------------------------------------------

    def is_compatible(self, object):
        """ Indicates whether a specified object is compatible with the item.
        """
        if issubclass(type(self.klass), type):
            return isinstance(object, self.klass)
        return isinstance(object, self.get_object().__class__)

    #-------------------------------------------------------------------------
    #  Indicates whether the item can be selected by the user:
    #-------------------------------------------------------------------------

    def is_selectable(self):
        """ Indicates whether the item can be selected by the user.
        """
        return self.selectable

#-------------------------------------------------------------------------
#  'InstanceDropChoice' class:
#-------------------------------------------------------------------------


class InstanceDropChoice(InstanceFactoryChoice):

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

    # Indicates whether an instance compatible with this item can be dragged and
    # dropped rather than created . This value overrides the default.
    droppable = True

    # Indicates whether the item can be selected by the user. This value
    # overrides the default.
    selectable = False

    # Does this item create new instances? This value overrides the default.
    is_factory = False
