# -*- 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>

from elisa.plugins.search.searcher import Searcher

from elisa.core.utils import defer
from elisa.core.utils.i18n import install_translation
from elisa.core.utils.sorting import async_sorted_merge, natural_cmp

from elisa.core import common
from twisted.internet import task

from elisa.plugins.database.models import MusicAlbum, MusicTrack, Artist, File


_ = install_translation('database')


def order_by(result_set, field):
    result_set.order_by(field)
    return result_set


def find_all(result_set):
    return result_set.all()


class DBSearcher(Searcher):
    """
    This is the Searcher for the database. It currently supports only music
    searches. Filters are ignored.
    """
    paths = ['music']
    def search(self, uri, model):
        store = common.application.store

        # create a SQL query string with leading and trailing percents
        # like "%searchstring%"
        search_string = '%%%s%%' % uri.filename

        dfr = defer.succeed(None)
        # artists
        dfr.addCallback(self._search_artists, store, search_string)
        dfr.addCallback(self._fill_in_data, model.artists, 'name')

        # albums
        dfr.addCallback(self._search_music_albums, store, search_string)
        dfr.addCallback(self._fill_in_data, model.albums, 'name')

        # tracks
        dfr.addCallback(self._search_music_tracks, store, search_string)
        dfr.addCallback(self._fill_in_data, model.tracks, 'title')

        return dfr

    def _search_artists(self, result, store, name):
        dfr = store.find(Artist, Artist.name.like(name))
        dfr.addCallback(order_by, Artist.name)
        dfr.addCallback(find_all)
        return dfr
    
    def _search_music_tracks(self, result, store, title):
        dfr = store.find(MusicTrack, MusicTrack.title.like(title),
                         MusicTrack.file_path == File.path,
                         File.hidden == False)
        dfr.addCallback(order_by, MusicTrack.title)
        dfr.addCallback(find_all)
        return dfr

    def _search_music_albums(self, result, store, album_name):
        dfr = store.find(MusicAlbum, MusicAlbum.name.like(album_name))
        dfr.addCallback(order_by, MusicAlbum.name)
        dfr.addCallback(find_all)
        return dfr

    def _fill_in_data(self, resulting_list, reference_list, attr):
        if len(reference_list) == 0:
            reference_list.extend(resulting_list)
            return

        def compare(self, other):
            # the way we want to compare the objects
            return natural_cmp(getattr(self, attr), getattr(other, attr))

        return async_sorted_merge(reference_list, resulting_list,
                compare=compare)
