# Elisa - Home multimedia server
# Copyright (C) 2006-2008 Fluendo Embedded S.L. (www.fluendo.com).
# All rights reserved.
#
# This file is available under one of two license agreements.
#
# This file is licensed under the GPL version 3.
# See "LICENSE.GPL" in the root of this distribution including a special
# exception to use Elisa with Fluendo's plugins.
#
# The GPL part of Elisa is also available under a commercial licensing
# agreement from Fluendo.
# See "LICENSE.Elisa" in the root directory of this distribution package
# for details on that license.

from elisa.core.tests.elisa_test_case import ElisaTestCase
from elisa.core import plugin
from elisa.core import media_manager, metadata_manager, media_uri
from elisa.base_components import media_provider, metadata_provider
from elisa.core.tests.test_metadata_provider import FooMetadataProvider, BarMetadataProvider

from twisted.internet import defer, threads

class GooMetadataProvider(metadata_provider.MetadataProvider):

    def get_rank(self):
        rank = 0
        return rank

    def able_to_handle(self, dict):
        if not dict.has_key('uri'):
            return False

        uri = dict['uri']

        if uri.scheme == 'goo':
            return True
        return False

    def get_metadata(self, dict, low_priority=False):
        d = threads.deferToThread(self._get_metadata,dict)
        return d

    def _get_metadata(self, dict):
        if not dict.has_key('uri'):
            return dict
        dict['artist'] =  'Foo'
        dict['album'] =  'Bar'
        return dict

class FailingMetadataProvider(metadata_provider.MetadataProvider):

    def get_rank(self):
        return 0

    def able_to_handle(self, dict):
        if not dict.has_key('uri'):
            return False

        uri = dict['uri']

        if uri.scheme == 'failing':
            return True
        return False

    def get_metadata(self, dict, low_priority=False):
        failing

class NotCriticallyFailingProvider(metadata_provider.MetadataProvider):
    def get_rank(self):
        return 0

    def able_to_handle(self, dict):
        if not dict.has_key('uri'):
            return False

        uri = dict['uri']

        if uri.scheme == 'non_critically_failing':
            return True
        return False

    def get_metadata(self, dict, low_priority=False):
        return defer.failure(MetadataError())

class FooPlugin(plugin.Plugin):
    name = 'foo'
    components = {'foo_meta': {'path':FooMetadataProvider},
                  'goo_meta': {'path':GooMetadataProvider},
                  'failing_meta': {'path':FailingMetadataProvider}
                  }

class BarPlugin(plugin.Plugin):
    name = 'bar'
    components = {'bar_meta': {'path':BarMetadataProvider}}



class TestMetadataManager(ElisaTestCase):

    def setUpClass(self):
        self.orig_log_failure = None

    def setUp(self):
        ElisaTestCase.setUp(self)

        # Silly
        from elisa.core.common import application
        registry = application.plugin_registry
        registry.register_plugin(FooPlugin)
        registry.register_plugin(BarPlugin)

        self._manager = metadata_manager.MetadataManager()
        self._manager.register_component(registry.create_component('foo:foo_meta'))
        self._manager.register_component(registry.create_component('foo:goo_meta'))
        self._manager.register_component(registry.create_component('foo:failing_meta'))
        self._manager.register_component(registry.create_component('bar:bar_meta'))

        if self.orig_log_failure is None:
            self.orig_log_failure = application.log_failure
        else:
            # unpatch log_failure here so we don't risk to screw up all the
            # other tests
            application.log_failure = self.orig_log_failure

    def test_metadata_retrieval_bar(self):
        bar_uri = media_uri.MediaUri(u'bar://foo')
        bar_dict = {'uri' : bar_uri, 'album' : None}

        def callIn(dict):
            self.assertEquals(dict, {'uri' : bar_uri, 'album': 'bar',
                                     'cover': 'fool', 'artist': 'foo'})


        df = self._manager.get_metadata(bar_dict)
        df.addCallback(callIn)
        return df

    def test_metadata_retrieval_foo(self):
        bar_uri = media_uri.MediaUri(u'foo://bar')
        bar_dict = {'uri' : bar_uri, 'artist' : None, 'album' : None}

        def callIn(dict):
            self.assertEquals(dict, {'uri' : bar_uri, 'artist' : 'foo',
                                     'album': 'bar'})


        df = self._manager.get_metadata(bar_dict)
        df.addCallback(callIn)
        return df

    def test_metadata_retrieval_cover(self):
        bar_uri = media_uri.MediaUri(u'foo://bar')
        bar_dict = {'uri' : bar_uri, 'artist' : None, 'album' : None,
                    'cover': None}

        def callIn(dict):
            self.assertEquals(dict, {'uri' : bar_uri, 'artist' : 'foo',
                                     'album': 'bar', 'cover' : 'fool'})

        df = self._manager.get_metadata(bar_dict)
        df.addCallback(callIn)
        return df

    def test_metadata_retrieval_failing(self):
        uri = media_uri.MediaUri(u'failing://bar')
        metadata = {'uri': uri, 'artist': None, 'album': None}

        # use a tag object to check that log_failure is called
        context = dict(called=False)
        def log_failure(*args):
            context['called'] = True

        from elisa.core.common import application
        application.log_failure = log_failure

        def check_failure_logged(result):
            self.assertTrue(context['called'], 'critical error not logged')

        dfr = self._manager.get_metadata(metadata)
        dfr.addCallback(check_failure_logged)

        return dfr
    
    def test_metadata_non_critical_failure(self):
        uri = media_uri.MediaUri(u'non_critically_failing://bar')
        metadata = {'uri': uri, 'artist': None, 'album': None}

        # use a tag object to check that log_failure is called
        context = dict(called=False)
        def log_failure(*args):
            context['called'] = True

        from elisa.core.common import application
        application.log_failure = log_failure

        def check_failure_logged(result):
            self.assertFalse(context['called'], 'non critical error logged')

        dfr = self._manager.get_metadata(metadata)
        dfr.addCallback(check_failure_logged)

        return dfr
        
