# -*- coding: utf-8 -*-
# Moovida - Home multimedia server
# Copyright (C) 2007-2009 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 Moovida with Fluendo's plugins.
#
# The GPL part of Moovida is also available under a commercial licensing
# agreement from Fluendo.
# See "LICENSE.Moovida" in the root directory of this distribution package
# for details on that license.
#
# Author: Olivier Tilloy <olivier@fluendo.com>

"""
Unit tests for the Youtube resource provider.
"""

from twisted.trial.unittest import TestCase
from elisa.core.utils.misc import run_functional_tests_check
from twisted.internet import defer

from elisa.plugins.youtube.resource_provider import YoutubeResourceProvider, \
                                                    API_SERVER, VIDEO_SERVER, \
                                                    IMG_SERVER

from elisa.plugins.youtube.models import YoutubeVideoModel, \
                                         YoutubeVideoListModel

from elisa.plugins.base.models.media import PlayableModel, RawDataModel

from elisa.core.media_uri import MediaUri

import re
import binascii

class TestYoutubeResourceProvider(TestCase):

    """
    This test case tests the YoutubeResourceProvider class.
    """

    def setUp(self):
        run_functional_tests_check()
        def created(provider):
            self.provider = provider
            return provider.initialize()

        create_dfr = YoutubeResourceProvider.create({}).addCallback(created)
        return create_dfr

    def tearDown(self):
        return self.provider.clean()

    def test_get_wrong_uri(self):
        """
        Test trying to get a unexisting URI.
        """
        uri = 'http://%s/feeds/api/standardfeeds/crap' % API_SERVER
        result_model, request_defer = self.provider.get(MediaUri(uri))
        self.failUnlessFailure(request_defer, Exception)
        return request_defer

    def test_get_top_rated(self):
        """
        Test a simple API call.
        """
        uri = 'http://%s/feeds/api/standardfeeds/top_rated' % API_SERVER

        def request_done(result_model):
            self.failUnless(isinstance(result_model, YoutubeVideoListModel))
            self.failUnless(reduce(lambda x, y: x and isinstance(y, YoutubeVideoModel), result_model.videos))
            return result_model

        result_model, request_defer = self.provider.get(MediaUri(uri))
        request_defer.addCallback(request_done)
        return request_defer

    def test_get_playable_wrong_uri(self):
        """
        Test trying to retrieve a playable model from a wrong video id.
        """
        video_id = 'aaaaaaaaaaa'
        uri = 'http://%s/watch?v=%s' % (VIDEO_SERVER, video_id)
        result_model, request_defer = self.provider.get(MediaUri(uri))
        self.failUnlessFailure(request_defer, Exception)
        return request_defer

    def test_get_playable_model(self):
        """
        Test retrieving the playable model for a given video.
        """
        video_id = 'm3gMgK7h-BA'
        uri = 'http://%s/watch?v=%s' % (VIDEO_SERVER, video_id)

        def request_done(result_model):
            self.failUnless(isinstance(result_model, PlayableModel))
            expected = MediaUri('http://%s/get_video' % VIDEO_SERVER)
            self.failUnlessEqual(expected.scheme, result_model.uri.scheme)
            self.failUnlessEqual(expected.host, result_model.uri.host)
            self.failUnlessEqual(expected._path, result_model.uri._path)
            params = result_model.uri._params
            self.failUnless('video_id' in params)
            self.failUnlessEqual(params['video_id'], video_id)
            self.failUnless('t' in params)
            self.failUnless('fmt' in params)
            self.failUnlessEqual(params['fmt'], '18')
            return result_model

        result_model, request_defer = self.provider.get(MediaUri(uri))
        request_defer.addCallback(request_done)
        return request_defer

    def test_get_playable_model_with_context_model(self):
        """
        Test retrieving the playable model for a given video, with a
        contextual model.
        """
        video_id = 'm3gMgK7h-BA'
        uri = 'http://%s/watch?v=%s' % (VIDEO_SERVER, video_id)
        context_model = YoutubeVideoModel()
        context_model.title = 'amazing guitar player'

        def request_done(result_model):
            self.failUnless(isinstance(result_model, PlayableModel))
            self.failUnless(hasattr(result_model, 'title'))
            self.failUnlessEqual(result_model.title, context_model.title)
            return result_model

        result_model, request_defer = self.provider.get(MediaUri(uri), context_model)
        request_defer.addCallback(request_done)
        return request_defer

    def test_get_thumbnail(self):
        """
        Test retrieving a video thumbnail.
        """
        video_id = 'm3gMgK7h-BA'
        thumbnail = '2.jpg'
        uri = 'http://%s/vi/%s/%s' % (IMG_SERVER, video_id, thumbnail)
        image_size = 3173

        def request_done(result_model):
            self.failUnless(isinstance(result_model, RawDataModel))
            self.assertEqual(result_model.size, image_size)
            header = 'ffd8' + 'ffe0' # SOI marker + JFIF marker
            self.assertEqual(binascii.hexlify(result_model.data[:4]), header)
            return result_model

        result_model, request_defer = self.provider.get(MediaUri(uri))
        request_defer.addCallback(request_done)
        return request_defer

    def test_post(self):
        """
        Test a POST request.
        """
        uri = 'http://%s/feeds/api/standardfeeds/crap' % API_SERVER
        dfr = self.provider.post(MediaUri(uri))
        self.failUnlessFailure(dfr, NotImplementedError)
        return dfr
