# Licensed under the MIT license
# http://opensource.org/licenses/mit-license.php

# a backend

# Copyright 2007, Frank Scholz <coherence@beebits.net>
# Copyright 2008, Jean-Michel Sizun <jm.sizun@free.fr>

from twisted.internet import defer

from coherence.upnp.core import utils

from coherence.upnp.core import DIDLLite
from coherence.upnp.core.DIDLLite import classChooser, Container, Resource, DIDLElement

import coherence.extern.louie as louie

from coherence.extern.simple_plugin import Plugin

from coherence import log

from urlparse import urlsplit

import re
from coherence.upnp.core.utils import getPage
from coherence.backend import BackendStore, BackendItem, Container, LazyContainer, \
     AbstractBackendStore

class PlaylistItem(BackendItem):
    logCategory = 'playlist_store'
    
    def __init__(self, title, stream_url, mimetype):

        self.name = title
        self.stream_url = stream_url
        self.mimetype = mimetype

        self.url = stream_url
        self.item = None
        
    def get_id(self):
        return self.storage_id

    def get_item(self):
        if self.item == None:
            upnp_id = self.get_id()
            upnp_parent_id = self.parent.get_id()
            if (self.mimetype.startswith('video/')):
                item = DIDLLite.VideoItem(upnp_id, upnp_parent_id, self.name)
            else:
                item = DIDLLite.AudioItem(upnp_id, upnp_parent_id, self.name)
                
            # what to do with MMS:// feeds?
            protocol = "http-get"
            if self.stream_url.startswith("rtsp://"):
                protocol = "rtsp-rtp-udp"
            
            res = Resource(self.stream_url, '%s:*:%s:*' % (protocol,self.mimetype))
            res.size = None
            item.res.append(res)
        
            self.item = item
        return self.item
    
    def get_url(self):
        return self.url



class PlaylistStore(AbstractBackendStore):

    logCategory = 'playlist_store'

    implements = ['MediaServer']

    wmc_mapping = {'16': 1000}

    description = ('Playlist', 'exposes the list of video/audio streams from a m3u playlist (e.g. web TV listings published by french ISPs such as Free, SFR...).', None)

    options = [{'option':'name', 'text':'Server Name:', 'type':'string','default':'my media','help': 'the name under this MediaServer shall show up with on other UPnP clients'},
       {'option':'version','text':'UPnP Version:','type':'int','default':2,'enum': (2,1),'help': 'the highest UPnP version this MediaServer shall support','level':'advance'},
       {'option':'uuid','text':'UUID Identifier:','type':'string','help':'the unique (UPnP) identifier for this MediaServer, usually automatically set','level':'advance'},    
       {'option':'playlist_url','text':'Playlist file URL:','type':'string','help':'URL to the playlist file (M3U).'},
    ]

    playlist_url = None;

    def __init__(self, server, **kwargs):
        AbstractBackendStore.__init__(self, server, **kwargs)
        
        self.playlist_url = self.config.get('playlist_url', 'http://mafreebox.freebox.fr/freeboxtv/playlist.m3u')
        self.name = self.config.get('name', 'playlist')
        
        self.init_completed()


    def __repr__(self):
        return self.__class__.__name__

    def append( self, obj, parent):
        if isinstance(obj, basestring):
            mimetype = 'directory'
        else:
            mimetype = obj['mimetype']

        UPnPClass = classChooser(mimetype)
        id = self.getnextID()
        update = False
        if hasattr(self, 'update_id'):
            update = True

        item = PlaylistItem( id, obj, parent, mimetype, self.urlbase,
                                        UPnPClass, update=update)
        
        self.store[id] = item
        self.store[id].store = self
        if hasattr(self, 'update_id'):
            self.update_id += 1
            if self.server:
                self.server.content_directory_server.set_variable(0, 'SystemUpdateID', self.update_id)
            if parent:
                value = (parent.get_id(),parent.get_update_id())
                if self.server:
                    self.server.content_directory_server.set_variable(0, 'ContainerUpdateIDs', value)

        if mimetype == 'directory':
            return self.store[id]

        return None

     
    def upnp_init(self):
        self.current_connection_id = None
        if self.server:
            self.server.connection_manager_server.set_variable(0, 'SourceProtocolInfo',
                                                                  ['rtsp-rtp-udp:*:video/mpeg:*',
                                                                  'http-get:*:video/mpeg:*',
                                                                  'rtsp-rtp-udp:*:audio/mpeg:*',
                                                                  'http-get:*:audio/mpeg:*'],
                                                                  default=True)
        
        rootItem = Container(None, self.name)
        self.set_root_item(rootItem)
        self.retrievePlaylistItems(self.playlist_url, rootItem)
  
    def retrievePlaylistItems (self, url, parent_item):
        
        def gotPlaylist(playlist):
            self.info("got playlist")
            items = {}
            if playlist :
                content,header = playlist
                lines = content.splitlines().__iter__()
                line = lines.next()
                while line is not None:
                    if re.search ( '#EXTINF', line):
                        channel = re.match('#EXTINF:.*,(.*)',line).group(1)
                        mimetype = 'video/mpeg'
                        line = lines.next()
                        while re.search ( '#EXTVLCOPT', line):
                            option = re.match('#EXTVLCOPT:(.*)',line).group(1)
                            if option == 'no-video':
                                mimetype = 'audio/mpeg'
                            line = lines.next()
                        url = line
                        item = PlaylistItem(channel, url, mimetype)
                        parent_item.add_child(item)
                    try:
                        line = lines.next() 
                    except StopIteration:
                        line = None                      
            return items

        def gotError(error):
            self.warning("Unable to retrieve playlist: %s" % url)
            print "Error: %s" % error
            return None
        
        d = getPage(url)
        d.addCallback(gotPlaylist)
        d.addErrback(gotError)            
        return d
    
