# -*- coding: utf-8 -*-
# Moovida - Home multimedia server
# Copyright (C) 2006-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: Benjamin Kampmann <benjamin@fluendo.com>

# always the first import
from elisa.extern.storm_wrapper import store

from elisa.core.media_uri import MediaUri
from elisa.plugins.database.models import MusicTrack, MusicAlbum, Artist, File
from elisa.plugins.search.models import MusicSearchResultModel

from elisa.plugins.database.tests.test_database_parser import DBMixin
from twisted.trial.unittest import TestCase
from twisted.internet import task

from elisa.plugins.database.searcher import DBSearcher

class TestSearcher(DBMixin, TestCase):

    def setUp(self):
        dfr = super(TestSearcher, self).setUp()
        dfr.addCallback(self._create_searcher)
        return dfr

    def _create_searcher(self, result=None):
        def set_searcher(searcher):
            self.searcher = searcher

        dfr = DBSearcher.create()
        dfr.addCallback(set_searcher)
        return dfr

    def _set_up_db(self, data):
        def iterate(data):
            for klass, attributes in data:
                obj = klass()
                for attr, value in attributes.iteritems():
                    setattr(obj, attr, value)
                yield self.store.add(obj)

        return task.coiterate(iterate(data))

    def _query(self, result, uri):
        model = MusicSearchResultModel()
        dfr = self.searcher.search(uri, model)
        dfr.addCallback(lambda x: model)
        return dfr

    def _check(self, result, artists, albums, tracks):

        # first check the count
        msg = "Not the same number of %s found"
        self.assertEquals(len(result.artists), len(artists), msg % "artists")
        self.assertEquals(len(result.albums), len(albums), msg % "albums")
        self.assertEquals(len(result.tracks), len(tracks), msg % "tracks")

        # then check the values and the order
        self.assertEquals(artists, [a.name for a in result.artists])
        self.assertEquals(albums, [a.name for a in result.albums])
        self.assertEquals(tracks, [a.title for a in result.tracks])


    def test_one_artist_multiple_albums(self):
        uri = MediaUri('elisa://search/music/madonna')
        data = [ (Artist, {'name' : u'madonna'}),
                 (Artist, {'name' : u'james brown'}),
                 (MusicAlbum, {'name' : u'music'}),
                 (MusicAlbum, {'name' : u'madonna'}),
                 (MusicAlbum, {'name' : u'holy madonna'}),
                 (MusicAlbum, {'name' : u'madonna likes you'}),
                 (MusicAlbum, {'name' : u'a madonna album'}),
                 ]

        expected = ( [u'madonna'], ['a madonna album', 'holy madonna',
                        'madonna', 'madonna likes you'], [])

        dfr = self._set_up_db(data)
        dfr.addCallback(self._query, uri)
        dfr.addCallback(self._check, *expected)
        return dfr

    def test_two_artist_multiple_albums_and_multiple_tracks(self):
        uri = MediaUri('elisa://search/music/james')
        data = [ (Artist, {'name' : u'madonna'}),
                 (Artist, {'name' : u'james brown'}),
                 (Artist, {'name' : u'james last'}),
                 (MusicAlbum, {'name': u'jmes'}),
                 (MusicAlbum, {'name': u'james bond - golden eye'}),
                 (MusicAlbum, {'name': u'Best of James Brown'}),
                 (MusicTrack, {'file_path' : u'eins', 'title' : u'James'}),
                 (MusicTrack, {'file_path' : u'e', 'title' : u'nope'}),
                 (MusicTrack, {'file_path' : u'i', 'title' : u'Bond James'}),
                 (File, {'path': u'eins', 'hidden': False}),
                 (File, {'path': u'e', 'hidden': False}),
                 (File, {'path': u'i', 'hidden': False}),
                 ]

        expected = ( [u'james brown', u'james last'],
                     ['Best of James Brown','james bond - golden eye'],
                     ['Bond James', 'James'])

        dfr = self._set_up_db(data)
        dfr.addCallback(self._query, uri)
        dfr.addCallback(self._check, *expected)
        return dfr

    def test_case_insensitive(self):
        uri = MediaUri('elisa://search/music/moby')
        data = [ (Artist, {'name' : u'Madonna'}),
                 (Artist, {'name' : u'MoBy'}),
                 (MusicAlbum, {'name': u'MoBy'}),
                 (MusicAlbum, {'name': u' moBy '}),
                 (MusicAlbum, {'name': u'Best of James Brown'}),
                 (MusicTrack, {'file_path' : u'eins', 'title' : u'mob'}),
                 (MusicTrack, {'file_path' : u'e', 'title' : u'moby'}),
                 (MusicTrack, {'file_path' : u'i', 'title' : u'inAmobYes'}),
                 (File, {'path': u'eins', 'hidden': False}),
                 (File, {'path': u'e', 'hidden': False}),
                 (File, {'path': u'i', 'hidden': False}),
                 ]

        expected = ( [u'MoBy', ],
                     [u' moBy ', u'MoBy'],
                     [u'inAmobYes', u'moby'])

        dfr = self._set_up_db(data)
        dfr.addCallback(self._query, uri)
        dfr.addCallback(self._check, *expected)
        return dfr

    def test_already_filled_list(self):
        uri = MediaUri('elisa://search/music/moby')
        data = [ (Artist, {'name' : u'Madonna'}),
                 (Artist, {'name' : u'MoBy'}),
                 ## (Artist, {'name' : u'moBY'}),
                 (MusicAlbum, {'name': u'MoBy'}),
                 (MusicAlbum, {'name': u' moBy '}),
                 (MusicAlbum, {'name': u'Best of James Brown'}),
                 (MusicTrack, {'file_path' : u'eins', 'title' : u'mob'}),
                 (MusicTrack, {'file_path' : u'e', 'title' : u'moby'}),
                 (MusicTrack, {'file_path' : u'i', 'title' : u'inAmobYes'}),
                 (File, {'path': u'eins', 'hidden': False}),
                 (File, {'path': u'e', 'hidden': False}),
                 (File, {'path': u'i', 'hidden': False}),
                 ]

        def query(result, uri):
            model = MusicSearchResultModel()

            # already filled stuff in the list
            artist_a = Artist()
            artist_a.name = u"Coldplay"
            artist_b = Artist()
            artist_b.name = u"Mehh"
            model.artists = [artist_a, artist_b]

            album_a = MusicAlbum()
            album_a.name = u"Cooler than Water"
            album_b = MusicAlbum()
            album_b.name = u"X&Y"
            model.albums = [album_a, album_b]

            track_a = MusicTrack()
            track_a.title = u"fontaine"
            track_b = MusicTrack()
            track_b.title = u"sing"
            model.tracks = [track_a, track_b]

            dfr = self.searcher.search(uri, model)
            dfr.addCallback(lambda x: model)
            return dfr

        def check(model):
            self.assertEquals(['Cooler than Water', 'MoBy', ' moBy ',
                               'X&Y'], [i.name for i in model.albums])
            self.assertEquals(['Coldplay', 'Mehh', 'MoBy'],
                              [i.name for i in model.artists])
            self.assertEquals(['fontaine', 'inAmobYes', 'moby', 'sing'],
                               [i.title for i in model.tracks]) 
                            

        dfr = self._set_up_db(data)
        dfr.addCallback(query, uri)
        dfr.addCallback(check)
        return dfr

