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

"""
Test cases for the conditional database fixes 
"""

from twisted.trial.unittest import TestCase
from twisted.internet import defer, task

from storm.locals import create_database
from elisa.extern.storm_wrapper import store

from elisa.plugins.database import database_updater
from elisa.plugins.database.models import File

class TestGSTFixes(TestCase):

    def _dummy_find_typefinder(self, name):
        return name

    def setUp(self):

        # make the find_typefinder find something
        self._find_typefinder = database_updater._find_typefinder
        database_updater._find_typefinder = self._dummy_find_typefinder

        self.db = create_database('sqlite:')
        self.store = store.DeferredStore(self.db)

        dfr = self.store.start()
        dfr.addCallback(self._setup_files_table)
        dfr.addCallback(self._setup_video_table)
        dfr.addCallback(self._setup_music_tracks_table)
        return dfr

    def tearDown(self):
        return self.store.stop()

    def _setup_video_table(self, result=None):
        sql = "CREATE TABLE IF NOT EXISTS videos"\
                " (file_path VARCHAR PRIMARY KEY, name VARCHAR,"\
                " creation_time INTEGER, size VARCHAR, duration VARCHAR,"\
                " codec VARCHAR, thumbnail_uri VARCHAR);"

        return self.store.execute(sql)

    def _setup_music_tracks_table(self, result=None):
        sql = "CREATE TABLE IF NOT EXISTS music_tracks" \
                " (file_path VARCHAR PRIMARY KEY, title VARCHAR,"\
                " track_number INTEGER, album_name VARCHAR, "\
                " duration INTEGER, genre VARCHAR);"

        return self.store.execute(sql)

    def _setup_files_table(self, result=None):
        sql = "CREATE TABLE IF NOT EXISTS files" \
                " (path VARCHAR PRIMARY KEY, source VARCHAR," \
                " modification_time INTEGER DEFAULT 0, mime_type VARCHAR," \
                " hidden INTEGER DEFAULT 0," \
                " deleted INTEGER, playcount INTEGER DEFAULT 0, last_played" \
                " INTEGER DEFAULT 0);"

        return self.store.execute(sql)

    def tearDown(self):
        database_updater._find_typefinder = self._find_typefinder
        return self.store.stop()

    def _create_files(self, files):
        def iterate(files):
            for file in files:
                model = File()
                for key, value in file.iteritems():
                    setattr(model, key, value)
                
                yield self.store.add(model)
        
        return task.coiterate(iterate(files))

    def _check_files(self, files):

        def return_obj(val, obj):
            return obj

        def do_reload(obj):
            # this is a bit ugly but we have to reload the object because we
            # changed the stuff manually and our storm does not keep track of
            # that.
            dfr = self.store.reload(obj)
            dfr.addCallback(return_obj, obj)
            return dfr

        def do_check(obj, attrs, path):
            if obj is None:
                self.fail("No file for path '%s'" % path)

            for key, val in attrs.iteritems():
                attr = getattr(obj, key)

                msg = "'%s' on '%s' is '%s'. expected '%s'" % \
                        (key, path, attr, val)

                self.assertEquals(attr, val, msg)
        
        def iterate(files):
            for path, attrs in files.iteritems():
                dfr = self.store.get(File, path)
                dfr.addCallback(do_reload)
                dfr.addCallback(do_check, attrs, path)
                yield dfr

        
        return task.coiterate(iterate(files))

    def test_mscdoc_fixes(self):

        def check(result):
            exp_data = { u'something\\with.doc' : {
                            'modification_time' : 0,
                            'mime_type' : u'video/mpeg'},
                         u'something/irrelevant': {
                            'modification_time' :  12345,
                            'mime_type' : u'video/mpeg'},
                         u'something/with.doc' : {
                            'modification_time' : 12345,
                            'mime_type' : u'application/sth'},
                         u'with/ending.xls' : {
                            'modification_time' : 0,
                            'mime_type' : u'video/mpeg'},
                        u'with\\same.xls' : {
                            'modification_time' : 12345,
                            'mime_type' : u'application/else'}
                        }
            return self._check_files(exp_data)


        test_data = [ {'path' : u'something\\with.doc',
                            'modification_time' : 12345,
                            'mime_type' : u'video/mpeg'},
                      {'path' : u'something/irrelevant',
                            'modification_time' :  12345,
                            'mime_type' : u'video/mpeg'},
                      {'path' : u'something/with.doc',
                            'modification_time' : 12345,
                            'mime_type' : u'application/sth'},
                      {'path' : u'with/ending.xls',
                            'modification_time' : 12345,
                            'mime_type' : u'video/mpeg'},
                      {'path' : u'with\\same.xls',
                            'modification_time' : 12345,
                            'mime_type' : u'application/else'},
                    ]

        dfr = self._create_files(test_data)
        dfr.addCallback(lambda s: database_updater.msdoc_typefinder_fix(self.store))
        dfr.addCallback(self.assertTrue)
        dfr.addCallback(check)
        return dfr

    def test_ds_store_fixes(self):

        def check(result):
            exp_data = { u'/path/to/.DS_Store' : {
                            'modification_time' : 0,
                            'mime_type' : u'video/mpeg'},
                         u'something/irrelevant': {
                            'modification_time' :  12345,
                            'mime_type' : u'video/mpeg'},
                         u'something.ds_store' : {
                            'modification_time' : 12345,
                            'mime_type' : u'application/sth'},
                         u'else.ds_store' : {
                            'modification_time' : 0,
                            'mime_type' : u'video/mpeg'},
                        }
            return self._check_files(exp_data)


        test_data = [ {'path' : u'/path/to/.DS_Store',
                            'modification_time' : 12345,
                            'mime_type' : u'video/mpeg'},
                      {'path' : u'something/irrelevant',
                            'modification_time' :  12345,
                            'mime_type' : u'video/mpeg'},
                      {'path' : u'something.ds_store',
                            'modification_time' : 12345,
                            'mime_type' : u'application/sth'},
                      {'path' : u'else.ds_store',
                            'modification_time' : 12345,
                            'mime_type' : u'video/mpeg'},
                    ]

        dfr = self._create_files(test_data)
        dfr.addCallback(lambda s: database_updater.dsstore_typefinder_fix(self.store))
        dfr.addCallback(self.assertTrue)
        dfr.addCallback(check)
        return dfr

