import os
import sys
import lib
import time
import signal
import socket
import ConfigParser

from select import *
from subprocess import *

class Media(object):

    def __init__(self, config):

        self.config = config
        self.args = ""
        self.language = "en"
        self.socket = None
        self.child_pid = None
        self.mplayer = None
        self.mencoder_pid = None
        self.mplayer_pid = None
        signal.signal(signal.SIGABRT, self.kill_handler)

    def kill_handler(self, sig, frame):
        try:
            os.kill(self.mplayer_pid.pid + 1, signal.SIGKILL)
            sys.exit(0)
        except:
            lib.log("Problems closing child")

    def set_args(self, options):

        for opt in options:

            if opt == "local":
                self.mplayer = os.popen("which mplayer").read().strip()

            elif opt.find("language=") >= 0:
                try:
                    self.language = opt.split("=")[1]
                except:
                    lib.log("Bad language option")

            elif opt.find("format=") >= 0:
                try:
                    self.mux += " -mpegopts format=%s" % opt.split("=")[1]
                except:
                    lib.log("Bad format option")


    def run_mplayer(self):
        msg = "%s 1>/dev/null 2>/dev/null" % self.filename

        if self.kind == "dvd":
            msg = "dvd://" + msg

        self.mplayer += " " + msg
        self.mplayer_pid = Popen(self.mplayer, shell=True)

    def setup_mencoder(self):
        self.path = self.config.get("Mencoder", "path")
        a, b = os.popen2(self.path)
        version = b.read().split("MEncoder ")[1].split(" (C)")[0].split("-")[-1]

        if version > "4.1.1": self.mencoder_old = False
        else: self.mencoder_old = True

        lib.log("Mencoder version: %s" % version)

        a.close()
        b.close()

        if self.mencoder_old:
            self.fifo = self.config.get("Mencoder", "fifo_path")
        else:
            self.fifo = "-"

    def setup_filename(self, filename):
        try:
            self.kind, self.filename = filename.split("://")
        except:
            return (False, "Wrong filename protocol")

        if self.acodec == "mp3lame":
            audio = "-oac mp3lame -lameopts cbr:br=%s vol=5" % self.abitrate
        else:
            audio = "-oac lavc -lavcopts acodec=%s:abitrate=%s" % (\
                    self.acodec, self.abitrate)

        if self.kind == "file":
            if not os.path.exists(self.filename):
                msg = "File requested does not exist. SETUP failed."
                lib.log(msg)
                return (False, msg)

            self.args += " %s -mf fps=%s -of %s %s"\
                         " -ovc lavc -lavcopts vcodec=%s:vbitrate=%s -vf scale=%s:%s"\
                         " -really-quiet -o %s 2>/dev/null" % (
                self.filename, self.fps, self.mux, audio, self.vcodec,
                self.vbitrate, self.width, self.height, self.fifo)

        elif self.kind == "dvd":
            self.args += " dvd://%s -alang %s -vf scale=%s:%s %s"\
                         " -of %s -ovc lavc -lavcopts vcodec=%s:vbitrate=%s"\
                         " -ofps %s -really-quiet -o %s 2>/dev/null" % (
                self.filename, self.language, self.width, self.height, audio,
                self.mux, self.vcodec, self.vbitrate, self.fps, self.fifo)

        return (True, "")

    '''
    MENCODER SETUP DESCRIPTION
    ===========================

    -> mux, vcodecs and acodecs
     |-> mencoder (-of | -ovc | -oac) help

    -> if used mpeg as mux:
     |-> to setup format: format=%s as an option at the end

    '''

    def setup(self, filename, mux, vcodec, vbitrate,\
              fps, acodec, abitrate, width, height, port, options):

        self.mux = mux
        self.vcodec = vcodec
        self.vbitrate = vbitrate
        self.fps = fps
        self.acodec = acodec
        self.abitrate = abitrate
        self.width = width
        self.height = height
        self.port = int(port)

        self.setup_mencoder()
        ret_val = self.setup_filename(filename)

        if not ret_val[0]:
            return ret_val[1]

        self.set_args(options)

        # good one: /tmp/dvb.mpg avi mpeg4 400 25 mp3lame 192 320 240 5000 file
        # /tmp/dvb.mpg mpeg mpeg1video 400 25 mp2 192 320 240 5000 format=mpeg1 file
        #4 mpeg mpeg1video 400 25 mp3lame 192 400 240 5000 language=en local dvd
        if self.socket != None:
            del(self.socket)

        self.socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
        self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.socket.bind( ('', self.port) )
        self.socket.listen(1)

        return 0


    def play(self):

        if self.mencoder_old:
            try:
                os.mkfifo(self.fifo)
            except:
                lib.log("Fifo already exists")


        lib.log("Starting Mencoder: %s %s" % (self.path, self.args) )
        # exec Mencoder
        if self.mencoder_old:
            self.mencoder_pid = Popen(self.path + self.args, shell=True)
            self.pout = open(self.fifo)
        else:
            self.path += self.args
            pin, self.pout = os.popen2(self.path)

        self.child_pid = os.fork()

        if self.child_pid == 0:
            conn,addr= self.socket.accept()
            lib.log("Sending Data to client: %s" % addr[0])

            data = self.pout.read(1024)

            conn.settimeout(5)
            retry = 0

            while data != "" and retry < 5:
                try:
                    conn.send(data)
                    r, w, x = select([conn], [], [], 0)
                    if conn in r:
                        back = conn.recv(1024)
                        if back == "OK" and self.mplayer and not self.mplayer_pid:
                            self.run_mplayer()

                except socket.error:
                    lib.log("Socket error (maybe timeout ?)")
                    retry += 1

                data = self.pout.read(1024)

            if retry < 5:
                lib.log("Finished sending Data to client: %s" % addr[0])
            else:
                lib.log("Client timed out")

            sys.exit(0)


    def stop(self):
        try:
            if self.mplayer_old:
                os.kill(self.mencoder_pid.pid + 1, signal.SIGKILL)
            else:
                self.pout.close()
            self.mplayer = None
        except:
            lib.log("Trying to stop before playing...")

        if self.socket != None:
            lib.log("Closing socket")
            self.socket.close()

            lib.log("Trying to stop Mencoder process")
            if self.child_pid != None:
                os.kill(self.child_pid, signal.SIGABRT)
