from django.conf import settings
from django.conf.urls.defaults import *
from django.core import urlresolvers

from django.http import Http404
from django.shortcuts import get_object_or_404

from django.contrib.sites.models import SiteManager, Site


from sphene.community.models import Group
from sphene.community.sphsettings import get_sph_setting


import re
import logging


logger = logging.getLogger('sphene.community.middleware')

def my_get_current(self):
    try:
        group = get_current_group()
    except AttributeError, e:
        group = None
    if not group:
        return self.get(pk=settings.SITE_ID)
    else:
        return Site( pk=settings.SITE_ID, domain = group.baseurl, name = group.name )

SiteManager.get_current = my_get_current
                    


# If all are used the following order has to remain:
# 1.) ThreadLocals (required)
# 2.) MultiHostMiddleware (optional, but very much recommended!)
# 3.) GroupMiddleware (required)
# all other orders will lead to problems ..


#
# Short descriptions:
#  every module within SCT requires a Group object - this can either come from the
#  MultiHostMiddleware - ie. from the domain/host name (vhosts) or from an URL parameter.
#  we need to somehow distuingish between those two within the reverse URL lookups.
#

class MultiHostMiddleware:
    def process_request(self, request):
        try:
            sphdata = get_current_sphdata()
            host = request.META['HTTP_HOST']
            if host[-3:] == ':80':
                host = host[:-3] # ignore default port number, if present
            urlconf = None
            urlconf_params = None
            if host in settings.SPH_HOST_MIDDLEWARE_URLCONF_MAP:
                urlconf = settings.SPH_HOST_MIDDLEWARE_URLCONF_MAP[host]
            else:
                # TODO cache results ? - cache regular expressions .. ?
                for key, value in settings.SPH_HOST_MIDDLEWARE_URLCONF_MAP.iteritems():
                    regex = re.compile(key)
                    match = regex.match(host)
                    if not match:
                        continue
                    # We got a match.
                    urlconf = value
                    urlconf_params = 'params' in urlconf and urlconf['params'].copy() or dict()
                    namedgroups = match.groupdict()
                    for key, value in namedgroups.iteritems():
                        urlconf_params[key] = value
                    break
            if not urlconf:
                logging.info("Unable to find urlconf for %s / map: %s !!!" % (host, str(settings.SPH_HOST_MIDDLEWARE_URLCONF_MAP)))
                return
            while 'alias' in urlconf:
                urlconf = settings.SPH_HOST_MIDDLEWARE_URLCONF_MAP[urlconf['alias']]
                
            myparams = urlconf_params or urlconf['params']

            # if there is a parameter called 'groupName', load the given group,
            # and set it into the thread locals.
            if myparams and 'groupName' in myparams:
                try:
                    set_current_group( Group.objects.get( name__exact = myparams['groupName'] ) )
                    sphdata['group_fromhost'] = True
                except Group.DoesNotExist:
                    pass
            set_current_urlconf_params( urlconf_params or urlconf['params'] )
            request.urlconf = urlconf['urlconf']
            
        except KeyError:
            pass # use default urlconf

class GroupMiddleware(object):
    def process_view(self, request, view_func, view_args, view_kwargs):
        request.attributes = { }
        if 'urlPrefix' in view_kwargs:
            urlPrefix = view_kwargs['urlPrefix']
            if urlPrefix != '':
                urlPrefix = '/' + urlPrefix
            request.attributes['urlPrefix'] = urlPrefix
            del view_kwargs['urlPrefix']
        group = None
        groupName = None
        if get_current_urlconf_params() and 'groupName' in get_current_urlconf_params():
            groupName = get_current_urlconf_params()['groupName']
            # Check if we already loaded the current group in another
            # middleware.
            group = get_current_group()
            if group is None or group.name != groupName:
                try:
                    group = get_object_or_404(Group, name = groupName)
                except Http404, e:
                    # We allow access to admin site without group.
                    if not view_func.__module__.startswith('django.contrib.admin.'):
                        raise e
        if 'groupName' in view_kwargs:
            if view_kwargs.get( 'noGroup', False ):
                del view_kwargs['groupName']
                del view_kwargs['noGroup']
            else:
                groupName = view_kwargs['groupName']
                if groupName == None: groupName = get_current_urlconf_params()['groupName']
                sphdata = get_current_sphdata()
                if group == None:
                    group = get_object_or_404(Group, name = groupName )
                    sphdata['group_fromhost'] = not get_sph_setting('community_groups_in_url')
                del view_kwargs['groupName']
                view_kwargs['group'] = group
                request.attributes['group'] = group
                #settings.TEMPLATE_DIRS = ( "/tmp/hehe", ) + settings.TEMPLATE_DIRS
                
        set_current_group( group )
        return None

# copied from http://code.djangoproject.com/wiki/CookBookThreadlocalsAndUser
# threadlocals middleware
try:
    from threading import local
except ImportError:
    from django.utils._threading_local import local

#print "Executing module body."
_thread_locals = local()
def get_current_request():
    return getattr(_thread_locals, 'request', None)

def get_current_urlconf():
    return getattr(get_current_request(), 'urlconf', None)

def get_current_session():
    req = get_current_request()
    if req == None: return None
    return req.session

def get_current_user():
    user = getattr(_thread_locals, 'user', None)
    if user != None: return user
    req = get_current_request()
    if req == None: return None
    return req.user

def get_current_group():
    try:
        return _thread_locals.group
    except AttributeError, e:
        logger.error('Unable to retrieve group. Is GroupMiddleware enabled?')
        raise e

def get_current_urlconf_params():
    return getattr(_thread_locals, 'urlconf_params', None)

def set_current_urlconf_params(urlconf_params):
    _thread_locals.urlconf_params = urlconf_params

def set_current_group(group):
    _thread_locals.group = group

def get_current_sphdata():
    return getattr(_thread_locals, 'sphdata', None)
    
class ThreadLocals(object):
    """Middleware that gets various objects from the
    request object and saves them in thread local storage."""
    def process_request(self, request):
        _thread_locals.request = request
        _thread_locals.user = getattr(request, 'user', None)
        _thread_locals.sphdata = { }
        try:
            delattr(_thread_locals, 'urlconf_params')
        except AttributeError:
            pass
        _thread_locals.group = None
        



## copied from http://code.djangoproject.com/wiki/PageStatsMiddleware
import re
from operator import add
from time import time
from django.db import connection
import logging

logger = logging.getLogger('sphene.community.middleware')

class StatsMiddleware(object):

    def process_view(self, request, view_func, view_args, view_kwargs):

        # turn on debugging in db backend to capture time
        from django.conf import settings
        debug = settings.DEBUG
        settings.DEBUG = True

        # get number of db queries before we do anything
        n = len(connection.queries)

        # time the view
        start = time()
        response = None
        try:
            response = view_func(request, *view_args, **view_kwargs)
        finally:
            if request.path.startswith('/static'):
                return response

            totTime = time() - start

            # compute the db time for the queries just run
            queries = len(connection.queries) - n
            if queries:
                dbTime = reduce(add, [float(q['time']) 
                                      for q in connection.queries[n:]])
            else:
                dbTime = 0.0

            # and backout python time
            pyTime = totTime - dbTime

            # restore debugging setting
            settings.DEBUG = debug

            stats = {
                'totTime': totTime,
                'pyTime': pyTime,
                'dbTime': dbTime,
                'queries': queries,
                }

            # replace the comment if found            
            if response and response.content:
                s = response.content
                regexp = re.compile(r'(?P<cmt><!--\s*STATS:(?P<fmt>.*?)-->)')
                match = regexp.search(s)
                if match:
                    s = s[:match.start('cmt')] + \
                        match.group('fmt') % stats + \
                        s[match.end('cmt'):]
                    out = match.group('fmt') % stats
                    #for query in connection.queries:
                    #    logger.debug( '  %5s : %s' % (query['time'], query['sql'], ) )
                    response.content = s

            querystr = ''
            for query in connection.queries:
                sql = query['sql']
                if sql is None: sql = " ?WTF?None?WTF? "
                querystr += "\t" + query['time'] + "\t" + sql + "\n"
            logger.debug( 'All Queries: %s' % (querystr,) )
            logger.info( 'Request %s: %s' % (request.get_full_path(), stats,) )

        return response

from django.core.handlers.modpython import ModPythonRequest

class ModPythonSetLoggedinUser(object):
    def process_request(self, request):
        if not isinstance(request, ModPythonRequest):
            return None

        if not hasattr(request, '_req'):
            return None

        if not hasattr(request, 'user') or not request.user.is_authenticated():
            return None

	# request.user.username is a unicode string
	# but _req.user requires an ascii string (afaik)
        request._req.user = str(request.user.username)

        return None


class PsycoMiddleware(object):
    def process_request(self, request):
        import psyco
        psyco.profile()
        return None

from sphene.community import PermissionDenied
from django.template.context import RequestContext
from django.shortcuts import render_to_response
from django.template import loader
from django.http import HttpResponseForbidden
class PermissionDeniedMiddleware(object):
    def process_exception(self, request, exception):
        if isinstance(exception, PermissionDenied):
            return HttpResponseForbidden(loader.render_to_string( 'sphene/community/permissiondenied.html',
                                                                  { 'exception': exception,
                                                                    },
                                                                  context_instance = RequestContext(request) ) )
        return None



class LastModified(object):
    """ Middleware that sets the Last-Modified and associated headers,
    if requested by the view. (By setting the sph_lastmodified attribute
    of the response object.

    based on a contribution of Andrew Plotkin:
    http://eblong.com/zarf/boodler/sitework/
    """

    def process_response(self, request, response):
        stamp = getattr(response, 'sph_lastmodified', None)
        if not stamp: return response

        import rfc822
        import calendar
        if stamp is True:
            val = rfc822.formatdate()
        else:
            val = rfc822.formatdate(calendar.timegm(stamp.timetuple()))
        response['Last-Modified'] = val
        response['Cache-Control'] = 'private, must-revalidate, max-age=0'
        return response

