import sys

import logging
from cStringIO import StringIO
logStream = StringIO()
FORMAT = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
logging.basicConfig(format=FORMAT, stream = logStream)

from google.appengine.ext.webapp import Request
from google.appengine.ext.webapp import Response
from traceback import format_exception

from google.appengine.ext import webapp

from orangescape.config.routing import make_map
from orangescape.model.server.Context import getApplication
from orangescape.model.server.azure.AzureSession import PrimarySession
from orangescape.gateway.wsgi import BaseWSGIApplication

map = make_map()

class WSGIApplication(BaseWSGIApplication):
    """Wraps a set of webapp RequestHandlers in a WSGI-compatible application.
    This is based on webapp's WSGIApplication by Google, but uses Routes library
    (http://routes.groovie.org/) to match url's.
    """
    def __init__(self, mapper, debug = True):
        """Initializes this application with the given URL mapping.
        Args:
          mapper: a routes.mapper.Mapper instance
          debug: if true, we send Python stack traces to the browser on errors
        """
        self.mapper = mapper
        self.__debug = debug

    def isAdminAccess(self, request, session):
        accessKeyName = 'AccessKey'
        accessKey = request.get(accessKeyName)
        id = request.get('userid')
        if accessKey and id:
            logging.info('Checking admin access')
            metadata = session.getApplication().getSheetMetadata('User')
            logging.info('AccessKey given %s'%(accessKey))
            if metadata.getPublicCellMetadataDict().has_key(accessKeyName):
                accessKeyCell = metadata.getPublicCellMetadata(accessKeyName)
                logging.info('AccessKey cell exists in model %s. Checking instance %s'%(metadata.getSheetName(), id))
                instance = session.getIfExists(id, metadata)
                if instance and instance.getValue(accessKeyName)==accessKey:
                    logging.info('AccessKey in instance %s'%(instance.getValue(accessKeyName)))
                    return id
        return False

    def clearUnwantedArgs(self,controller, kargs):
        if 'section' in kargs:
            del kargs['section']
        for key in kargs:
            if key.__contains__("___"):
                del kargs[key]
                break;

    def __call__(self, environ, start_response):
        """Called by WSGI when a request comes in."""
        request = Request(environ)
        response = Response()
        WSGIApplication.active_instance = self

        #initialize the command factory here
        session = PrimarySession(getApplication())
        logging.info('request.path %s'%(request.path))
        logging.info('request.path_url %s'%(request.path_url))
        controller, action, kargs = self.initializeCommandFactory(request, response, environ, session, request.path)
        if controller and action:
            #do authentication
            isAuthenticated = False
            if 'section' in kargs:
                if kargs['section'] == 'open':
                    isAuthenticated = True
                if kargs['section'] == 'admin' and self.isAdminAccess(request, session):
                    isAuthenticated = True
                    controller.setUserId('guest')
                del kargs['section']
            if not isAuthenticated:
                #perform authentication
                from orangescape.model.server.util.AuthUtil import authenticate
                userid = authenticate(controller)
                if userid:
                    isAuthenticated = True
                    controller.setUserId(userid)
            try:
                # Execute the requested action, passing the route dictionary as
                # named parameters.
                if isAuthenticated:
                    self.clearUnwantedArgs(controller, kargs)
                    getattr(controller, action)(**kargs)
            except :
                e = sys.exc_info()[1]
                logging.info('Error.....')
                for line in StackTraceFromCurrentException():
                    logging.info(formatLine(line))
                logging.info(e.__class__.__name__ + ": " + str(e))

                controller.handle_exception(e, self.__debug)
                errMsg="%s:%s"%(type(e).__name__,e)
                response.set_status(500,errMsg)
                response.headers['ErrorMessage'] = errMsg
                response.wsgi_write(start_response)
                #TODO Remove this code and log the message in blob
                return [logStream.getvalue()]
            response.wsgi_write(start_response)
            return ['']
        else:
            response.set_status(404)

def formatLine(lineInfo):
    fileName, lineNo, name = lineInfo
    return '\nFile "%s", line %s, in %s' % (fileName, lineNo, name)

def StackTraceFromCurrentException():
    traceback = sys.exc_info()[2]
    stackTrace = []
    while traceback is not None:
        frame = traceback.tb_frame
        lineno = traceback.tb_lineno
        code = frame.f_code
        filename = code.co_filename
        name = code.co_name
        stackTrace.append((filename, lineno, name))
        traceback = traceback.tb_next
    sys.exc_clear()
    return stackTrace

def application(environ, start_response):
    try:
        logging.info('environ :%s'%(environ))
        app = WSGIApplication(map, debug = True)
        result = app(environ, start_response)
        return result
    except Exception, e:
        logging.info('Error.....')
        for line in StackTraceFromCurrentException():
            logging.info(formatLine(line))
        logging.info(e.__class__.__name__ + ": " + str(e))
        return [logStream.getvalue()]
