#!/usr/bin/env python

__author__ = "Gustavo Sverzut Barbieri / Artur Duque de Souza"
__author_email__ = "barbieri@gmail.com / artur.souza@indt.org.br"
__license__ = "GPL"
__version__ = "0.3"

import os
import cgi
import socket
import logging
import urlparse
import threading
import SocketServer
import BaseHTTPServer
import mimetypes

import lib.utils as utils
import lib.file_handler as files
import lib.transcoder as transcoder

from log import Log

__all__ = ("RequestHandler")

class RequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
    """Class that implements an HTTP request handler for our server."""
    log = logging.getLogger("gms.request")
    def_transcoder = None
    transcoders = utils.PluginSet(transcoder.Transcoder)
    transcoders_log = Log()
    tid_queue = []

    menu = {
        "Log": "/get_log.do",
        "Stop": "/stop-transcoder.do",
        "Status": "/status.do",
        "All Log": "/get_all_log.do",
        "Version": "/version.do",
        "Shutdown": "/shutdown.do"
        }

    @classmethod
    def load_plugins_transcoders(cls, directory):
        cls.transcoders.load_from_directory(directory)

        if cls.def_transcoder is None and cls.transcoders:
            cls.def_transcoder = cls.transcoders[0].name
    # load_plugins_transcoders()


    def do_dispatch(self, body):
        self.url = self.path
        pieces = urlparse.urlparse(self.path)
        self.path = pieces[2]
        self.query = cgi.parse_qs(pieces[4])

        url = {
            "/": self.serve_main,
            "/shutdown.do": self.serve_shutdown,
            "/stop-transcoder.do": self.serve_stop_transcoder,
            "/status.do": self.serve_status,
            "/version.do": self.serve_version,
            "/new_id.do": self.serve_new_id,
            "/get_log.do": self.serve_get_log,
            "/get_all_log.do": self.serve_get_all_log,
            "/stream.do": self.serve_stream,
            "/transcode.do": self.serve_transcode,
            "/list.do": self.serve_list,
            "/get_file_info.do": self.serve_file_info,
            }

        try:
            url[self.path](body)
        except KeyError:
            try:
                action = self.query.get("action", None)
                if action and "stream.do" in action:
                    self.serve_stream(body)
                elif os.path.exists("html/%s" % self.path):
                    data = open("html/%s" % self.path)
                    self.wfile.write(data.read())
                else:
                    self.send_error(404, "File not found")
            except Exception, e:
                self.log.error(e)

    # do_dispatch()


    def do_GET(self):
        self.do_dispatch(True)
    # do_GET()


    def do_HEAD(self):
        self.do_dispatch(False)
    # do_HEAD()


    def _nav_items(self):
        ret = ""
        for name, url in self.menu.items():
            ret += utils.getHTML("menu", {"name": name, "url": url})
        return ret
    # _nav_items()


    def serve_main(self, body):
        self.send_response(200)
        self.send_header("Content-Type", "text/html")
        self.send_header('Connection', 'close')
        self.end_headers()
        if body:
            self.wfile.write(utils.getHTML("index", {"menu": self._nav_items()}))
    # serve_main()


    def serve_version(self, body):
        self.send_response(200)
        self.send_header("Content-Type", "text/html")
        self.send_header('Connection', 'close')
        self.end_headers()
        if body:
            self.wfile.write("Version: %s" %  __version__)
    # serve_version


    def serve_shutdown(self, body):
        self.send_response(200)
        self.send_header("Content-Type", "text/html")
        self.send_header('Connection', 'close')
        self.end_headers()
        if body:
            self.wfile.write(utils.getHTML("shutdown"))
        self.server.server_close()
    # serve_shutdown()


    def serve_list(self, body):
        self.send_response(200)
        self.send_header("Content-Type", "text/html")
        self.send_header('Connection', 'close')
        self.end_headers()

        if body:
            file_list = []
            files.list_media_files(utils.config.get_transcoded_location(), file_list)
            output = files.FileList(map(lambda x, y: x+y, file_list,
                                        ["<br>"]*len(file_list)))
            self.wfile.write(output)

    # serve_list()


    def serve_stop_all_transcoders(self, body):
        self.send_response(200)
        self.send_header("Content-Type", "text/html")
        self.send_header('Connection', 'close')
        self.end_headers()
        if body:
            self.server.stop_transcoders()
            self.wfile.write(utils.getHTML("stop_all",
                                           {"menu": self._nav_items()}))
    # serve_stop_all_transcoders()


    def serve_stop_selected_transcoders(self, body, tids=[]):
        self.send_response(200)
        self.send_header("Content-Type", "text/html")
        self.send_header('Connection', 'close')
        self.end_headers()
        opts = ""
        if body:
            transcoders = self.server.get_transcoders()

            for tid in tids:
                for t, r in transcoders:
                    if t.tid == int(tid):
                        try:
                            t.stop()
                        except Exception, e:
                            self.log.info("Plugin already stopped")

                        opts += utils._create_html_item("%s" % t)

                        break

                self.wfile.write(utils.getHTML("stop_selected",
                                               {"menu": self._nav_items(),
                                                "opts": opts}))
    # serve_stop_selected_transcoders()


    def serve_stop_transcoder(self, body):
        req = self.query.get("request", None)
        tid = self.query.get("tid", None)
        if req and "all" in req:
            self.serve_stop_all_transcoders(body)
        elif tid:
            self.serve_stop_selected_transcoders(body, tid[0].split(";"))
        else:
            self.serve_status(body)
    # serve_stop_transcoder()


    def serve_status(self, body):
        self.send_response(200)
        self.send_header("Content-Type", "text/html")
        self.send_header('Connection', 'close')
        self.end_headers()
        stopone = ""
        running = ""
        stopall = ""

        if body:
            tl = self.server.get_transcoders()
            if not tl and not self.query.get("tid", None) and \
                   not self.query.get("running", None):
                running = "<p>No running transcoder.</p>\n"

            elif not tl and self.query.get("tid", None):
                tids = self.query.get("tid")
                for tid in tids:
                    stat = self.transcoders_log.get_status(int(tid))
                    self.wfile.write("%s<br>" % stat)
                return True

            elif self.query.get("running", None):
                for transcoder, request in tl:
                    outf = transcoder.params_first("outfile")
                    tid = transcoder.tid
                    self.wfile.write("%s:%s<br>" % (tid, outf))
                return True

            elif self.query.get("tid", None):
                req_tid = self.query.get("tid")
                for transcoder, request in tl:
                    if str(transcoder.tid) in req_tid:
                        self.wfile.write("Status:%s:%s %%" % (\
                            transcoder.tid, transcoder.status))
                        return True
                stat = self.transcoders_log.get_status(int(req_tid[0]))
                self.wfile.write("%s<br>" % stat)
                return True

            else:
                running = "<p>Running transcoders:</p>\n"
                stopall = utils._create_html_item("<a href='%s?request=all'>"
                                                 "[STOP ALL]</a>" %
                                                 self.menu["Stop"])

                for transcoder, request in tl:
                    stopone += utils._create_html_item("%s;"
                                                       "<a href='%s?tid=%s'>"
                                                       " [STOP] </a>") % (
                        transcoder, self.menu["Stop"], transcoder.tid)

            self.wfile.write(utils.getHTML("status",
                                           {"menu": self._nav_items(),
                                            "running": running,
                                            "stopall": stopall,
                                            "stopone": stopone}))
    # serve_status()


    def _get_transcoder(self):
        # get transcoder option: mencoder is the default
        request_transcoders = self.query.get("transcoder", ["mencoder"])

        for t in request_transcoders:
            transcoder = self.transcoders.get(t)
            if transcoder:
                return transcoder

        if not transcoder:
            return self.transcoders[self.def_transcoder]
    # _get_transcoder()


    def _get_new_id(self, tid):
        self.server.last_tid = utils.create_tid(tid)
        self.tid_queue.append(self.server.last_tid)
        return self.server.last_tid
    # _get_new_id()


    def serve_new_id(self, body):
        self.send_response(200)
        self.send_header("Content-Type", "text/html")
        self.send_header('Connection', 'close')
        self.end_headers()

        if body:
            self.wfile.write("%s" % self._get_new_id(self.server.last_tid))
    # serve_new_id()

    def serve_get_log(self, body):
        self.send_response(200)
        self.send_header("Content-Type", "text/html")
        self.send_header('Connection', 'close')
        self.end_headers()

        if body:
            if self.query.get("tid", None):
                tid = int(self.query.get("tid")[0])
                stat = self.transcoders_log.get_status(tid)
                self.wfile.write("Status: %s" % stat)
            else:
                stat = self.transcoders_log.get_status()
                for rtid, status in stat.iteritems():
                    self.wfile.write("<b>%s</b>: %s<br><br>" % (rtid, status))
    # serve_get_log()

    def serve_get_all_log(self, body):
        self.send_response(200)
        self.send_header("Content-Type", "text/html")
        self.send_header('Connection', 'close')
        self.end_headers()

        if body:
            if self.query.get("tid", None):
                tid = int(self.query.get("tid")[0])
                stat = self.transcoders_log.get_status(tid, True)
                for status in stat:
                    self.wfile.write("%s<br><br>" % status)
            else:
                stat = self.transcoders_log.get_status(None, True)
                for rtid, history in stat.iteritems():
                    for status in history:
                        self.wfile.write("<b>%s</b>: %s<br>" % (rtid, status))
                    self.wfile.write("<br><br>")
    # serve_get_all_log()


    def serve_file_info(self, body):
        if body:

            file_dat = self.query.get("file", None)

            if file_dat:
                self.send_response(200)
                self.send_header("Content-Type", "text/html")
                self.send_header('Connection', 'close')
                self.end_headers()

                try:
                    opts = files.TranscodedFile(file_dat[0], self.query).opts
                    for key in opts.keys():
                        self.wfile.write("%s=%s<br>" % (key, opts.get(key, "None")[0]))

                except Exception, e:
                    self.send_error(500, str(e))
                    return
    # serve_file_info()

    def serve_stream(self, body):
	args = self.query.get("file", None)
	if not args:
	    self.send_error(404, "File not found")
	    return

        filename = args[0];
        if not filename:
            self.send_error(404, "File not found")
            return

        #Only stream files on .transcode dir
        filename = os.path.join (utils.config.get_transcoded_location(),
                                 os.path.basename(filename))
        self.log.error("Stream file: %s" % filename)
        if not os.path.exists (filename):
            self.send_error(404, "File not found")
            return

        size = int(os.path.getsize(filename))
        self.send_response(200)
        self.send_header("Content-Type", mimetypes.guess_type(filename)[0])
        self.send_header("Cache-Control","no-cache")
        self.send_header("Content-Length", size)
        self.end_headers()

        media = open(filename)
        data_in = " "
        total_read = 0

        test_tid = int(self.query.get("tid", "0")[0])
        if test_tid == 0 or test_tid not in self.tid_queue:
            test_tid = self._get_new_id(self.server.last_tid)

        self.transcoders_log.insert(test_tid, "gms.Stream: %s" % filename)

        try:
            file_data = ""
            while data_in != "":
                data_in = media.read(4096)
                file_data += data_in

                #total_read += 4096
            self.wfile.write(file_data)
                #status = utils.progress_bar(total_read, size, 50)
                #msg_status = "Status:%s:%s%%" % (test_tid, status)
                #self.transcoders_log._update_status(test_tid, msg_status)

            self.transcoders_log._update_status(test_tid, "OK: Done")

        except Exception, e:
            self.log.error("Stream error: %s" %e)
            self.transcoders_log._update_status(test_tid, "Error: %s" % e)
    # serve_stream()

    def serve_transcode(self, body):
        type = self.query.get("type", None)[0]
        if type.upper() == "FILE":
            self.send_error(404, "Transcode local files not allowed")
            return

        transcoder = self._get_transcoder()
        try:
            obj = transcoder(self.query)
        except Exception, e:
            self.send_error(500, str(e))
            return

        self.send_response(200)
        self.send_header("Content-Type", obj.get_mimetype())
        self.send_header("Cache-Control","no-cache")
        self.end_headers()

        if body:
            test_tid = int(self.query.get("tid", "0")[0])
            if test_tid == 0 or test_tid not in self.tid_queue:
                test_tid = self._get_new_id(self.server.last_tid)

            if self.query.get("transcoder", None):
                self.transcoders_log.insert(test_tid, "gms.%s" % obj.name)
                obj.tid = test_tid
                obj.log = self.transcoders_log

                self.server.add_transcoders(self, obj)
                if obj.start(self.wfile):
                    self.transcoders_log.info(test_tid, "OK")
                else:
                    self.transcoders_log.info(test_tid, "Fail")

                self.server.del_transcoders(self, obj)
                files.TranscodedFile("", self.query)

    # serve_stream()


    def log_request(self, code='-', size='-'):
        self.log.info('"%s" %s %s', self.requestline, str(code), str(size))
    # log_request()


    def log_error(self, format, *args):
        self.log.error("%s: %s" % (self.address_string(), format % args))
    # log_error()


    def log_message(self, format, *args):
        self.log.info("%s: %s" % (self.address_string(), format % args))
    # log_message()

# RequestHandler
