# -*- coding: utf-8 -*-
# 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.


__maintainer__ = 'Lionel Martin <lionel@fluendo.com>'
__maintainer2__ = 'Florian Boucault <florian@fluendo.com>'

import weakref

from elisa.core import log

class DictObservable(log.Loggable, dict):

    # FIXME: should be made thread-safe.
    # FIXME: not complete.

    def __init__(self, *args, **kw):
        log.Loggable.__init__(self)
        dict.__init__(self, *args, **kw)
        self._observers = []

    def __hash__(self):
        return Observable.__hash__(self)

    def __repr__(self):
        return "<DictObservable %r>" % dict.__repr__(self)

    def __eq__(self, other):
        return id(self) == id(other)

    def __setitem__(self, key, value):
        dict.__setitem__(self, key, value)
        self._send_message_to_observers("modified", key, value)

    def add_observer(self, observer):
        """Attach an observer which will then be notified of all the changes
        applied to the observable.

        @param observer: observer to attach
        @type observer:  L{elisa.core.observers.observer.Observer}
        """
        self.debug("Adding observer %r" % observer)
        real_observers = [weak_observer() for weak_observer in self._observers]
        if observer not in real_observers:
            self._observers.append(weakref.ref(observer))
        else:
            self.debug("Observer %r was already observing" % observer)

    def remove_observer(self, observer):
        """Detach an observer which will not be notified anymore of changes
        applied to the observable.

        @param observer: observer to detach
        @type observer:  L{elisa.core.observers.observer.Observer}
        """
        self.debug("Removing observer %r", observer)
        refs = weakref.getweakrefs(observer)
        for ref in refs:
            try:
                self._observers.remove(ref)
            except ValueError:
                pass
        """
        # ignore the call if the observer was not known
        self.debug("Observer %r was not observing", observer)
        """

    def _send_message_to_observers(self, message, *args):
        for weak_observer in self._observers:
            observer = weak_observer()
            if observer == None:
                continue
            else:
                getattr(observer, message)(*args)


class DictObserver(object):

    # FIXME: should pass the old value as well
    def modified(self, key, value):
        """
        Message sent by a L{DictObservable} when one of its elements is
        modified.

        @param key:   key of the dictionary for which the value was modified
        @type key:    object
        @param value: new value associated to L{key}
        @type value:  object
        """
        pass




#if __name__ == "__main__":
#
#    l = DictObservable()
#    o = DictObserver()
#
#    l.add_observer(o)
#
#    print l
#    l['key']= 'value'
#    l['key']= 'value2'
