# -*- 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 Flickr API helper functions.
"""

from twisted.trial.unittest import TestCase, SkipTest

from elisa.plugins.flickr.resource_provider import FlickrResourceProvider
from elisa.plugins.flickr import flickr_api as flickr
from elisa.plugins.flickr.models import FlickrPhotoModel

from elisa.core.media_uri import MediaUri

try:
    from hashlib import md5
except ImportError:
    # hashlib is new in Python 2.5
    from md5 import md5

from xml.dom import minidom
import os.path
import shutil


class TestFlickrAPIOffline(TestCase):

    """
    This test case tests offline helper functions.
    """

    def setUpClass(self):
        # Backup the pointer to the real function
        self.get_token_file = flickr.get_token_file

        # Simulate that the application is already authenticated
        def get_dummy_token_file():
            return os.path.join(os.path.abspath('.'),
                    'flickr', 'dummy', 'auth.xml')

        flickr.get_token_file = get_dummy_token_file

    def tearDownClass(self):
        # Restore the pointer to the real function
        flickr.get_token_file = self.get_token_file

    def test_sign(self):
        """
        Test signing a method given its parameters.
        """
        arguments = {'method': 'flickr.auth.getFrob',
                     'api_key': flickr._key}
        flickr.sign_arguments(arguments)
        self.failUnless('api_sig' in arguments.keys())
        md5_sum = md5(flickr._secret + 'api_key' + flickr._key + \
                      'methodflickr.auth.getFrob').hexdigest()
        self.failUnlessEqual(arguments['api_sig'], md5_sum)

    def test_save_token(self):
        """
        Test saving the token to a local cache file.
        """
        token_file = flickr.get_token_file()
        token_path = os.path.dirname(token_file)
        shutil.rmtree(token_path)

        token = 'dummytoken'
        flickr._save_token(token)
        self.failUnless(os.path.exists(token_file))
        f = file(token_file)
        self.failUnlessEqual(f.read(), token)
        f.close()

    def test_authenticate_1_cached(self):
        """
        Test the authentication process when the application is already
        authenticated and the authentication token is locally cached.
        """
        token = 'dummytoken'
        token_response = minidom.parseString('<?xml version="1.0" ?>' + \
            '<rsp stat="ok"><auth><token>'+ token + '</token>' + \
            '<perms>read</perms><user fullname="Dummy User" ' + \
            'nsid="99999999@A11" username="dummy" /></auth>' + \
            '</rsp>').toprettyxml()
        flickr._save_token(token_response)

        def got_login(login):
            self.failUnlessEqual(len(login), 1)
            self.failUnless(login.has_key('token'))
            self.failUnlessEqual(login['token'], token)
            return login

        login_dfr = flickr.authenticate_1(None)
        login_dfr.addCallback(got_login)
        return login_dfr

    def test_build_photo_url(self):
        """
        Test building the list of image URIs for a photo model.
        """
        model = FlickrPhotoModel()
        model.farm = 1
        model.server = 2
        model.flickr_id = 'abcdef'
        model.secret = 'ghijkl'
        flickr.build_photo_url(model)
        self.failUnless(hasattr(model, 'images'))
        self.failUnlessEqual(len(model.images.references), 4)
        thumbnail = 'http://farm1.static.flickr.com/2/abcdef_ghijkl_t.jpg'
        small = 'http://farm1.static.flickr.com/2/abcdef_ghijkl_m.jpg'
        medium = 'http://farm1.static.flickr.com/2/abcdef_ghijkl.jpg'
        large = 'http://farm1.static.flickr.com/2/abcdef_ghijkl_b.jpg'
        self.failUnlessEqual(model.images.references[0], MediaUri(thumbnail))
        self.failUnlessEqual(model.images.references[1], MediaUri(small))
        self.failUnlessEqual(model.images.references[2], MediaUri(medium))
        self.failUnlessEqual(model.images.references[3], MediaUri(large))

class TestFlickrAPIOnline(TestCase):

    """
    This test case tests online helper functions (those need a resource
    provider to do actual queries to the Flickr API).
    """

    def setUpClass(self):
        # Backup the pointer to the real function
        self.get_token_file = flickr.get_token_file

        # Simulate that the application is already authenticated
        def get_dummy_token_file():
            return os.path.expanduser(os.path.join('~', '.flickr', 'dummy',
                                                   'auth.xml'))

        flickr.get_token_file = get_dummy_token_file

    def tearDownClass(self):
        # Restore the pointer to the real function
        flickr.get_token_file = self.get_token_file

    def setUp(self):
        raise SkipTest("MANUAL TEST")
        self.provider = FlickrResourceProvider()
        return self.provider.initialize()

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

    def test_authenticate_1(self):
        """
        Test the first authentication step.
        """
        # Make sure the application is not authenticated yet
        token_file = flickr.get_token_file()
        if os.path.exists(token_file):
            os.remove(token_file)

        def got_login(login):
            root = 'http://flickr.com/services/auth/?'
            self.failUnless(login['url'].startswith(root))
            args = login['url'][len(root):].split('&')
            keys = sorted([str(arg.split('=')[0]) for arg in args])
            self.failUnlessEqual(keys, ['api_key', 'api_sig', 'frob', 'perms'])
            print login
            return login

        login_dfr = flickr.authenticate_1(self.provider)
        login_dfr.addCallback(got_login)
        return login_dfr


class ManualTests(TestCase):

    """
    Manual tests that should not be run by default, only manually run to test
    specific steps of the authentication process for example.
    """

    def setUp(self):
        self.provider = FlickrResourceProvider()
        return self.provider.initialize()

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

    def test_manual_authenticate_2(self):
        """
        Test the second step of the authentication.
        """
        frob = '72157605556853655-faafec4f99009ffe-818323'

        def got_token(token):
            print token
            return token

        token_dfr = flickr.authenticate_2(self.provider, frob)
        token_dfr.addCallback(got_token)
        return token_dfr

    test_manual_authenticate_2.skip = 'MANUAL'
