import os, sys

import cherrypy
from mako.template import Template
from mako.lookup import TemplateLookup
import simplejson
import datetime, decimal
from StringIO import StringIO
from invirt.config import structs as config
from webcommon import State

class MakoHandler(cherrypy.dispatch.LateParamPageHandler):
    """Callable which sets response.body."""
    
    def __init__(self, template, next_handler, content_type='text/html; charset=utf-8'):
        self.template = template
        self.next_handler = next_handler
        self.content_type = content_type
    
    def __call__(self):
        env = globals().copy()
        env.update(self.next_handler())
        cherrypy.response.headers['Content-Type'] = self.content_type
        return self.template.render(**env)
        

class MakoLoader(object):
    
    def __init__(self):
        self.lookups = {}

    def get_lookup(self, directories, module_directory=None,
                     collection_size=-1, imports=[], **kwargs):
        # Find the appropriate template lookup.
        key = (tuple(directories), module_directory)
        try:
            lookup = self.lookups[key]
        except KeyError:
            lookup = TemplateLookup(directories=directories,
                                    module_directory=module_directory,
                                    collection_size=collection_size,
                                    default_filters=['decode.utf8'],
                                    input_encoding='utf-8',
                                    output_encoding='utf-8',
                                    imports=imports,
                                    )
            self.lookups[key] = lookup
        return lookup

    def __call__(self, filename, directories, module_directory=None,
                 collection_size=-1, content_type='text/html; charset=utf-8',
                 imports=[]):
        cherrypy.request.lookup = lookup = self.get_lookup(directories, module_directory,
                                                           collection_size, imports)
        cherrypy.request.template = t = lookup.get_template(filename)
        cherrypy.request.handler = MakoHandler(t, cherrypy.request.handler, content_type)

cherrypy.tools.mako = cherrypy.Tool('on_start_resource', MakoLoader())

def revertStandardError():
    """Move stderr to stdout, and return the contents of the old stderr."""
    errio = sys.stderr
    if not isinstance(errio, StringIO):
        return ''
    sys.stderr = sys.stdout
    errio.seek(0)
    return errio.read()

def catchStderr():
    old_handler = cherrypy.request.handler
    def wrapper(*args, **kwargs):
        sys.stderr = StringIO()
        ret = old_handler(*args, **kwargs)
        e = revertStandardError()
        if e:
            if isinstance(ret, dict):
                ret["error_text"] = e
        return ret
    if old_handler:
        cherrypy.request.handler = wrapper

cherrypy.tools.catch_stderr = cherrypy.Tool('before_handler', catchStderr)

class JSONEncoder(simplejson.JSONEncoder):
	def default(self, obj):
		if isinstance(obj, datetime.datetime):
			return str(obj)
		elif isinstance(obj, decimal.Decimal):
			return float(obj)
		else:
			return simplejson.JSONEncoder.default(self, obj)

def jsonify_tool_callback(*args, **kwargs):
    if not cherrypy.request.cached:
        response = cherrypy.response
        response.headers['Content-Type'] = 'text/javascript'
        response.body = JSONEncoder().iterencode(response.body)

cherrypy.tools.jsonify = cherrypy.Tool('before_finalize', jsonify_tool_callback, priority=30)

def require_login():
    """If the user isn't logged in, raise 403 with an error."""
    if cherrypy.request.login is False:
        raise cherrypy.HTTPError(403,
            "You are not authorized to access that resource")

cherrypy.tools.require_login = cherrypy.Tool('on_start_resource', require_login, priority=150)

def require_POST():
    """If the request isn't a POST request, raise 405 Method Not Allowed"""
    if cherrypy.request.method != "POST":
        raise cherrypy.HTTPError(405,
                                 "You must submit this request with POST")

cherrypy.tools.require_POST = cherrypy.Tool('on_start_resource', require_POST, priority=150)

def remote_user_login():
    """Get the current user based on the SSL or GSSAPI environment
variables and store it in the request object's login variable. This
conforms to the CherryPy API:
http://www.cherrypy.org/wiki/RequestObject#login

If the user is logged in successfully, cherrypy.request.login is set
to the username. If the user failed to log in, cherrypy.request.login
is set to False. If the user did not attempt authentication,
cherrypy.request.login is set to None."""
    environ = cherrypy.request.wsgi_environ
    user = environ.get('REMOTE_USER')
    if user is None:
        return
    else:
        cherrypy.request.login = None # clear what cherrypy put there

    if environ.get('AUTH_TYPE') == 'Negotiate':
        # Convert the krb5 principal into a krb4 username
        if not user.endswith('@%s' % config.kerberos.realm):
            cherrypy.request.login = False # failed to login
        else:
            cherrypy.request.login = user.split('@')[0].replace('/', '.')
    else:
        cherrypy.request.login = user

cherrypy.tools.remote_user_login = cherrypy.Tool('on_start_resource', remote_user_login, priority=50)

def invirtwebstate_init():
    """Initialize the cherrypy.request.state object from Invirt"""
    if not hasattr(cherrypy.request, "state"):
        cherrypy.request.state = State(cherrypy.request.login)

cherrypy.tools.invirtwebstate = cherrypy.Tool('on_start_resource', invirtwebstate_init, priority=100)

class View(object):
    _cp_config = {'tools.mako.directories': [os.path.join(os.path.dirname(__file__),'templates')]}
