# Elisa - Home multimedia server
# Copyright (C) 2006-2008 Fluendo Embedded S.L. (www.fluendo.com).
# All rights reserved.
#
# This file is available under one of two license agreements.
#
# This file is licensed under the GPL version 3.
# See "LICENSE.GPL" in the root of this distribution including a special
# exception to use Elisa with Fluendo's plugins.
#
# The GPL part of Elisa is also available under a commercial licensing
# agreement from Fluendo.
# See "LICENSE.Elisa" in the root directory of this distribution package
# for details on that license.

from elisa.core.tests.elisa_test_case import ElisaTestCase
from elisa.core.observers.observable import Observable
from elisa.core.observers.observer import Observer


class MyObserver(Observer):

    def __init__(self):
        Observer.__init__(self)
        self.origin = None

    def attribute_set(self, origin, key, old_value, new_value):
        self.origin = origin

class MyObserverRaisingException(Observer):

    def __init__(self):
        Observer.__init__(self)

    def attribute_set(self, origin, key, old_value, new_value):
        raise Exception()

class TestObservers(ElisaTestCase):

    def test_trivial(self):
        observer = MyObserver()
        o = Observable()

        o.add_observer(observer)

        o.test = "test"

        self.failUnlessEqual(observer.origin, o)

    def test_stop_observing_then_reobserve(self):
        observer = MyObserver()
        o1 = Observable()
        o2 = Observable()

        # attach
        o1.add_observer(observer)

        # attach to another one
        o2.add_observer(observer)

        observer.origin = None
        o1.test = "test"
        self.failUnlessEqual(observer.origin, o1)
        observer.origin = None
        o2.test = "test"
        self.failUnlessEqual(observer.origin, o2)

        # detach
        o1.remove_observer(observer)

        observer.origin = None
        o1.test = "test"
        self.failUnlessEqual(observer.origin, None)
        observer.origin = None
        o2.test = "test"
        self.failUnlessEqual(observer.origin, o2)

        # reattach
        o1.add_observer(observer)

        observer.origin = None
        o1.test = "test"
        self.failUnlessEqual(observer.origin, o1)
        observer.origin = None
        o2.test = "test"
        self.failUnlessEqual(observer.origin, o2)

    def test_remove_observer(self):
        observer = MyObserver()
        o = Observable()

        # try stop observing while it's not anyway
        o.remove_observer(observer)

        # observing
        o.add_observer(observer)

        o.test = "test"
        self.failUnlessEqual(observer.origin, o)

        # stop observing
        o.remove_observer(observer)
        observer.origin = None
        o.test = "test"
        self.failUnlessEqual(observer.origin, None)

    def test_multiple_observers(self):
        observer = MyObserver()
        o1 = Observable()
        o2 = Observable()

        # observe #1
        o1.add_observer(observer)

        observer.origin = None
        o1.test = "test"
        self.failUnlessEqual(observer.origin, o1)
        observer.origin = None
        o2.test = "test"
        self.failUnlessEqual(observer.origin, None)

        # observe #2
        o2.add_observer(observer)

        observer.origin = None
        o1.test = "test"
        self.failUnlessEqual(observer.origin, o1)
        observer.origin = None
        o2.test = "test"
        self.failUnlessEqual(observer.origin, o2)

        # stop observing #1
        o1.remove_observer(observer)

        observer.origin = None
        o1.test = "test"
        self.failUnlessEqual(observer.origin, None)
        observer.origin = None
        o2.test = "test"
        self.failUnlessEqual(observer.origin, o2)

        # stop observing #2
        o2.remove_observer(observer)

        observer.origin = None
        o1.test = "test"
        self.failUnlessEqual(observer.origin, None)
        observer.origin = None
        o2.test = "test"
        self.failUnlessEqual(observer.origin, None)

    def test_exception(self):
        observer = MyObserverRaisingException()
        o = Observable()

        o.add_observer(observer)

        self.failUnlessRaises(Exception, o.__setattr__, "test", "test")

    def test_repeated_add_observer(self):
        observer = MyObserver()
        observable = Observable()

        # add_observer
        observable.add_observer(observer)

        observer.origin = None
        observable.test = "test"
        self.failUnlessEqual(observer.origin, observable)

        # add_observer again, it should be ignored
        observable.add_observer(observer)

        observer.origin = None
        observable.test = "test"
        self.failUnlessEqual(observer.origin, observable)

        # remove_observer: no observation anymore
        observable.remove_observer(observer)

        observer.origin = None
        observable.test = "test"
        self.failUnlessEqual(observer.origin, None)

        # remove_observer again, it should be ignored
        observable.remove_observer(observer)

        observer.origin = None
        observable.test = "test"
        self.failUnlessEqual(observer.origin, None)
