#!/usr/bin/env python
# Copyright 2006 John-Mark Gurney <jmg@funkthat.com>
'''DVD Handling'''

__version__ = '$Change$'
# $Id$

default_audio_lang = 'en'

import itertools
import os
import sets

import sys
sys.path.append('mpegts')
try:
	import mpegts
	audiofilter = lambda x, y: mpegts.DVDAudioFilter(x, y)
except ImportError:
	print >>sys.stderr, 'module mpegts could not be loaded, not filtering audio'
	audiofilter = lambda x, y: x

from pydvdread import *

from DIDLLite import StorageFolder, Movie, VideoItem, Resource
from FSStorage import FSObject, registerklassfun

from twisted.python import log, threadable
from twisted.spread import pb
from twisted.web import resource, server

def gennameindexes(pref, item):
	d = {}
	for i, title in enumerate(item):
		t = '%s %d (%s)' % (pref, i + 1, title.time)
		d[t] = i

	return d

class IterTransfer(pb.Viewable):
	def __init__(self, iterable, request):
		self.iter = iter(iterable)
		self.request = request
		request.registerProducer(self, 0)

	def resumeProducing(self):
		if not self.request:
			return
		# get data and write to request.
		try:
			data = self.iter.next()
			if data:
				# this .write will spin the reactor, calling
				# .doWrite and then .resumeProducing again, so
				# be prepared for a re-entrant call
				self.request.write(data)
		except StopIteration:
			if self.request:
				self.request.unregisterProducer()
				self.request.finish()
				self.request = None

	def pauseProducing(self):
		pass

	def stopProducing(self):
		# close zipfile
		self.request = None

	# Remotely relay producer interface.

	def view_resumeProducing(self, issuer):
		self.resumeProducing()

	def view_pauseProducing(self, issuer):
		self.pauseProducing()

	def view_stopProducing(self, issuer):
		self.stopProducing()

	synchronized = ['resumeProducing', 'stopProducing']

threadable.synchronize(IterTransfer)

class IterGenResource(resource.Resource):
	isLeaf = True

	def __init__(self, itergen):
		resource.Resource.__init__(self)

		self.itergen = itergen

	def render(self, request):
		request.setHeader('content-type', 'video/mpeg')

		if request.method == 'HEAD':
			return ''

		# return data
		IterTransfer(self.itergen(), request)
		# and make sure the connection doesn't get closed
		return server.NOT_DONE_YET

class DVDChapter(VideoItem):
	def __init__(self, *args, **kwargs):
		self.dvdtitle = kwargs['dvdtitle']
		self.chapter = kwargs['chapter']
		del kwargs['dvdtitle'], kwargs['chapter']

		audio = self.dvdtitle.selectaudio(default_audio_lang)
		kwargs['content'] = IterGenResource(lambda i = self.chapter,
		    p = audio.pos: audiofilter(i, 0x80 + p))
		VideoItem.__init__(self, *args, **kwargs)

		self.url = '%s/%s' % (self.cd.urlbase, self.id)
		self.res = Resource(self.url, 'http-get:*:video/mpeg:*')
		#self.res.size = self.chapter.size

	def doUpdate(self):
		pass

class DVDTitle(StorageFolder):
	def __init__(self, *args, **kwargs):
		self.dvdtitle = kwargs['dvdtitle']
		self.dvddisc = kwargs['dvddisc']
		del kwargs['dvdtitle'], kwargs['dvddisc']

		audio = self.dvdtitle.selectaudio(default_audio_lang)
		kwargs['content'] = IterGenResource(lambda dt = self.dvdtitle,
		    p = audio.pos: audiofilter(itertools.chain(*dt), 0x80 + p))
		StorageFolder.__init__(self, *args, **kwargs)

		self.url = '%s/%s' % (self.cd.urlbase, self.id)
		self.res = Resource(self.url, 'http-get:*:video/mpeg:*')

		# mapping from path to objectID
		self.pathObjmap = {}

	def checkUpdate(self):
		self.doUpdate()
		#return self.dvddisc.checkUpdate()

	def genChildren(self):
		return gennameindexes('Chapter', self.dvdtitle)

	def createObject(self, i, arg):
		return DVDChapter, i, (), { 'dvdtitle': self.dvdtitle,
		    'chapter': self.dvdtitle[arg] }

class DVDDisc(FSObject, StorageFolder):
	def __init__(self, *args, **kwargs):
		path = kwargs['path']
		del kwargs['path']

		StorageFolder.__init__(self, *args, **kwargs)
		FSObject.__init__(self, path)

	def genChildren(self):
		self.dvd = DVD(self.FSpath)

		return gennameindexes('Title', self.dvd)

	def createObject(self, i, arg):
		return DVDTitle, i, (), { 'dvdtitle': self.dvd[arg],
		    'dvddisc': self }

def detectdvd(path, fobj):
	if os.path.isdir(path):
		# Make sure we there is only a VIDEO_TS in there, even
		# if there is a VIDEO_TS w/ other files, we will open
		# the VIDEO_TS as a DVD (if it is one)
		ld = os.listdir(path)
		if ld == ['VIDEO_TS' ]:
			pass
		elif not filter(lambda x: x[:4] != 'VTS_' and
		    x[:9] != 'VIDEO_TS.', ld):
			pass
		else:
			return None, None

	d = DVD(path)
	return DVDDisc, { 'path': path }

registerklassfun(detectdvd)