#!/usr/bin/env python
# -*- coding: utf-8 -*-
#--------------------------------------------------------------------
# Display Message on Renderer's Screen (a special transcoder)
#--------------------------------------------------------------------
import os, sys, signal
import time
import glob
import subprocess
import codecs
import threading

from PIL import Image,ImageChops,ImageOps
from PIL import ImageDraw, ImageFont
from optparse import OptionParser
from multiprocessing import Process, Lock, Pipe
#from signal import signal
import textwrap
import tempfile
import urllib
import urllib2
import socket
import atexit

#sys.path.append('regzamod')
from RzCmnSubs import dbg,error,setdbg

#---- globals
g_debug=0

g_edp=0	#disp error message on renderer screen
g_encode_sys="cp932"  # default encode type of system(os) 
g_iav_logfile="iav_log.txt"
g_imgtemp_prefix="iav_imgtmp"
g_abps=64000   # audio bitrate
g_svfmt="JPEG"
g_quality=100
g_quickResize=True
g_fpi=10  # frames/image
g_imod=Image.BILINEAR
g_scale=1.0
g_aspect=1.77778


#---- disp message video 
def msg_trans (args,dpmsg,opt):
	dbg("msg_trans: dpmsg=%s, args=%r" % (dpmsg,args) )
	
	#---- kick transcoder body
	buffered=0
	cwd="./"
	try:
		p = subprocess.Popen(args, bufsize=-1, shell=False, cwd=cwd, stdin=subprocess.PIPE,
			stdout=subprocess.PIPE, stderr=None,close_fds=False)
	except OSError:
		error(g_edp,"RzDspMsg: Failed to exec %s" % args)
		return (1)
		
	#---- kick watchdog proc ------
	ret=0
	pp,pc=Pipe()
	Process(target=watchdog_pipe,args=(pc,os.getpid(),p.pid)).start()
	
	#---- kick image supplyer ------
	(rc)=imgcat(dpmsg,opt,p,p.stdin)
	dbg("RzDspMsg.msg_trans: imgcat end rc=%d" % (rc))
	p.stdin.close()

	ret=p.wait()
	return (ret)
	
#---- supply imageclips to file_o
def imgcat (dpmsg,opt,proc,file_o):
	#param proc: target transcoder proc, to supply image to

	dbg("imgcat: dpmsg=%s" % dpmsg)
	tm_start=time.time()
	dpsize=[opt.dpsize_w,opt.dpsize_h]
	rc=0
	
	#---- setup fonts/mergins
	fh=18.0  # for 480p
	fh *=dpsize[1]/480.0
	font = ImageFont.truetype('c:\\windows\\fonts\\arialuni.ttf', int(fh))
	fw,fh=font.getsize("M")
	lfv= int(fh*0.8)		# linefeed height
	capt_mergin_x=10 	# caption mergin holizontal in pixcel
	capt_mergin_y=4  	# caption mergin vertical in pixcel 
	if(g_scale <1.0):
		capt_mergin_x += dpsize[0]*(1.0-g_scale)/2 
		capt_mergin_y += dpsize[1]*(1.0-g_scale)/2 
	
	#---- loop of image supply
	dpcnt=int(opt.dur+1.0)
	dpcnt=1000
	for j in range(0,dpcnt):
		try:
			#---- create image background ---------
			fname="dummy.jpg"
			img=Image.new('RGB',dpsize,(0,0,0))

			#---- draw error msg ---------
			str=dpmsg
			lines=textwrap.wrap(str, width=80)
			wmax=0
			for line in lines:
				w,h=font.getsize(line)
				if(w>wmax):
					wmax=w
			h=lfv*len(lines)
			xpos=dpsize[0]/2-wmax/2	#centering
			ypos=dpsize[1]/2-h/2	#centering
			for str in lines:
				dr = ImageDraw.Draw(img)
				sd=2	#shadow depth
				dr.text((xpos,ypos), 		str,font=font,fill='black')
				dr.text((xpos-sd,ypos-sd),	str,font=font,fill='yellow')
				ypos+=lfv
				
			#---- save(write) image ---------
			lpc=g_fpi
			for i in range(lpc):
				img.save(file_o,g_svfmt,quality=g_quality)
			file_o.flush()
		except IOError,e:
			# will frequentry occur on web contents
			error(g_edp,"RzDspMsg: IOError(2), e=%r, image='%s'" % (e,fname))
			# something wrong, reset counter
			if((proc.poll()!=None or file_o.closed)):
				dbg("RzDspMsg: target proc terminated or pipe closed, let's stop")
				rc=1
				loop=0
				break
			elif(True):
				time.sleep(1);
			elif(False):
				err_cnt+=1
				if(err_cnt>3):
					dbg("RzDspMsg: IOError Exception, count over="+err_cnt+" : exit")
					proc.terminate()
					sys.exit(2)
					return(-2)
				time.sleep(0.5)
				#don't retry infinitly !!
			else:
				error(g_edp,"RzDspMsg.imgcat: IOError(2) e=%r, image='%s'" % (e,fname))
				time.sleep(0.1)
		except Exception ,e:
			error(g_edp,"RzDspMsg: unknown Exception(2), e=%r, image='%s'" % (e,fname))
			#should kill transcoder_proc, otherwise main proc will hung-up
			proc.terminate()
			sys.exit(3)
			return (-3)

		#--- loop tail start
		dbg(">>==== RzDspMsg.imgcat: Loop No.%d End" % j )
	#---- ending
	tm_now=time.time()
	dbg(">>==== RzDspMsg.imgcat: Stopping, rc=%d timeElapsed=%.2f" % (rc,tm_now - tm_start))
	return (rc)

#---- watchdog
def watchdog_pipe(pc,ppid,pid):
	import time
	# this mechanism work well, to know the parent death
	dbg("===== watchdog: started, mypid=%d parent pid=%d target_pid=%d" % (os.getpid(),ppid,pid))
	time1=time.time()
	
	try:
		#read pipe in blocking mode
		#i.e. wait untill parent die, b/c parent never send to the pipe
		pc.recv()
	except EOFError:
		dbg("===== watchdog: EOFError on pipe.recv")
		#parent seems to be killed
		pass	#Noop
	except IOError:
		dbg("===== watchdog: IOError on pipe.recv")
		pass	#Noop
	
	dbg("===== watchdog: kill pid=%d" % pid)
	try:
		#os.kill(pid,signal.SIGKILL)
		os.kill(pid,9)
	except WindowsError:
		dbg("WindowsError: pid=%d may not exists" % pid)

	time2=time.time()
	time=time2-time1
	dbg("watchdog: play time=%f" % time)
	sys.exit()
	
def exec_prog(args,logf):
	msg="exec_prog: args=%s" % args
	#dbg(msg)
	p=None
	try:
		cwd="./"
		p = subprocess.Popen(args, shell=False, cwd=cwd, stdin=subprocess.PIPE,
	    	stdout=None, stderr=None,
	    	close_fds=False)
	except OSError:
		msg="Failed to exec %s" % args
		dbg(msg)
	return p

#----------------------------------------------------------------------------------
# main
#----------------------------------------------------------------------------------
if __name__ == '__main__':
	
	tm_start0=time.time()
	setdbg(g_debug)
	#---- change default encoding
	if(True):
		#dbg("RzDspMsg.main: defaultencoding=%s" % sys.getdefaultencoding())
		reload(sys)
		sys.setdefaultencoding('utf-8')
	
	#---- get main args 
	if(len(sys.argv)<2):
		print "usage: RzDspMsg.py {--dpmsg message_text} {--video_out file_path} [-xxx options ..]"
		sys.exit(1)
	myprog=sys.argv[0]
	
	#---- get options -----------------------
	parser = OptionParser()
	#---- main params
	parser.add_option("--dpmsg",	action="store",	dest="dpmsg",		type="string", 	default="Hellow World")
	parser.add_option("--video_out",action="store",	dest="video_out",	type="string", 	default="work_out.mpg")

	#---- options
	parser.add_option("--temp",		action="store",	dest="temp",		type="string", 	default=".")
	parser.add_option("--audio_in",	action="store",	dest="audio_in",	type="string", 	default="regzamod/Common/DefaultClips/Silent-180sec.mp3")
	parser.add_option("--sess_id",	action="store",	dest="sess_id",		type="string", 	default="0")
	parser.add_option("--progpath",	action="store",	dest="progpath",	type="string",	default="win32/ffmpeg.exe")
	parser.add_option("--m2ts",		action="store",	dest="m2ts",		type="int",		default=0)
	parser.add_option("--asp_hack",	action="store",	dest="asp_hack",	type="int",		default=0)
	parser.add_option("--aspect",	action="store",	dest="aspect",		type="float",	default=1.7778)
	parser.add_option("--dpsize_w",	action="store",	dest="dpsize_w",	type="int",		default=720)
	parser.add_option("--dpsize_h",	action="store",	dest="dpsize_h",	type="int",		default=480)
	parser.add_option("--dur",		action="store",	dest="dur",			type="float",	default=20.0)
	(opt,args) = parser.parse_args()

	#---- init/default settings -----------
	dbg("main: Start opt.temp=%s, opt.sess_id=%s opt.asp_hack=%d" % (opt.temp,opt.sess_id,opt.asp_hack))
	
	#---- tricky recover msg string
	opt.dpmsg=opt.dpmsg.replace("@"," ")
	d_aspect=opt.aspect
	if(opt.dpsize_w >480 and opt.asp_hack>0):
		#----------------------------------------------------
		# over 480p, regza can't disp mpeg2 with aspect 16/9 
		#----------------------------------------------------
		d_aspect=1.3333
	
	#---- prepair transcoder params -------
	fps_imgstr="%d/%d" % (g_fpi,10)
	prog=opt.progpath
	#para ="-loglevel warning -y -q:v 0" 
	para ="-loglevel warning -y " 
	#para+=" -ss 0 -f image2pipe -r %s -vcodec mjpeg -i pipe:0" % (fps_imgstr)
	para+=" -f image2pipe -r %s -vcodec mjpeg -i pipe:0" % (fps_imgstr)
	
	if(opt.video_out.endswith(".m2ts")):
		# mpegts: new ffmpeg cause long black-screen on start-up (on REGZA-TV)
		para+=" -f mpegts -vcodec mpeg2video -g 1 -acodec ac3 -ab %d" % g_abps   # mpegts is slow start
	else:
		para+=" -f vob -vcodec mpeg2video -acodec ac3 -ab %d" % g_abps
	para+=" -t %f -r 24 -aspect %f -map 1:v -map 0:a %s" % (opt.dur,d_aspect,opt.video_out)
	mpara=para.split()
	args=[prog,"-ss","0","-i",opt.audio_in]+mpara

	#---- kick transcoder(for disp short message video)
	rc=msg_trans(args,opt.dpmsg,opt)
	tm_end0=time.time()
	
	dbg("RzDspMsg.main: AllEnd time elapsed=%.2f" % (tm_end0-tm_start0))
