import os
import sys
import lib
import time
import shlex
import signal
import socket
import ConfigParser
import logging as log

from select import *
from subprocess import *

class Media(object):

    def __init__(self, config):

        self.config = config
        self.path = ""
        self.args = []
        self.language = None
        self.subtitle = None
        self.mpegopts = None
        self.socket = None
        self.child_pid = None
        self.mplayer = None
        self.mencoder_pid = None
        self.mplayer_pid = None

    # __init__

    def setup_opts(self, options):

        for opt in options:

            if opt == "local":
                self.mplayer = lib.which("mplayer")

            elif opt.find("language=") >= 0:
                try:
                    lan = opt.split("=")[1]
                    if len(lan) < 2:
                        self.language = lan
                except Exception, e:
                    log.error("Bad language option: %s" % e)

            elif opt.find("subtitle=") >= 0:
                try:
                    sub = opt.split("=")[1]
                    if len(sub) < 2:
                        self.language = sub
                except Exception, e:
                    log.error("Bad subtitle option: %s" % e)

            elif opt.find("format=") >= 0:
                try:
                    self.mpegopts = opt.split("=")[1]
                except Exception, e:
                    log.error("Bad format option: %s" % e)

    # setup_opts

    def run_mplayer(self):
        msg = self.filename

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

        self.mplayer_pid = Popen([self.mplayer, self.filename, "1> %s" % os.devnull,\
                                  "2> %s" % os.devnull], stdout=PIPE, close_fds=True)

    # run_mplayer

    def setup_mencoder(self):
        self.path = self.config.get("Mencoder", "path")
        mp = Popen([self.path], stdout=PIPE, close_fds=True)

        version = mp.stdout.read().split("MEncoder ")[1].split(" (C)")[0].split("-")[-1]

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

        os.kill(mp.pid, signal.SIGKILL)
        log.info("Mencoder version: %s" % version)

        if self.mencoder_old:
            try:
                self.fifo = self.config.get("Mencoder", "fifo_path")
                os.mkfifo(self.fifo)
            except Exception, e:
                log.info("Fifo: %s" % e)
        else:
            self.fifo = "-"

    # setup_mencoder

    def setup_audio(self):

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

    # setup_audio


    def setup_video(self):

        video = ""

        video += " -of %s" % self.mux
        video += " -ofps %s" % self.fps

        if self.vcodec == "nuv" or self.vcodec == "xvid"\
               or self.vcodec == "qtvideo" or self.vcodec == "copy":
            video += " -ovc %s" % self.vcodec
        else:
            video += " -ovc lavc -lavcopts vcodec=%s:vbitrate=%s" % (
                self.vcodec, self.vbitrate)

        if self.mux == "mpeg" and self.mpegopts is not None:
            video += " -mpegopts format=%s" % self.mpegopts

        video += " -vf scale=%s:%s" % (self.width, self.height)

        return video

    # setup_video


    def arg_append(self, args, options):
        l = shlex.split(options)
        for i in l:
            args.append(i)

    # arg_append

    def setup_args(self, args):

        args.append(self.path)
        args.append(self.filename)

        if self.language != None:
            self.arg_append(args, "-alang %s" % self.language)

        if self.subtitle != None:
            self.arg_append(args, "-slang %s" % self.subtitle)
            self.arg_append(args, "-subfps %s" % self.fps)

        self.arg_append(args, "-idx")
        self.arg_append(args, self.audio_opts)
        self.arg_append(args, self.video_opts)

        self.arg_append(args, "-really-quiet")
        self.arg_append(args, "-o %s" % self.fifo)
        self.arg_append(args, "2> %s" % os.devnull)

    # setup_args

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

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

        elif self.kind == "dvd":
            self.filename = "dvd://" + filename

        return (True, "")

    # setup_filename

    def setup_socket(self):
        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)

        try:
            self.socket.bind( ('', self.port) )
            self.socket.listen(1)
        except Exception, e:
            log.error("Could not create socket: %s" % e)
            return (False, e)

        return (True, "")

    # setup_socket

    '''
    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

    '''


    # good one: /tmp/dvb.mpg avi mpeg4 400 25 mp3lame 192 320 240
    # file:///tmp/dvb.mpg mpeg mpeg1video 400 25 mp2 192 320 240 format=mpeg1
    # dvd://4 mpeg mpeg1video 400 25 mp3lame 192 400 240 language=en local
    # file:///tmp/mpg/bad_day.mpg avi mpeg4 400 25 mp3 192 320 240

    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.setup_opts(options)
        self.audio_opts = self.setup_audio()
        self.video_opts = self.setup_video()
        self.setup_args(self.args)

        ret_val = self.setup_socket()
        if not ret_val[0]:
            return ret_val[1]

        return True

    # setup

    def play(self):

        log.info("Starting Mencoder: %s" % self.args )

        try:
            self.mencoder_pid = Popen(self.args, stdout=PIPE, close_fds=True)
        except Exception, e:
            msg = "Could not init Mencoder: %s" % e
            log.error(msg)
            return msg

        if self.mencoder_old: self.pout = open(self.fifo)
        else: self.pout = self.mencoder_pid.stdout

        self.child_pid = os.fork()

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

            data = self.pout.read(4096)

            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, e:
                    log.error("Socket error: %s" % e)
                    retry += 1

                data = self.pout.read(4096)

            if retry < 5:
                log.info("Finished sending Data to client: %s" % addr[0])
            else:
                log.error("Client timed out, retried more than %s times" % retry)

            os.kill(self.mencoder_pid.pid, signal.SIGKILL)
            sys.exit(0)

        return True

        # play


    def stop(self):
        try:

            if self.mencoder_pid:
                os.kill(self.mencoder_pid.pid, signal.SIGKILL)
                self.mencoder_pid = None

            if self.mplayer_pid:
                os.kill(self.mplayer_pid.pid, signal.SIGKILL)
                self.mplayer_pid = None

            if self.socket != None:
                self.socket.close()

            if self.child_pid != None:
                os.kill(self.child_pid, signal.SIGKILL)

        except Exception, e:
            log.error("Stop error: %s" % e)

    # stop
