#######################################################
#                                                     #
#    Copyright (C), 2004, Raphael Ritz                #
#    <r.ritz@biologie.hu-berlin.de>                   #
#                                                     #
#    Humboldt University Berlin                       #
#                                                     #
# Copyright (C), 2005, Logilab S.A. (Paris, FRANCE)   #
# http://www.logilab.fr/ -- mailto:contact@logilab.fr #
#                                                     #
#######################################################

__revision__ = '$Id:  $'


import os, sys

if __name__ == '__main__':
    execfile(os.path.join(sys.path[0], 'framework.py'))

from Testing import ZopeTestCase
from Products.CMFPlone.tests import PloneTestCase
from Products.CMFBibliographyAT.tests import setup
from ZODB.PersistentList import PersistentList
from Globals import PersistentMapping



#ZopeTestCase.installProduct('DeadlockDebugger')
#import Products.DeadlockDebugger

class TestBibliographyFolder(PloneTestCase.PloneTestCase):
    '''Test the BibliographyFolder Import and duplication handling'''
    
    def afterSetUp(self):
        self._refreshSkinData()
        self.bf = self.getEmptyBibFolder()
        bib_source = open(setup.BIBTEX_TEST_BIB, 'r').read()
        self.bf.processImport(bib_source, 'bibtex_test.bib')

    #FIXME duplicate from testBibliographyFolder - REFACTOR
    def getEmptyBibFolder(self, ident ='bib_folder'):
        uf = self.folder
        uf.invokeFactory(type_name = "BibliographyFolder",
                         id = ident )
        return getattr(uf, ident)
    
    def testBibtexImportDuplicate(self):
        bibtool = self.portal.portal_bibliography
        filter = {'portal_type': bibtool.getReferenceTypes(), }

	self.insertDuplicates()
        self.assertEquals(len(self.bf.contentIds(filter=filter)), 3 ,
                          'Duplicate Entry was introduced, expected 3 unique entries')

    def insertDuplicates(self):
        bib_source = open(setup.BIBTEX_TEST_BIB_DUP, 'r').read()
        self.bf.processImport(bib_source, 'bibtex_test_duplicates.bib')

    def insertSameImportFile(self):
        bib_source = open(setup.BIBTEX_TEST_BIB, 'r').read()
        self.bf.processImport(bib_source, 'bibtex_test.bib')


    def testBibtexImportDuplicate_Access(self):
        self.insertDuplicates()

        self.assertNotEqual(self.bf.getDuplicatesFolder().contentValues(), [])

        dup_entry = self.bf.getDuplicatesFolder().contentValues()[0]
        self.assertEquals(dup_entry.Title(), 'Programming Python.')
        self.assertEquals(len(dup_entry.getIs_duplicate_of()), 1)

    def testNewFolderCriterias(self):
        """
        testes that the import_criterias for a fold changed after
        being modifieded (folder bg)
        """
        duplicates_criteria = {'BookReference' : PersistentList(('authors', 'title')) }
  
        self.second_bf = self.getEmptyBibFolder('second_bib_folder')

        old_criterias = self.bf.getCriterias()
        sec_old_criterias = self.second_bf.getCriterias()
        
        for bib_type in duplicates_criteria.keys():
            self.bf.setCriteriasForType(bib_type, duplicates_criteria[bib_type])
 
        new_criterias = self.bf.getCriterias()
        sec_new_criterias = self.second_bf.getCriterias()

        self.assertNotEquals(old_criterias, new_criterias,
                              'Criterias have not been changed')
 
        self.assertEquals(sec_old_criterias, sec_new_criterias,
                              'Criterias have been changed')

    def testLocalGlobalDistinction(self):
        bibtool = self.portal.portal_bibliography
        filter = {'portal_type': bibtool.getReferenceTypes(), }

        # insert 3 entries in second_bib_folder
        second_bf = self.getEmptyBibFolder('second_bib_folder')
        bib_source = open(setup.BIBTEX_TEST_BIB, 'r').read()
        second_bf.processImport(bib_source, 'bibtex_test.bib')

        folder_contents = [ c for c in self.folder.contentIds() if c != '.personal' ]
        self.assertEquals(folder_contents, ['bib_folder', 'second_bib_folder'])
        self.assertEquals(len(folder_contents), 2)

        # do a global import of bib_folder
        bibtool = self.portal.portal_bibliography
        bib_source = open(setup.BIBTEX_TEST_BIB_DUP, 'r').read()
        entries = bibtool.getEntries(bib_source, None, 'bibtex_test_duplicates.bib')
        for entry in entries:
            if entry.get('title'):
                upload = self.bf.processSingleImport(entry, span_of_search='global')

        # check matches 2 
        dup_entry = self.bf.getDuplicatesFolder().contentValues()[0]
        self.assertEquals(len(dup_entry.getIs_duplicate_of()), 2)


    def testCriteriasScope(self):
        """
        testes
        set 1 :
           Changing criterias for a folder (self.bg) doesn't imply changing
           those of another folder (self.second_bg)
        set 2 :
           If criterias for a folder had been changed, changing
           portal criterias has no influence on them (self.bg),
           otherwise, a folder gets new portal criterias (self.second_bg)
        
        
        """
        bibtool = self.portal.portal_bibliography
        port_old_criterias = bibtool.getSelectedCriteria()

        folder_criterias = {'BookReference' : ('authors', 'title') }
        portal_criterias = {'ArticleReference' :
                                   ('publication_year', 'title')}
        self.second_bf = self.getEmptyBibFolder('second_bib_folder')

        #port_old_criterias = PersistentMapping()
        for key, value in bibtool.getSelectedCriteria().items():
            port_old_criterias[key] = value

        ### set 1
  
        old_criterias = self.bf.getCriterias()
        sec_old_criterias = self.second_bf.getCriterias()
        #changes criterias on first folder
        for bib_type in folder_criterias.keys():
            self.bf.setCriteriasForType(bib_type, \
                                        folder_criterias[bib_type])
        new_criterias = self.bf.getCriterias()
        sec_new_criterias = self.second_bf.getCriterias()

        #Criterias on Folder1 should got changed
        self.assertNotEquals(old_criterias, new_criterias,
                              'Folder1 criterias have not been changed')

        #Criterias for Folder2 should stay unchanged
        self.assertEquals(sec_old_criterias, sec_new_criterias,
                              'Folder2 criterias have been changed')
        
        #Criterias for Folder2 should be equal to those of Portal
	self.assertEquals(sec_new_criterias, port_old_criterias,
                              'Folder2 criterias are not equal to those of Portal')

        #Criterias for Folder1 should not be equal to those of Portal
        self.assertNotEquals(new_criterias, port_old_criterias,
                              'Folder1 criterias are equal to those of Portal')

        ### set 2
   
        #changes criterias on bibliography tool
        for bib_type in portal_criterias.keys():
            bibtool.setCriteriasForType(bib_type,\
                                        portal_criterias[bib_type])
        port_new_criterias = bibtool.getSelectedCriteria()
   
        new2_criterias = self.bf.getCriterias()
	
        self.second_bf = self.getEmptyBibFolder('another_second_bib_folder')
        sec_new2_criterias = self.second_bf.getCriterias()
  
        #portal criterias should got changed
        self.assertNotEquals(port_old_criterias, port_new_criterias,
                             'Portal criterias have not been changed')


        #Criterias for Folder1 should stay unchanged
        self.assertEquals(new_criterias, new2_criterias,
                              'Folder 1 criterias have been changed')
        #Criterias for Folder2 should be those of Portal
        self.assertEquals(port_new_criterias, sec_new2_criterias,
                              'Criterias For Folder 2 are not those of Portal')

    def testZeroCriterias(self):
        """
        testes an import without criterais specified
        """
	bibtool = self.portal.portal_bibliography
        filter = {'portal_type': bibtool.getReferenceTypes(), }

        self.bf.setCriterias({})
        self.insertDuplicates()
	# 4 bibref items, no duplicate folder
	self.assertEquals(len(self.bf.contentIds(filter=filter)), 4,
                          'Import failed, expected 4 entries')

    def testDuplicateImportFolderWideCriterias(self):
        """
        bibtex_test.bib contains 2 entries of BookReference type and
        1 entry of WebpublishedReference type
        """
        folder_criterias = {'BookReference' : () }
        bibtool = self.portal.portal_bibliography
        filter = {'portal_type': bibtool.getReferenceTypes(), }

        self.insertSameImportFile()
        self.assertEquals(len(self.bf.contentIds(filter=filter)), 3 ,
                          'Import failed, expected 3 entries')

        #set criterais for BookReference type to ()
        for bib_type in folder_criterias.keys():
            self.bf.setCriteriasForType(bib_type, \
                                        folder_criterias[bib_type])
        self.insertSameImportFile()
        self.assertEquals(len(self.bf.contentIds(filter=filter)), 5,
                          'Import failed, expected 5 entries')

    def testDuplicateImportCriterias(self):
        """
        bibtex_test.bib contains 2 entries of BookReference type and
        1 entry of WebpublishedReference type
        """
        portal_criterias = {'BookReference' : () }
        bibtool = self.portal.portal_bibliography
        filter = {'portal_type': bibtool.getReferenceTypes(), }

	# tests : portal wide criterias
        # set portal criterias for BookReference type to ()
        for bib_type in portal_criterias.keys():
            bibtool.setCriteriasForType(bib_type, \
                                        portal_criterias[bib_type])

        self.insertSameImportFile()
        self.assertEquals(len(self.bf.contentIds(filter=filter)), 3 ,
                          'Import failed, expected 3 entries')
        
	###
	### the next test is deprecated as the behaviour of the duplicates
	### engine has slightly changed: bib_tool duplicates criteria are
	### only adopted on bibfolder creation, afterwards there will be 
	### no further influence on bibfolder criteria by the bib_tool.
	### mg, 20061121
	
	## tests : portal wide criterias
        ## set portal criterias for BookReference type to ()
        #for bib_type in portal_criterias.keys():
        #    bibtool.setCriteriasForType(bib_type, \
        #                                portal_criterias[bib_type])
        #
	#self.insertSameImportFile()
	#print len(self.bf.contentIds(filter=filter))
        #self.assertEquals(len(self.bf.contentIds(filter=filter)), 5, 
        #                  'Import failed, expected 5 entries')

        # tests : folder wide criterias
        #set folder criterias for BookReference to ()
        
	folder_criterias = {'BookReference' : () }
        for bib_type in folder_criterias.keys():
            self.bf.setCriteriasForType(bib_type, \
                                        folder_criterias[bib_type])
        self.insertSameImportFile()
        self.assertEquals(len(self.bf.contentIds(filter=filter)), 5,
                          'Import failed, expected 5 entries')



    def testBibtexImportDuplicate_2matches(self):
        """ test that the references in the duplicated entry is multiple"""
        bibtool = self.portal.portal_bibliography
        filter = {'portal_type': bibtool.getReferenceTypes(), }

        bib_source = open(setup.BIBTEX_TEST_BIB_DUP, 'r').read()
        self.bf.processImport(bib_source, 'bibtex_test_duplicates.bib')
        self.assertEquals(len(self.bf.contentIds(filter=filter)), 3 ,
                          'Duplicate Entry was introduced, expected 3 unique entries')

    def testDelay(self):
        func_name = 'delayDuplicated'
        nb_end = 1
        expected_logs = []
        self.action_test(func_name, expected_logs, nb_end)

    def testSkip(self):
        func_name = 'skipDuplicated'
        nb_end = 0
        expected_logs = []
        self.action_test(func_name, expected_logs, nb_end)

    # FIXME - freeze - from previous (force)?
    def testReplace(self):
        func_name = 'replaceDuplicated'
        nb_end = 0
        expected_logs = ['replace begin implemented']
        self.action_test(func_name, expected_logs, nb_end)
        # check UID hasn't changed
        # check edition has changed to 3rd
        #self.bf. check 

    def testForce(self):
        bibtool = self.portal.portal_bibliography
        filter = {'portal_type': bibtool.getReferenceTypes(), }

        func_name = 'forceDuplicated'
        nb_end = 0
        expected_logs = None
        self.action_test(func_name, expected_logs, nb_end)
        self.assertEquals(len(self.bf.contentIds(filter=filter)), 4,
                          'Duplicate Entry was not forcefully introduced, expected 4 entries')

    def action_test(self, func_name, expected_logs, nb_end):
        """
        if expected_logs is None - don't test logs
        """
        logs = []
        self.insertDuplicates()
        duplicates = self.bf.getDuplicates()
        self.assertEquals(len(duplicates), 1, 'beginning count is not right')
        
        for key, each_duplicated_entry in duplicates.items():
            action_func = getattr(self.bf, func_name)
            msg = action_func(key)
            if msg:
                logs.append(msg)
        if not expected_logs is None:
            self.assertEquals(logs, expected_logs)

        duplicates = self.bf.getDuplicates()
        #self.assertEquals(len(self.bf._duplicates), nb_end)
        self.assertEquals(len(duplicates), nb_end, 'end count is not right')


    # test logs
    def testBibtexImportLogs(self):
        # do a global import of bib_folder
        bibtool = self.portal.portal_bibliography
        bib_source = open(setup.BIBTEX_TEST_BIB_DUP, 'r').read()
        entries = bibtool.getEntries(bib_source, None, 'bibtex_test_duplicates.bib')
        logs = []
        for entry in entries:
            if entry.get('title'):
                upload = self.bf.processSingleImport(entry, span_of_search='global')
		obj = upload[2]
                if upload:
                    logs.append(upload)
        self.assertEquals(logs, [('Skipped: Programming Python.\n', 'SKIPPED', obj, )])


  
        
def test_suite():
    from unittest import TestSuite, makeSuite
    suite = TestSuite()
    suite.addTest(makeSuite(TestBibliographyFolder))
    return suite

if __name__ == '__main__':
    framework()
