#------------------------------------------------------------------------------
# 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!
#------------------------------------------------------------------------------

from __future__ import absolute_import

from traits.testing.unittest_tools import unittest

from ..api import Delegate, HasTraits, Instance, Str

# global because event handlers are being called with wrong value for self
baz_s_handler_self = None
baz_sd_handler_self = None
baz_u_handler_self = None
baz_t_handler_self = None
foo_s_handler_self = None
foo_t_handler_self = None

class Foo( HasTraits ):
    s = Str( 'foo' )
    t = Str( 'foo.t' )
    u = Str( 'foo.u' )

    def _s_changed(self, name, old, new):
        print 'Foo._s_changed( %s, %s, %s, %s)' % (self, name, old, new)
        global foo_s_handler_self
        foo_s_handler_self = self
        return

    def _t_changed(self, name, old, new):
        print 'Foo._t_changed( %s, %s, %s, %s)' % (self, name, old, new)
        global foo_t_handler_self
        foo_t_handler_self = self
        return

class Bar( HasTraits ):
    foo = Instance( Foo, () )
    s = Delegate( 'foo' )

class BazModify( HasTraits ):
    foo = Instance( Foo, () )
    sd = Delegate( 'foo', prefix='s', modify=True )
    t = Delegate( 'foo', modify=True )
    u = Delegate( 'foo', listenable=False, modify=True )

    def _s_changed(self, name, old, new):
        # should never be called
        print 'BazModify._s_changed( %s, %s, %s, %s)' % (self, name, old, new)
        global baz_s_handler_self
        baz_s_handler_self = self
        return

    def _sd_changed(self, name, old, new):
        print 'BazModify._sd_changed( %s, %s, %s, %s)' % (self, name, old, new)
        global baz_sd_handler_self
        baz_sd_handler_self = self
        return

    def _t_changed(self, name, old, new):
        print 'BazModify._t_changed( %s, %s, %s, %s)' % (self, name, old, new)
        global baz_t_handler_self
        baz_t_handler_self = self
        return

    def _u_changed(self, name, old, new):
        print 'BazModify._u_changed( %s, %s, %s, %s)' % (self, name, old, new)
        global baz_u_handler_self
        baz_u_handler_self = self
        return


class BazNoModify( HasTraits ):
    foo = Instance( Foo, () )
    sd = Delegate( 'foo', prefix='s' )
    t = Delegate( 'foo' )
    u = Delegate( 'foo', listenable=False )

    def _s_changed(self, name, old, new):
        print 'BazNoModify._s_changed( %s, %s, %s, %s)' % (self, name, old, new)
        global baz_s_handler_self
        baz_s_handler_self = self
        return

    def _sd_changed(self, name, old, new):
        print 'BazNoModify._sd_changed( %s, %s, %s, %s)' % (self, name, old, new)
        global baz_sd_handler_self
        baz_sd_handler_self = self
        return

    def _t_changed(self, name, old, new):
        print 'BazNoModify._t_changed( %s, %s, %s, %s)' % (self, name, old, new)
        global baz_t_handler_self
        baz_t_handler_self = self
        return

    def _u_changed(self, name, old, new):
        print 'BazNoModify._u_changed( %s, %s, %s, %s)' % (self, name, old, new)
        global baz_u_handler_self
        baz_u_handler_self = self
        return

class DelegateTestCase( unittest.TestCase ):
    """ Test cases for delegated traits. """

    def setUp(self):
        """ Reset all of the globals.
        """
        global baz_s_handler_self, baz_sd_handler_self, baz_u_handler_self
        global baz_t_handler_self, foo_s_handler_self, foo_t_handler_self
        baz_s_handler_self = None
        baz_sd_handler_self = None
        baz_u_handler_self = None
        baz_t_handler_self = None
        foo_s_handler_self = None
        foo_t_handler_self = None

    def test_reset(self):
        """ Test that a delegated trait may be reset.

        Deleting the attribute should reset the trait back to its initial
        delegation behavior.
        """

        f = Foo()
        b = Bar(foo=f)

        # Check initial delegation.
        self.assertEqual( f.s, b.s )

        # Check that an override works.
        b.s = 'bar'
        self.assertNotEqual( f.s, b.s )

        # Check that we can reset back to delegation.  This is what we are
        # really testing for.
        del b.s
        self.assertEqual( f.s, b.s )

        return


    # Below are 8 tests to check the calling of change notification handlers.
    # There are 8 cases for the 2x2x2 matrix with axes:
    # Delegate with prefix or not
    # Delegate with modify write through or not
    # Handler in the delegator and delegatee
    #
    def test_modify_prefix_handler_on_delegator(self):
        f = Foo()
        b = BazModify(foo=f)

        self.assertEqual( f.s, b.sd )

        b.sd = 'changed'
        self.assertEqual( f.s, b.sd )

        # Don't expect _s_changed to be called because from Baz's perspective
        # the trait is named 'sd'
        self.assertEqual( baz_s_handler_self, None )

        # Do expect '_sd_changed' to be called with b as self
        self.assertEqual( baz_sd_handler_self, b )

        return

    def test_modify_prefix_handler_on_delegatee(self):
        f = Foo()
        b = BazModify(foo=f)

        self.assertEqual( f.s, b.sd )

        b.sd = 'changed'
        self.assertEqual( f.s, b.sd )

        # Foo expects its '_s_changed' handler to be called with f as self
        self.assertEqual( foo_s_handler_self, f )

        return



    def test_no_modify_prefix_handler_on_delegator(self):
        f = Foo()
        b = BazNoModify(foo=f)

        self.assertEqual( f.s, b.sd )

        b.sd = 'changed'
        self.assertNotEqual( f.s, b.sd )

        # Don't expect _s_changed to be called because from Baz's perspective
        # the trait is named 'sd'
        self.assertEqual( baz_s_handler_self, None )

        # Do expect '_sd_changed' to be called with b as self
        self.assertEqual( baz_sd_handler_self, b )

        return

    def test_no_modify_prefix_handler_on_delegatee_not_called(self):
        f = Foo()
        b = BazNoModify(foo=f)

        self.assertEqual( f.s, b.sd )

        b.sd = 'changed'
        self.assertNotEqual( f.s, b.sd )

        # Foo expects its '_s_changed' handler to be called with f as self
        self.assertEqual( foo_s_handler_self, None )

        return




    def test_modify_handler_on_delegator(self):
        f = Foo()
        b = BazModify(foo=f)

        self.assertEqual( f.t, b.t )

        b.t = 'changed'
        self.assertEqual( f.t, b.t )

        # Do expect '_t_changed' to be called with b as self
        self.assertEqual( baz_t_handler_self, b )

        return

    def test_modify_handler_on_delegatee(self):
        f = Foo()
        b = BazModify(foo=f)

        self.assertEqual( f.t, b.t )

        b.t = 'changed'
        self.assertEqual( f.t, b.t )

        # Foo t did change so '_t_changed' handler should be called
        self.assertEqual( foo_t_handler_self, f)

        return


    def test_no_modify_handler_on_delegator(self):
        f = Foo()
        b = BazNoModify(foo=f)

        self.assertEqual( f.t, b.t )

        b.t = 'changed'
        self.assertNotEqual( f.t, b.t )

        # Do expect '_t_changed' to be called with b as self
        self.assertEqual( baz_t_handler_self, b )

        return

    def test_no_modify_handler_on_delegatee_not_called(self):
        f = Foo()
        b = BazNoModify(foo=f)

        self.assertEqual( f.t, b.t )

        b.t = 'changed'
        self.assertNotEqual( f.t, b.t )

        # Foo t did not change so '_t_changed' handler should not be called
        self.assertEqual( foo_t_handler_self, None)

        return



    # Below are 4 tests for notification when the delegated trait is changed
    # directly rather than through the delegator.

    def test_no_modify_handler_on_delegatee_direct_change(self):
        f = Foo()
        b = BazNoModify(foo=f)

        self.assertEqual( f.t, b.t )

        f.t = 'changed'
        self.assertEqual( f.t, b.t )

        # Foo t did change so '_t_changed' handler should be called
        self.assertEqual( foo_t_handler_self, f)

        return

    def test_no_modify_handler_on_delegator_direct_change(self):
        f = Foo()
        b = BazNoModify(foo=f)

        self.assertEqual( f.t, b.t )

        f.t = 'changed'
        self.assertEqual( f.t, b.t )

        # Do expect '_t_changed' to be called with b as self
        self.assertEqual( baz_t_handler_self, b )

        return






    def test_modify_handler_on_delegatee_direct_change(self):
        f = Foo()
        b = BazModify(foo=f)

        self.assertEqual( f.t, b.t )

        f.t = 'changed'
        self.assertEqual( f.t, b.t )

        # Foo t did change so '_t_changed' handler should be called
        self.assertEqual( foo_t_handler_self, f)

        return

    def test_modify_handler_on_delegator_direct_change(self):
        f = Foo()
        b = BazModify(foo=f)

        self.assertEqual( f.t, b.t )

        f.t = 'changed'
        self.assertEqual( f.t, b.t )

        # Do expect '_t_changed' to be called with b as self
        self.assertEqual( baz_t_handler_self, b )

        return


    # Below are tests which check that we can turn off listenableness.

    def test_modify_handler_not_listenable(self):
        f = Foo()
        b = BazModify(foo=f)

        self.assertEqual( f.u, b.u )

        f.u = 'changed'
        self.assertEqual( f.u, b.u )

        # Do not expect '_u_changed' to be called.
        self.assertEqual( baz_u_handler_self, None )

        return

    def test_no_modify_handler_not_listenable(self):
        f = Foo()
        b = BazNoModify(foo=f)

        self.assertEqual( f.u, b.u )

        f.u = 'changed'
        self.assertEqual( f.u, b.u )

        # Do not expect '_u_changed' to be called.
        self.assertEqual( baz_u_handler_self, None )

        return

if __name__ == '__main__':
    unittest.main()

#### EOF ######################################################################

