
import openpluginlib
import openimagelib
import openmedialib
import balance

def parse_args( args ):
	clips = []
	clip = []
	for i in args:
		if i.find( "=" ) < 0:
			if len( clip ) > 0:
				clips.append( clip )
				clip = []
		clip.append( i )
	if len( clip ) > 0:
		clips.append( clip )
	return clips

def assign_prop( property, array ):
	if property is not None and property.valid( ):
		if property.is_a_int( ):
			property.set( int( array[ 1 ] ) )
		elif property.is_a_double( ):
			property.set( float( array[ 1 ] ) )
		elif property.is_a_wstring( ):
			property.set( str( array[ 1 ] ) )
	else:
		print "invalid ", array

def assign_props( properties, array ):
	for i in array:
		split = i.split( "=" )
		assign_prop( properties.get_property( split[ 0 ] ), split )

def create_property( name, value, properties ):
	p = properties.get_property( name )
	if p is None or not p.valid( ):
		p = openpluginlib.property( openpluginlib.create_key_from_string( name ) )
		p.set( value )
		properties.append( p )
	return p

def inherit( dest, src ):
	for i in src.get_keys( ):
		dest.append( src.get_property( i ) )

def report( title, properties ):
	count = 0
	print title + "\n"
	for i in properties.get_keys( ):
		count += 1
		print "\t" + str( i ) + " =",
		property = properties.get_property( i )
		if property.is_a_int( ):
			print property.value_as_int( )
		elif property.is_a_double( ):
			print property.value_as_double( )
		elif property.is_a_wstring( ):
			print property.value_as_wstring( )
	if count == 0:
		print "\tNo properties"
	print


class preview:
	video_store = None
	audio_store = None
	precache = [ ]
	count = 0

	def __init__( self, frame ):
		if preview.video_store is None:
			if frame.get_image( ) is not None:
				preview.video_store = openmedialib.create_store( "sdl:", frame )
				if preview.video_store is None:
					preview.video_store = openmedialib.create_store( "glew:", frame )
				else:
					preview.audio_store = openmedialib.create_store( "openal:", frame )
			else:
				preview.audio_store = openmedialib.create_store( "openal:", frame )

			if preview.video_store is not None and not preview.video_store.init( ):
				preview.video_store = None
			if preview.audio_store is not None and not preview.audio_store.init( ):
				preview.audio_store = None

	def push( self, frame ):
		result = False
		if frame.get_audio( ) is not None and preview.audio_store is not None:
			result = preview.audio_store.push( frame )
			preview.precache.append( frame )
			preview.count += 1
			if preview.count > 8:
				frame = preview.precache.pop( 0 )
				if preview.video_store is not None:
					result = preview.video_store.push( frame )
		elif preview.video_store is not None:
			result = preview.video_store.push( frame )
		return result

	def has_keydown( self ):
		return preview.video_store is not None and preview.video_store.properties( ).get_property( "keydown" ).valid( )

	def keydown( self ):
		val = preview.video_store.properties( ).get_property( "keydown" ).value_as_int( )
		preview.video_store.properties( ).get_property( "keydown" ).set( 0 )
		return val

	def complete( self ):
		pass

def play( input, store = None, properties = [] ):
	output = None
	try:
		frame = input.fetch( )
		if frame is not None:
			speed = 1
			has_keydown = False
			if store is None:
				output = preview( frame )
				has_keydown = output.has_keydown( )
			else:
				output = openmedialib.create_store( str( store ), frame )
				assign_props( output.properties( ), properties )
				output.init( )
			balance.activate( input )
			i = 0
			while i < input.get_frames( ):
				if not output.push( frame ): break
				if has_keydown:
					key = output.keydown( )
					if key == 32: speed = [ 1, 0 ][ speed == 1 ]
					elif key == 27: break
					elif key == 104: speed = -1
					elif key != 0: print key
				if speed != 0:
					i += speed
					if i < 0: i = 0
					input.seek( i, False )
					frame = input.fetch( )
				else:
					frame.set_audio( None )
	except KeyboardInterrupt:
		pass
	balance.deactivate( input )
	if output is not None:
		output.complete( )

class input_wrapper( openmedialib.filter_delegate ):
	def __init__( self, input = None ):
		openmedialib.filter_delegate.__init__( self )
		self.input = input
		self.reseat = openmedialib.create_audio_reseat( )
		self.input_index = 0
		self.store_index = 0
		self.frame_store = { }
		if self.input is not None:
			inherit( self.properties( ), input.properties( ) )
		self.position = 0
		self.enable_audio = create_property( "enable_audio", 0, self.properties( ) )
		self.enable_video = create_property( "enable_video", 0, self.properties( ) )
		self.in_point = create_property( "in", 0, self.properties( ) )
		self.out_point = create_property( "out", 0, self.properties( ) )
		self.width = create_property( "width", 0, self.properties( ) )
		self.height = create_property( "height", 0, self.properties( ) )
		self.sar_num = create_property( "sar_num", 0, self.properties( ) )
		self.sar_den = create_property( "sar_den", 0, self.properties( ) )
		self.fps_num = create_property( "fps_num", 0, self.properties( ) )
		self.fps_den = create_property( "fps_den", 0, self.properties( ) )
		self.frequency = create_property( "frequency", 0, self.properties( ) )
		self.channels = create_property( "channels", 0, self.properties( ) )
		self.volume = create_property( "volume", 1.0, self.properties( ) )
		self.src_num = 0
		self.src_den = 0
		self.src_frequency = 0
		if self.input is not None:
			self.out_point.set( input.get_frames( ) )
			self.connect( input, 0 )

	def get_uri( self ):
		return "wrapper"

	def init( self, args ):
		if self.valid( ):
			assign_props( self.properties( ), args )

	def slot_count( self ):
		return 1

	def map_source_to_dest( self, position ):
		return int( float( position * self.fps_num.value_as_int( ) * self.src_den ) / ( self.fps_den.value_as_int( ) * self.src_num ) + 0.5 )

	def map_dest_to_source( self, position ):
		return int( float( position * self.src_num * self.fps_den.value_as_int( ) ) / ( self.src_den * self.fps_num.value_as_int( ) ) + 0.5 )

	def get_in( self ):
		return self.map_source_to_dest( in_point.value_as_int( ) )

	def get_out( self ):
		return self.map_source_to_dest( out_point.value_as_int( ) )

	def valid( self ):
		return self.input is not None or self.fetch_slot( 0 ) is not None

	def on_slot_change( self, input, slot ):
		if input is not None:
			if self.input is not input:
				self.out_point.set( input.get_frames( ) )
			self.input = input
			frame = input.fetch( )
			if frame is not None:
				self.fps_num.set( frame.get_fps_num( ) )
				self.fps_den.set( frame.get_fps_den( ) )
				self.src_num = frame.get_fps_num( )
				self.src_den = frame.get_fps_den( )
				if frame.get_image( ) is not None:
					self.enable_video.set( 1 )
					self.width.set( frame.get_image( ).width( ) )
					self.height.set( frame.get_image( ).height( ) )
					self.sar_num.set( frame.get_sar_num( ) )
					self.sar_den.set( frame.get_sar_den( ) )
				if frame.get_audio( ) is not None:
					self.enable_audio.set( 1 )
					self.src_frequency = frame.get_audio( ).frequency( )
					self.frequency.set( frame.get_audio( ).frequency( ) )
					self.channels.set( frame.get_audio( ).channels( ) )

	def fetch_callback( self ):
		return None

	def fetch( self ):
		self.acquire_values( )
		if self.enable_audio.value_as_int( ) == 0:
			self.input.set_process_flags( openmedialib.process_flags.image )
			self.input.seek( self.in_point.value_as_int( ) + self.map_dest_to_source( self.position ), False )
			self.position += 1
			frame = self.input.fetch( )
			self.resample( frame )
		else:
			frame = None
			input_requested = self.in_point.value_as_int( ) + self.map_dest_to_source( self.position )
			samples_required = openmedialib.audio_samples_for_frame( self.store_index, self.src_frequency, 
																	 self.fps_num.value_as_int( ), 
																	 self.fps_den.value_as_int( ) )
			for i in self.frame_store.keys( ):
				if i < input_requested:
					self.frame_store.pop( i )

			while not self.frame_store.has_key( input_requested ) or not self.reseat.has( samples_required ):
				if self.input_index < input_requested:
					self.input_index = input_requested
					self.reseat.clear( )
				self.input.seek( self.input_index, False )
				frame = self.input.fetch( )
				self.frame_store[ self.input_index ] = frame
				self.input_index += 1
				self.reseat.append( frame.get_audio( ) )
			self.store_index += 1
			frame = self.frame_store[ input_requested ]
			frame = frame.deep_copy( )
			frame.set_audio( self.reseat.retrieve( samples_required, False ) )
			frame.set_fps( self.fps_num.value_as_int( ), self.fps_den.value_as_int( ) )
			frame.set_position( input_requested )
			self.resample( frame )
		return frame

	def seek( self, position, relative = False ):
		expected = self.position + 1
		if relative:
			self.position += position
		else:
			self.position = position
		if self.position != expected:
			self.reseat.clear( )

	def get_position( self ):
		return self.position

	def get_frames( self ):
		return self.map_source_to_dest( self.out_point.value_as_int( ) - self.in_point.value_as_int( ) )

	# This method should be defined in oil utilities
	def is_scalable( self, image ):
		return str( image.pf( ) ) in [ "r8g8b8", "b8g8r8", "yuv444", "r8g8b8a8", "b8g8r8a8", "yuv420p", "yuv422p" ]

	def resample( self, frame ):
		if frame.get_image( ) is not None:
			image = frame.get_image( )
			iw = image.width( ) 
			ih = image.height( ) 
			isn = frame.get_sar_num( )
			if isn == 0: isn = 1
			isd = frame.get_sar_den( )
			if isd == 0: isd = 1
			image = openimagelib.deinterlace( image )
			if iw != self.width.value_as_int( ) or ih != self.height.value_as_int( ) or isn != self.sar_num.value_as_int( ) or isd != self.sar_den.value_as_int( ):
				if not self.is_scalable( image ):
					image = openimagelib.convert( image, unicode( "yuv420p" ), 0 )
				aspect_ratio = float( iw * isn ) / float( ih * isd )
				if iw != self.width.value_as_int( ) or ih != self.height.value_as_int( ):
					image = openimagelib.rescale( image, self.width.value_as_int( ), self.height.value_as_int( ) )
				else:
					nw = int( aspect_ratio * ih * self.sar_den.value_as_int( ) / self.sar_den.value_as_int( ) + 0.5 )
					image = openimagelib.rescale( image, nw, ih )
				frame.set_sar( self.sar_num.value_as_int( ), self.sar_den.value_as_int( ) )
			frame.set_image( image )

		if frame.get_audio( ) is not None:
			audio = frame.get_audio( )
			audio = openmedialib.audio_channel_convert( audio, self.channels.value_as_int( ) )
			audio = openmedialib.audio_resample( audio, self.frequency.value_as_int( ) )
			frame.set_audio( audio )

	def reuse( self ):
		return False
