""" FeedList.py

Provides a container for handling the feeds
"""
__copyright__ = "Copyright (c) 2002-2005 Free Software Foundation, Inc."
__license__ = """GNU General Public License

This program is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA. """


import Event
import Feed
import Config
import locale
import utils

class FeedList(list, Event.SignalEmitter):
    def __init__(self, init_seq = []):
        Event.SignalEmitter.__init__(self)
        self.initialize_slots(Event.FeedsChangedSignal,
                              Event.FeedDeletedSignal,
                              Event.FeedCreatedSignal,
                              Event.AllItemsReadSignal,
                              Event.ItemReadSignal,
                              Event.ItemsAddedSignal,
                              Event.FeedPolledSignal,
                              Event.FeedStatusChangedSignal,
                              Event.FeedErrorStatusChangedSignal,
                              Event.FeedsImportedSignal,
                              Event.FeedDetailChangedSignal)
        self._loading = False

    def load_data(self):
        def _load(feeds, parent):
            for df in feeds:
                if isinstance(df, list):
                    #fc = straw.FeedCategory()
                    #fc.undump(df[0])
                    #self.append(parent, fc)
                    _load(df[1:], parent)
                else:
                    f = Feed.Feed.create_empty_feed()
                    f.undump(df)
                    self.append(parent, f)
        self._loading = True
        feeds = Config.get_instance().feeds
        if feeds is not None:
            _load(feeds, None)
        self._loading = False
        self.emit_signal(Event.FeedsChangedSignal(self))

    def _forward_signal(self, signal):
        self.emit_signal(signal)

    def connect_signals(self, ob):
        #ob.signal_connect(Event.FeedsChangedSignal,
        #                  self.feeds_changed, True)
        ob.signal_connect(Event.FeedDetailChangedSignal,
                          self.feed_detail_changed, True)

        # these signals are forwarded so that listeners who just want to
        # listen for a specific event regardless of what feed it came from can
        # just connect to this feedlist instead of connecting to the
        # individual feeds.
        ob.signal_connect(Event.AllItemsReadSignal, self._forward_signal)
        ob.signal_connect(Event.ItemReadSignal, self._forward_signal)
        ob.signal_connect(Event.ItemsAddedSignal, self._forward_signal)
        ob.signal_connect(Event.FeedPolledSignal, self._forward_signal)
        ob.signal_connect(Event.FeedStatusChangedSignal, self._forward_signal)
        ob.signal_connect(Event.FeedErrorStatusChangedSignal, self._forward_signal)

    def __setitem__(self, key, value):
        list.__setitem__(self, key, value)
        self.connect_signals(value)
        self.save_feeds_and_notify(True)

    def extend(self, parent, values, from_sub=False):
        list.extend(self, values)
        for f in values:
            f.parent = parent
            self.connect_signals(f)
        self.save_feeds_and_notify(
            True, signal=Event.FeedsImportedSignal(self, values, parent, from_sub))

    def append(self, parent, value):
        list.append(self, value)
        value.parent = parent
        self.connect_signals(value)
        self.save_feeds_and_notify(
            True, signal=Event.FeedCreatedSignal(self, value, parent))

    def insert(self, index, parent, value):
        list.insert(self, index, value)
        value.parent = parent
        self.connect_signals(value)
        self.save_feeds_and_notify(
            True, signal=Event.FeedCreatedSignal(self, value, parent, index))

    def index(self, feed):
        return list.index(self, feed)

    def reorder(self, move, delta):
        k = self[:]
        move = list(move)
        move.sort()
        if delta > 0:
            move.reverse()
        if move[0] == 0 and delta < 0 or move[-1] == (len(self) - 1) and delta > 0:
            return
        for m in move:
            k[m + delta], k[m] = k[m], k[m + delta]
        for i in range(len(k)):
            list.__setitem__(self, i, k[i])
        self.save_feeds_and_notify(True)

    def __delitem__(self, value):
        feed = self[value]
        list.__delitem__(self, value)
        feed.delete_all_items()
        self.save_feeds_and_notify(
            True, signal=Event.FeedDeletedSignal(self, feed))

    def save_feeds_and_notify(self, notify, signal=None):
        if not self._loading:
            config = Config.get_instance()
            config.feeds = [f.dump() for f in self]
            if notify:
                if not signal:
                    signal = Event.FeedsChangedSignal(self)
                self.emit_signal(signal)
        return

    def feeds_changed(self, signal, notify):
        self.save_feeds_and_notify(notify, signal)

    def feed_detail_changed(self, signal, notify):
        self.save_feeds_and_notify(notify, signal)

    def _sort_dsu(self, seq):
        aux_list = [(x.title, x) for x in seq]
        aux_list.sort(lambda a,b:locale.strcoll(a[0],b[0]))
        return [x[1] for x in aux_list]

    def sort(self, indices = None):
        if not indices or len(indices) == 1:
            self[:] = self._sort_dsu(self)
        else:
            items = self._sort_dsu(indices)
            for i,x in enumerate(items):
                list.__setitem__(self, indices[i], items[i])
        self.save_feeds_and_notify(True)

    def __hash__(self):
        h = 0
        for item in self:
            h ^= hash(item)
        return h

    def get_feed_with_id(self, id):
        for f in self.flatten_list():
            if f.id == id:
                return f
        return None

    def flatten_list(self, ob=None):
        if ob is None:
            ob = self
        l = []
        for o in ob:
            if isinstance(o, list):
                l = l + self.flatten_list(o)
            else:
                l.append(o)
        return l

feedlist_instance = None

def get_instance():
    global feedlist_instance
    if feedlist_instance is None:
        feedlist_instance = FeedList()
    return feedlist_instance

