from zope.app.container.sample import SampleContainer
from zope.app.container.contained import Contained
from zope.event import notify
from DateTime import DateTime

from Products.ploneundelete.interfaces import IUndeleteContainer
from Products.CMFEditions.interfaces.IArchivist import ArchivistUnregisteredError
from OFS.event import ObjectWillBeRemovedEvent

# Define some fake objects for our tests

history_ids = []
_marker = []

class FakeRepository(object):
    """A fake CMFEditions portal repository, which stores a shallow copy of
       the object's dict along with a coment, uder id, and version id in
       a list for each object uid."""

    def __init__(self):
        self._storage = {}
        self.autoapply = True

    def getVersionableContentTypes(self):
        return ('VersionedObject',)

    def isUpToDate(self, obj):
        repo = self.getHistory(obj)
        if repo:
            return repo[-1].object.modified == obj.modified
        return False

    def setAutoApplyMode(self, value):
        self.autoapply = value

    def save(self, obj, comment):
        if self.autoapply and getattr(obj, 'history_id', None) is None:
            obj.history_id = len(history_ids)
            history_ids.append(obj.history_id)
        history = self._storage.setdefault(obj.history_id, [])
        history.append((obj.__dict__.copy(), comment, 'bogus_user', len(history)))

    def getHistory(self, obj):
        hist_id = getattr(obj, 'history_id', None)
        repo = self._storage.get(hist_id, None)
        if repo is None:
            raise ArchivistUnregisteredError
        hist_list = []
        for i in range(len(repo)):
            hist_list.append(HistoryWrapper(*repo[i]))
        return hist_list

    def restore(self, history_id, selector, container, new_id=None):
        saved = HistoryWrapper(*self._storage[history_id][selector])
        new =  VersionedObject(obj=saved.object)
        if not new_id:
            new_id = new.getId()
        container[new_id] = new

class FakeUIDHandler(object):
    def queryUid(self, obj, default=None):
        """A trivial UID handler implementation which assumes that the uid is
           stored as an attribute history_id on the object itself"""
        return getattr(obj, 'history_id', default)

class HistoryWrapper(object):
    """Something that looks like CMFEditions VersionData, for handling the
       revisions stored in our fake repository."""
    def __init__(self, struct, comment, principal, version_id):
        self.version_id = version_id
        self.sys_metadata = {}
        self.sys_metadata['principal'] = principal
        self.comment = comment
        self.object = ProxyObject(struct)

class ProxyObject(object):
    """A simple wrapper which is used to present the historical object"""
    def __init__(self, my_dict):
        self.__dict__.update(my_dict)

class VersionedObject(Contained):
    """A fake piece of Plone content which will be versioned for testing"""
    def __init__(self, id=None, obj=None):
        if obj is not None:
            self.__dict__.update(obj.__dict__)
        if id is not None:
            self.id = self.__name__ = id
        self.modified = DateTime()
        self.portal_type = 'VersionedObject'

    def __setattr__(self, name, value):
        super(VersionedObject, self).__setattr__(name, value)
        if name != 'modified':
            self.modified = DateTime()

    def getId(self):
        return self.id

    def Title(self):
        return self.title

    def getPortalTypeName(self):
        return self.portal_type

class FakeContainer(SampleContainer):
    """A container that we will undelete objects from it provides our fake
       tools.  It also fires before undelete events."""
    def __init__(self):
        super(FakeContainer, self).__init__()
        self.portal_repository = FakeRepository()
        self.portal_uidhandler = FakeUIDHandler()

    def __delitem__(self, name):
        notify(ObjectWillBeRemovedEvent(self[name], self, name))
        super(FakeContainer, self).__delitem__(name)