"""
open/dulcinea/lib/item.py
"""
from dulcinea.base import DulcineaPersistent
from dulcinea.common import format_date
from dulcinea.partition import PartKeyed, Partition
from dulcinea.timestamped import Timestamped, reverse_timestamp_sorted
from durus.btree import BTree
from qp.lib.spec import add_getters_and_setters, string, boolean, init


class Item(DulcineaPersistent, PartKeyed, Timestamped):

    title_is = (string, None)
    approved_is = boolean

    def __init__(self):
        assert self.__class__ is not Item, "abstract class"
        PartKeyed.__init__(self)
        Timestamped.__init__(self)
        init(self, approved=False)

    def is_new(self):
        return self.key is None

    def is_expired(self):
        if self.part_key == 'expired':
            return True
        return False

    def absorb(self, other):
        assert self.__class__ is other.__class__
        for key, value in other.__getstate__().items():
            if key != 'key':
                setattr(self, key, value)

    def get_search_text(self):
        return ' '.join(self.get_search_text_fields())

    def get_search_text_fields(self):
        return [self.get_title() or '', format_date(self.get_timestamp())]

    def is_approved(self):
        return self.approved

    def can_modify(self, user):
        return user.is_admin()

add_getters_and_setters(Item)


class ItemFolder(Partition):

    def __init__(self, value_spec=Item):
        Partition.__init__(self, value_spec=value_spec, part_key_spec=('active', 'expired'))
        init(self)
        self.parts['active'] = BTree()
        self.parts['expired'] = BTree()

    def get_all(self):
        return self.get_active() + self.get_expired()

    def get_active(self):
        return list(self.get_part('active').itervalues())

    def get_expired(self):
        return list(self.get_part('expired').itervalues())

    def get_recent_items(self, count=None, include_unapproved=False):
        """(count : int = None, include_unapproved : bool = False) -> [Item]

        Return the 'count' most recent items.  If 'include_unapproved' is True,
        both un-approved and approved items are returned.
        The list returned is in reverse-chronological order by timestamp.
        """
        return reverse_timestamp_sorted(
            [item for item in self.get_active()
             if item.is_approved() or include_unapproved])[:count]

    def get_to_oldest_date(self, oldest_date, **kwargs):
        if oldest_date is not None:
            return [item for item in self.get_recent_items(**kwargs)
                    if item.get_timestamp() >= oldest_date]
        return self.get_recent_items(**kwargs)


def partition_item_folder(item_folder, item_class):
    '''Convert a Keep-style ItemFolder and Items within into a two part Partition
    '''
    from durus.persistent import PersistentObject
    from durus.btree import BTree

    def __setstate__(self, state):
        if 'mapping' in state:
            parts = BTree()
            parts['active'] = state['mapping']
            parts['expired'] = BTree()
            state['parts'] = parts
            del state['mapping']
        PersistentObject.__setstate__(self, state)

    item_folder.__class__.__setstate__ = __setstate__
    item_folder.value_spec = item_class
    item_folder.part_key_spec = ('active', 'expired')
    item_folder._p_note_change()

    for item in item_folder.get_part('active').itervalues():
        item.part_key = 'active'
