
from elisa.core import plugin
from elisa.core.tests.test_media_provider import TestMediaProvider
from elisa.base_components.media_provider import NotifyEvent
from elisa.plugins.base import local_media
from elisa.core.media_uri import MediaUri
from elisa.core.utils import misc, sorting
import os, platform
from twisted.internet import defer
import pkg_resources
import shutil

if platform.system() == 'Linux':
    from elisa.extern.coherence.inotify import INotify

class DummyPlugin(plugin.Plugin):
    name = 'dummy'
    components = {
        'gst_metadata': 
            {'path': 'elisa.plugins.gstreamer_plugin.gst_metadata:GstMetadata'}
    }

class TestLocalMedia(TestMediaProvider):
    component_class = local_media.LocalMedia

    def __init__(self, methodName='runTest'):
        TestMediaProvider.__init__(self, methodName=methodName)

        if platform.system() != 'Windows':
            try:
                i = INotify()
                i.release()
            except Exception, error:
                self.skip = error

        # use a well known list of files so that if someone adds a file in data/
        # to use it in another test this doesn't break
        # key is a file in the source distribution, value a list of paths
        # relative to the working directory where to copy the file
        self.data_files = {
            'audio.ogg': ['audio.ogg', 'first_level/audio.ogg',
                'first_level/second_level/audio.ogg'],
            'video.ogg': ['video.ogg', 'first_level/second_level/video.ogg'],
            'audio.mp3': ['audio.mp3', 'first_level/audio.mp3']
        }

    def setUp(self):
        package_path = 'elisa.plugins.gstreamer_plugin.tests'
        # we are already in _trial_temp/ at this point
        self.working_data_dir = os.path.abspath('local_media_data')
        
        # setup a clean data dir for each test
        self.uris = []
        for filename, working_paths in self.data_files.iteritems():
            for path in working_paths:
                working_filename = os.path.join(self.working_data_dir, path)
                pkg_resources.ensure_directory(working_filename)
                working_uri = MediaUri('file://' + working_filename)
                self.uris.append(working_uri)
            
                # copy our data to the trial working dir
                fi = pkg_resources.resource_stream(package_path,
                    os.path.join('data', filename))
                fo = file(working_filename, 'w')
                fo.write(fi.read())
                fo.close()
        
        # chain up the parent that sets stuff in common.application
        super(TestLocalMedia, self).setUp()

        from elisa.core.common import application
        application.plugin_registry.register_plugin(DummyPlugin)
        self.gst_metadata = application.plugin_registry.create_component('dummy:gst_metadata')
        application.metadata_manager.register_component(self.gst_metadata)

    def tearDown(self):
        if platform.system() != 'Windows':
            try:
                i = INotify()
            except Exception, error:
                # no need to skip from here
                pass
            else:
                i.release()
        
        # clean the data dir at the end of each test
        shutil.rmtree(self.working_data_dir)

        # clean the component
        self.gst_metadata.clean()
        TestMediaProvider.tearDown(self)

    def get_data_uris(self, root, deep=False):
        uris = []
        for path, dirs, files in os.walk(root):
            for child in dirs + files:
                uris.append(self.get_data_uri(child))
        
            if not deep:
                break

        return uris

    def get_valid_uris(self):
        return self.uris

    def get_data_uri(self, filename=''):
        return MediaUri('file://' + os.path.join(self.working_data_dir, filename))

    def _touch(self, path):
        f = open(path.path, 'w')
        f.write('woo')
        f.close()

    def test_get_direct_children(self):
        # get the root uri
        uri = self.get_data_uri()

        def get_direct_children_done(children, root):
            expected = self.get_data_uris(root.path)
            self.assertEqual(len(children), len(expected))

            children_uris = [i[0] for i in children]
            # my professor of algorithms would be proud of me here
            for uri in expected:
                assert uri in children_uris

        children = []
        dfr = self.component.get_direct_children(uri, children)
        dfr.addCallback(get_direct_children_done, uri)

        return dfr

    def test_monitor_uri(self):
                
        dfr = defer.Deferred()
        uri = self.get_data_uri()
        foo_txt =  self.get_data_uri('foo.txt')
        
        def cb(u1, metadata, evt, u):
            self.assertEquals(u, uri)
            self.assertEquals(evt, NotifyEvent.ADDED)
            self.assertEquals(u1, foo_txt)
            self.assertEquals(metadata, {})
            dfr.callback(True)
                
        self.component.monitor_uri(uri, cb)
        self._touch(foo_txt)
        
        dfr.addCallback(lambda r: self.component.unmonitor_uri(uri))
        return dfr
    
    if platform.system() == 'Windows':
        test_monitor_uri.skip = "Skipped under windows, to fix"

    def test_copy(self):
#        TestMediaProvider.test_copy(self)

        orig_uri = self.get_data_uri('audio.ogg')
        dest_uri = self.get_data_uri('audio_copy.ogg')

        self.component.copy(orig_uri, dest_uri)
        self.failUnless(os.path.exists(dest_uri.path))
        
    if platform.system() == 'Windows':
        test_copy.skip = "Skipped under windows, to fix"

    def test_move(self):
#        TestMediaProvider.test_move(self)
       
        orig_uri = self.get_data_uri('audio.ogg')
        dest_uri = self.get_data_uri('audio_moved.ogg')
        
        self.component.move(orig_uri, dest_uri)
        self.failIf(os.path.exists(orig_uri.path))
        self.failUnless(os.path.exists(dest_uri.path))
        
    if platform.system() == 'Windows':
        test_move.skip = "Skipped under windows, to fix"

    def test_delete(self):
#        TestMediaProvider.test_delete(self)

        orig_uri = self.get_data_uri('audio.ogg')
        self.component.delete(orig_uri)
        self.failIf(os.path.exists(orig_uri.path))
        
    if platform.system() == 'Windows':
        test_delete.skip = "Skipped under windows, to fix"

    def test_get_media_type(self):
#        TestMediaProvider.test_get_media_type(self)
        
        def get_media_type_done(media_type,
                expected_file_type, expected_mime_types):
            self.assertEqual(media_type['file_type'], expected_file_type)
            self.failUnless(media_type['mime_type'] in expected_mime_types)

        uri = self.get_data_uri('audio.ogg')
        audio_ogg_dfr = self.component.get_media_type(uri)
        audio_ogg_dfr.addCallback(get_media_type_done,
                'audio', ['audio/x-vorbis'])
        
        uri = self.get_data_uri('video.ogg')
        video_ogg_dfr = self.component.get_media_type(uri)
        video_ogg_dfr.addCallback(get_media_type_done,
                'video', ['video/x-theora'])
        
        # FIXME: two of the build bots don't have mad, reenable this when we
        # implement missing plugin reporting in gst_metadata
#        uri = self.get_data_uri('audio.mp3')
#        audio_mp3_dfr = self.component.get_media_type(uri)
#        audio_mp3_dfr.addCallback(get_media_type_done,
#                'audio', ['application/x-id3', 'audio/mpeg'])
        audio_mp3_dfr = defer.succeed(None)

        dfr_list = defer.DeferredList([audio_ogg_dfr, video_ogg_dfr,
                audio_mp3_dfr], fireOnOneErrback=True)

        return dfr_list
    
    test_get_media_type.skip = "Skipped under windows due to glib2 reactor issues with unit test and GIL release issues on Rawhide"
