#
# This file is part of GNU Enterprise.
#
# GNU Enterprise is free software; you can redistribute it
# and/or modify it under the terms of the GNU General Public
# License as published by the Free Software Foundation; either
# version 3, or (at your option) any later version.
#
# GNU Enterprise is distributed in the hope that it will be
# useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
# PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public
# License along with program; see the file COPYING. If not,
# write to the Free Software Foundation, Inc., 59 Temple Place
# - Suite 330, Boston, MA 02111-1307, USA.
#
# Copyright 2000-2009 Free Software Foundation
#
# FILE:
# uidrivers/html/GFServer.py
#
# DESCRIPTION:
#
# NOTES:
#

import os.path, sys
from urllib import unquote
from gnue.common.utils import http
from gnue.common.utils.uuid import UUID
from BaseHTTPServer import HTTPServer
from SocketServer import ThreadingMixIn

from gnue.common import events

from UISplashScreen import SplashScreen
from gnue.forms.GFInstance import GFInstance
from gnue.common.apps import GConfig, errors
from gnue.forms.uidrivers.html.common import textEncode, textDecode
from Generator import build_basic_dialog

from GFController import ComController

from types import UnicodeType

try:
    from simplejson import JSONEncoder # JSONDecoder
except:
    print "You need to install simplejson to use the html uidriver."
    raise ImportError

_iconpath = GConfig.getInstalledBase('form_images', 'common_images')
_includepath = os.path.join(GConfig.getInstalledBase('common_shared'),'webfrontend')
_gnuejs_path = os.path.dirname(__file__)


class ThreadingHTTPServer (ThreadingMixIn, HTTPServer):
    pass

# =============================================================================
# GNUe Forms HTML UI driver Request handler
# =============================================================================

class GFServer:


    def __init__(self, gfclient):
        self.splash = SplashScreen()
        self.instances = {}
        # self.gfclient = gfclient
        self.jsonenc = JSONEncoder()
        self._controller = ComController()
        self._controller.gfclient=gfclient

        # assign form file from 1st free argument
        if len (gfclient.ARGUMENTS):
            self._controller.base_form = gfclient.ARGUMENTS [0]
        else:
            raise StartupError, u_("No Forms Definition File Specified.")

    def serve(self):
        print '\nGNUe Forms HTML UI driver is loaded.'
        print '\n-- please point your browser to http://127.0.0.1:8000 --'
        server = ThreadingHTTPServer(('',8000), GFRequestHandler)
        server.GFServer = self
        server.serve_forever()


    # TODO: overwrite finalizeRequest to pass more data (controller object) to Requesthandler

    # TODO: remove the following commands from here and directly call controller object

    def createFormsInstance(self, id, userParameters):
        self._controller.startSession(id, userParameters)

    def displayFormsInstance(self, uuid, form):
        return self._controller.pullHtml(uuid, form)

    def executeCmd(self, uuid, cmd, args):
        return self._controller.handleRequest(uuid, cmd, args)


# =============================================================================
# GNUe Forms HTML UI driver Request handler
# =============================================================================

class GFRequestHandler(http.HTTPRequestHandler):

    """
    Handle  requests sent via HTTP connections.

    @cvar protocol_version: Set to 'HTTP/1.1' so we do have persistent
      connections.
    """

    # Make sure to support persistent connections
    protocol_version = "HTTP/1.1"

    # ---------------------------------------------------------------------------
    # Process a GET request
    # ---------------------------------------------------------------------------

    def do_GET (self):
        """
        ....
        """
        try:
            if self.path=="/":
                uuid = UUID.generate_random ()
                forward_url = "session_%s/index.html" % uuid
                response = self.server.GFServer.splash.get_html(forward_url)
                self.push_content(response)
                self.server.GFServer.createFormsInstance(uuid, {})

            elif self.path=="/splashscreen.png":
                response = self.server.GFServer.splash.getPicture()
                self.push_content(response,"image/png")

            # FIXME: distinguish between different forms of one session here
            elif self.path[0:9]=="/session_" and self.path[41]=="/" and \
                 self.path[-5:]==".html":
                uuid=self.path[9:41]
                formname=self.path[42:-5]
                response=self.server.GFServer.displayFormsInstance(uuid, formname)
                self.push_content(response)

            elif self.path[0:9]=="/jsonrpc_" and self.path[41:42]=="?":
                uuid=self.path[9:41]
                # FIXME: Use standart argument parser
                arg_list = self.path[42:].split('&')

                args = {}
                for i in arg_list:
                    z=i.split('=')
                    args[z[0]]=unquote(z[1]).decode("utf-8")

                try:
                    cmd=args['cmd']
                except:
                    cmd=""

                try:
                    response = self.server.GFServer.executeCmd(uuid,cmd,args)
                except:
                    (group, name, message, detail) = errors.getException()
                    message = u"""<HTML><HEAD></HEAD><BODY><H1>Exception occured!</H1>
                        Group: %s<BR>
                        Name: %s<BR>
                        Message: %s<BR>
                        Details: <BR><PRE>%s</PRE></BODY></HTML>
                        """ % (group, name, message, detail)
                    response = [["alert","Warning!",message]]
                response = self.server.GFServer.jsonenc.encode(response)
                self.push_content(response,"text/text")
                print "JSON: %s -> %s" % (self.path,response)

            # get gnue specific js file from source directory
            elif self.path=="/incl/gnue.js":
                self.deliver_file(_gnuejs_path, 'gnue.js')

            # Include file handling for libraries
            elif self.path[0:6]=="/incl/":
                self.deliver_file(_includepath, self.path[6:])

            # file handling for icons
            elif self.path[0:6]=="/icon/":
                self.deliver_file(_iconpath, self.path[6:])

            else:
                self.send_response(404)
                self.connection.shutdown (1)
                print self.path

        except:
            (group, name, message, detail) = errors.getException()
            message = u"""<HTML><HEAD></HEAD><BODY><H1>Exception occured!</H1>
            Group: %s<BR>
            Name: %s<BR>
            Message: %s<BR>
            Details: <BR><PRE>%s</PRE></BODY></HTML>
            """ % (group, name, message, detail)
            self.push_content(message)
            print textEncode(message)

        # If a shutdown of the connection is requested do so, although we assume to
        # have a persistent connection.
        if self.close_connection:
            self.connection.shutdown (1)

    def deliver_file(self, base, path):

        # FIXME: implement security measures:
        #        1: normalize path
        #        2: remove all ".."
        #
        realpath=os.path.join(base, path)

        if realpath[-3:]==".js":
            mimetype = "text/javascript"
        elif realpath[-4:]==".css":
            mimetype = "text/css"
        elif realpath[-4:]==".htm" or realpath[-5:]==".html":
            mimetype = "text/html"
        elif realpath[-4:]==".gif":
            mimetype = "image/gif"
        elif realpath[-4:]==".png":
            mimetype = "image/png"
        elif realpath[-4:]==".jpg" or realpath[-5:]==".jpeg":
            mimetype = "image/jpeg"
        else:
            mimetype = "failed"

        if mimetype != "failed" and os.path.exists(realpath):
            response = ""
            for line in open(realpath,"rb"):
                response+=line
            self.push_content(response,mimetype)

        else:
            self.send_response(404)
            self.connection.shutdown (1)
            print self.path
            if self.path=="/incl/dojo.js":
                print "****************************************************************"
                print " You need dojo (www.dojotoolkit.org) to use the html uidriver."
                print " Please install dojo 4.0 or above on your computer and add the "
                print " the install path to gnue.conf: 'htmlui_include_path = <path>'"
                print " Currently searching for dojo.js at: '%s' " % realpath
                print "****************************************************************"

    def push_content(self, response, content_type="text/html"):
        if type(response)==UnicodeType:
            # FIXME: Should local encoding be used?
            response = response.encode('utf-8')

        self.send_response (200, flush = False)
        self.send_header ("Content-type", content_type, flush = False)
        self.send_header ("Content-length", str (len (response)), flush = False)
        self.send_header ("Cache-Control","no-cache, must-revalidate", flush = False)
        self.send_header ("Pragma","no-cache", flush = False)
        self.end_headers (flush = False)

        # Add the response to the send-queue and finally flush everything to the
        # socket.
        self.write (response, flush = True)


def start_server(GFClient):
    GFServer(GFClient).serve()
