from unittest import TestCase, TestSuite, makeSuite, main

import Zope
try:
    from Interface.Verify import verifyClass
except ImportError:
    # for Zope versions before 2.6.0
    from Interface import verify_class_implementation as verifyClass

from Products.CMFCore.tests.base.testcase import \
     SecurityTest

from Products.CMFCore.tests.base.utils import \
     has_path

from Products.CMFCore.tests.base.dummy import DummyFTI
from Products.CMFCore.tests.base.dummy import DummyContent

from Products.CMFCore.CatalogTool import CatalogTool
from Products.CMFCore.TypesTool import TypesTool
from Products.CMFCore.URLTool import URLTool
from Products.CMFCore.WorkflowTool import WorkflowTool

from Products.CMFDefault.DiscussionTool import DiscussionTool
from Products.CMFDefault.DiscussionTool import DiscussionNotAllowed
from Products.CMFDefault.DiscussionItem import DiscussionItem
from Products.CMFDefault.DiscussionItem import DiscussionItemContainer


class DiscussionItemTests(TestCase):

    def test_interface(self):
        from Products.CMFCore.interfaces.Dynamic \
                import DynamicType as IDynamicType
        from Products.CMFCore.interfaces.Contentish \
                import Contentish as IContentish
        from Products.CMFCore.interfaces.Discussions \
                import DiscussionResponse as IDiscussionResponse

        verifyClass(IDynamicType, DiscussionItem)
        verifyClass(IContentish, DiscussionItem)
        verifyClass(IDiscussionResponse, DiscussionItem)


class DiscussionItemContainerTests(TestCase):

    def test_interface(self):
        from Products.CMFCore.interfaces.Discussions \
                import Discussable as IDiscussable

        verifyClass(IDiscussable, DiscussionItemContainer)


class DiscussionTests( SecurityTest ):

    def setUp( self ):

        SecurityTest.setUp(self)

        root = self.root
        root._setObject( 'portal_discussion', DiscussionTool() )
        self.discussion_tool = root.portal_discussion
        root._setObject( 'portal_catalog', CatalogTool() )
        self.catalog_tool = root.portal_catalog
        root._setObject( 'portal_url', URLTool() )
        self.url_tool = root.portal_url
        root._setObject( 'portal_workflow', WorkflowTool() )
        self.workflow_tool = root.portal_workflow
        root._setObject( 'portal_types', TypesTool() )
        types_tool = self.types_tool = root.portal_types
        try: root._delObject('test')
        except AttributeError: pass
        root._setObject( 'test', DummyContent( 'test', catalog=1 ) )

    def test_policy( self ):

        test = self.root.test
        self.assertRaises( DiscussionNotAllowed
                         , self.discussion_tool.getDiscussionFor
                         , test
                         )
        assert getattr( test, 'talkback', None ) is None

        test.allow_discussion = 1
        assert self.discussion_tool.getDiscussionFor( test )
        assert test.talkback

        del test.talkback
        del test.allow_discussion
        self.types_tool._setObject( 'Dummy Content', DummyFTI )
        self.assertRaises( DiscussionNotAllowed
                         , self.discussion_tool.getDiscussionFor
                         , test
                         )
        assert getattr( test, 'talkback', None ) is None

        ti = getattr(self.types_tool, 'Dummy Content')
        ti.allow_discussion = 1
        assert self.discussion_tool.getDiscussionFor( test )
        assert test.talkback

        del test.talkback
        ti.allow_discussion = 0
        self.assertRaises( DiscussionNotAllowed
                         , self.discussion_tool.getDiscussionFor
                         , test
                         )
        assert getattr( test, 'talkback', None ) is None

        test.allow_discussion = 1
        assert self.discussion_tool.getDiscussionFor( test )
        assert test.talkback

    def test_nestedReplies( self ):
        test = self.root.test
        test.allow_discussion = 1
        talkback = self.discussion_tool.getDiscussionFor( test )
        assert talkback._getDiscussable() == test
        assert talkback._getDiscussable( outer=1 ) == test
        assert not talkback.hasReplies( test )
        assert len( talkback.getReplies() ) == 0

        reply_id = talkback.createReply( title='test', text='blah' )
        assert talkback.hasReplies( test )
        assert len( talkback.getReplies() ) == 1
        assert talkback.getReply( reply_id )

        reply1 = talkback.getReplies()[0]
        items = talkback._container.items()
        assert items[0][0] == reply1.getId()
        assert reply1.inReplyTo() == test

        parents = reply1.parentsInThread()
        assert len( parents ) == 1
        assert test in parents

        talkback1 = self.discussion_tool.getDiscussionFor( reply1 )
        assert talkback == talkback1
        assert len( talkback1.getReplies() ) == 0
        assert len( talkback.getReplies() ) == 1

        talkback1.createReply( title='test2'
                             , text='blah2'
                             )
        assert len( talkback._container ) == 2
        assert talkback1.hasReplies( reply1 )
        assert len( talkback1.getReplies() ) == 1
        assert len( talkback.getReplies() ) == 1

        reply2 = talkback1.getReplies()[0]
        assert reply2.inReplyTo() == reply1

        parents = reply2.parentsInThread()
        assert len( parents ) == 2
        assert parents[ 0 ] == test
        assert parents[ 1 ] == reply1

        parents = reply2.parentsInThread( 1 )
        assert len( parents ) == 1
        assert parents[ 0 ] == reply1

    def test_itemCataloguing( self ):

        test = self.root.test
        catalog = self.catalog_tool._catalog
        test.allow_discussion = 1
        assert len( self.catalog_tool ) == 1
        assert has_path( catalog, test.getPhysicalPath() )
        talkback = self.discussion_tool.getDiscussionFor( test )
        assert talkback.getPhysicalPath() == ( '', 'test', 'talkback' ), \
            talkback.getPhysicalPath()
        talkback.createReply( title='test'
                            , text='blah'
                            )
        assert len( self.catalog_tool ) == 2
        for reply in talkback.getReplies():
            assert has_path( catalog, reply.getPhysicalPath() )
            assert has_path( catalog
                           , '/test/talkback/%s' % reply.getId() )

        reply1 = talkback.getReplies()[0]
        talkback1 = self.discussion_tool.getDiscussionFor( reply1 )
        talkback1.createReply( title='test2'
                             , text='blah2'
                             )
        for reply in talkback.getReplies():
            assert has_path( catalog, reply.getPhysicalPath() )
            assert has_path( catalog
                           , '/test/talkback/%s' % reply.getId() )
        for reply in talkback1.getReplies():
            assert has_path( catalog, reply.getPhysicalPath() )
            assert has_path( catalog
                           , '/test/talkback/%s' % reply.getId() )

    def test_deletePropagation( self ):

        test = self.root.test

        test.allow_discussion = 1
        talkback = self.discussion_tool.getDiscussionFor( test )
        talkback.createReply( title='test'
                            , text='blah'
                            )
        self.root._delObject( 'test' )
        assert len( self.catalog_tool ) == 0

    def test_deleteReplies(self):
        test = self.root.test
        test.allow_discussion = 1

        talkback = self.discussion_tool.getDiscussionFor(test)
        id1 = talkback.createReply(title='test1', text='blah')
        reply1 = talkback.getReply(id1)
        talkback1 = self.discussion_tool.getDiscussionFor(reply1)
        id2 = talkback1.createReply(title='test2', text='blah')
        reply2 = talkback1.getReply(id2)
        talkback2 = self.discussion_tool.getDiscussionFor(reply2)
        id3 = talkback2.createReply(title='test3', text='blah')
        reply3 = talkback.getReply(id3)
        talkback3 = self.discussion_tool.getDiscussionFor(reply3)
        self.assertEqual(len(talkback.getReplies()), 1)
        self.assertEqual(len(talkback1.getReplies()), 1)
        self.assertEqual(len(talkback2.getReplies()), 1)
        self.assertEqual(len(talkback3.getReplies()), 0)

        talkback.deleteReply(id2)
        self.assertEqual(len(talkback.getReplies()), 1)
        reply1 = talkback.getReply(id1)
        talkback1 = self.discussion_tool.getDiscussionFor(reply1)
        self.assertEqual(len(talkback.getReplies()), 1)
        self.assertEqual(len(talkback1.getReplies()), 0)

def test_suite():
    return TestSuite((
        makeSuite( DiscussionItemTests ),
        makeSuite( DiscussionItemContainerTests ),
        makeSuite( DiscussionTests ),
        ))

if __name__ == '__main__':
    main(defaultTest='test_suite')
