# -*- coding: utf-8 -*-
# Elisa - Home multimedia server
# Copyright (C) 2006-2008 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 Elisa with Fluendo's plugins.
#
# The GPL part of Elisa is also available under a commercial licensing
# agreement from Fluendo.
# See "LICENSE.Elisa" in the root directory of this distribution package
# for details on that license.

__maintainer__ = 'Philippe Normand <philippe@fluendo.com>'

from elisa.base_components.playlist import Playlist
from elisa.core import common
from twisted.internet import defer
import threading, time

class DefaultPlaylist(Playlist):

    def __init__(self):
        Playlist.__init__(self)
        self._lock = threading.Lock()
        self._interrupt = False
        
    def initialize(self):
        plugin_registry = common.application.plugin_registry
        list_model = plugin_registry.create_component('base:list_model')
        list_model.activity = self
        self._model = list_model

    def get_model(self):
        return self._model

    def loadmore(self, uri, model, start=0, end=None):
        self.debug("loadmore %r from %r to %r", uri, start, end)
        
        def done(r):
            self.loading = False
            seconds = time.time() - t0
            self.debug("Loaded %d items in %s seconds", len(model),seconds)
            return r
        
        def ready_to_start(m):
            d = self._walk(start, end, uri, model)
            d.addCallback(lambda r: model)
            return d

        def got_media_type(media_type):
            file_type = media_type['file_type']
            if file_type == "directory":

                # skip first items
                if start > 0:
                    dfr = self._walk(0, start, uri, [])
                    dfr.addCallback(ready_to_start)
                else:
                    # update the model for items between start and end indexes
                    dfr = self._walk(start, end, uri, model)
                    dfr.addCallback(lambda r: model)
                return dfr
            elif file_type in self.media_types:
                self.debug("Adding: %r", uri)
                model.append(uri)
                return model
        
        if self.loading:
            try:
                self._lock.acquire()
                self._interrupt = True
            finally:
                self._lock.release()
        else:
            self._interrupt = False
            
        t0 = time.time()
        self.loading = True
        dfr_mtype = common.application.media_manager.get_media_type(uri)
        dfr_mtype.addCallback(got_media_type)
        dfr_mtype.addCallback(done)
        return dfr_mtype

    @defer.deferredGenerator
    def _walk(self, start, end, uri, model):
        """
        This methods walks through an URI directory resource between
        start and end, skips directory entries and update the given
        model with file entries found.
        """
        media_manager = common.application.media_manager
        root = uri
        current = uri

        def got_media_type(media_type, location):
            media_type = media_type['file_type']
            if media_type in self.media_types:
                self.debug("Adding: %r", location)
                model.append(location)
            return location

        def got_location(next_location):
            if next_location:
                d = media_manager.get_media_type(next_location)
                d.addCallback(got_media_type, next_location)
                return d
            else:
                return None

        if end is not None:
            # between start and end
            while start < end:
                if self._need_interrupt():
                    break
                dfr = media_manager.next_location(current, root=root)
                dfr.addCallback(got_location)
                wfd = defer.waitForDeferred(dfr)
                yield wfd
                current = wfd.getResult()
                if not current:
                    break
                else:
                    start += 1
        else:
            # until end
            while current:
                if self._need_interrupt():
                    break
                dfr = media_manager.next_location(current, root=root)
                dfr.addCallback(got_location)
                wfd = defer.waitForDeferred(dfr)
                yield wfd
                current = wfd.getResult()
                if not current:
                    break

        yield model

    def _need_interrupt(self):
        try:
            self._lock.acquire()
            value = self._interrupt
            if value:
                self.log("need interrupt: %r", value)
        finally:
            self._lock.release()
                
        return value

    def empty(self):
        """ Clear playlist's
        """
        try:
            self._lock.acquire()
            self._interrupt = True
        finally:
            self._lock.release()
            self.info("Clearing playlist")
            self._model[:]=[]


    def add_uri(self, uri, position=-1):
        """ Adds an uri to the Playlist

        @param uri:      the uri to add. if uri is a list, it will be directly
                         added to the list model.
        @type uri:       L{elisa.core.media_uri.MediaUri}
        @param position: position of the list to update, -1 means appending
                         to the end
        @type position:  int
        """
