from quixote import get_request, get_response, get_session
from quixote.http_request import parse_header
from quixote.directory import Directory
from qommon import get_cfg, get_logger
import qommon.soap as soap
import qommon.storage
import lasso
import random

def build_uuid():
    return ''.join([random.choice(string.lowercase) for x in range(10)])

def soap_endpoint(method):
    def f(*args, **kwargs):
        try:
            return method(*args, **kwargs)
        except Exception, e:
            get_logger().error('Exception in method %r: %s; returning a SOAP error' % (method, e))
            fault = lasso.SoapFault.newFull('Internal Server Error', str(e))
            body = lasso.SoapBody()
            body.any = [ fault ]
            envelope = lasso.SoapEnvelope(body)
            return envelope.exportToXml()
    return f

class SessionIndex(qommon.storage.StorableObject):
    _names = 'session-index'
    def __init__(self, id):
        qommon.storage.StorableObject.__init__(self, id)
        self.session_id = get_session().id

class LassoDirectory(Directory):
    def _q_traverse(self, path):
        response = get_response()
        # Set caching directives
        response.set_header('Cache', 'no-cache, no-store')
        response.set_header('Pragma', 'no-cache')
        return Directory._q_traverse(self, path)

    def get_soap_message(self):
        '''Interpret received request as a SOAP message, and return its
        content.
        '''
        request = get_request()
        if request.get_method() != 'POST':
            raise soap.SOAPException('SOAP Endpoint got a message with a method different from POST (%s)' % request.get_method())
        ctype = request.environ.get('CONTENT_TYPE')
        if not ctype:
            raise soap.SOAPException('SOAP Endpoint got a message without content-type')
        ctype, ctype_params = parse_header(ctype)
        if ctype != 'text/xml':
            raise soap.SOAPException('SOAP Endpoint got a message with wrong content-type (%s)' % ctype)

        length = int(request.environ.get('CONTENT_LENGTH'))
        return request.stdin.read(length)

    def trace(self, what=None,where=None):
        '''If trace is activated, log the passed object'''
        pass

    def soap_call(self, url, body):
        return soap.soapCall(url, body)

    def returnSoap(self, profile):
        response = get_response()
        response.set_content_type('text/xml')
        return profile.msgBody

    def postTo(self, url, body, fieldname, relay_state = None, title = ''):
        if relay_state is not None:
            relay_state = \
                '<input type="hidden" name="RelayState" value="%s" />' \
                    % relay_state
        else:
            relay_state = ''

        return """<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
 <head>
  <title>%(title)s</title>
 </head>
 <body onload="document.forms[0].submit()">
  <h1>%(title)s</h1>
  <form action="%(url)s" method="post">
   <p>%(hint)s</p>
   <p>%(disclaimer)s</p>
   <input type="hidden" name="%(fieldname)s" value="%(body)s" />
   %(relay_state)s
   <div class="buttons-bar">
    <input type="submit" name="sendButton" value="%(send)s" />
   </div>
  </form>
 </body>
</html>
""" % { 'fieldname': fieldname,
        'body': body,
        'url': url,
        'relay_state': relay_state,
        'hint': _('You should be automaticaly redirected to the identity provider.'),
        'disclaimer': _('If this page is still visible after a few seconds, \
press the <em>%(send)s</em> button below.') % { 'send': _('Send') },
        'send': _('Send'),
        'title': _(title)}

    def add_attributes(self, provider_key, assertion, identity,
            add_attribute_values):
        attributes = getattr(identity, 'attributes', {})
        exported_attributes = get_cfg('providers').\
                get(provider_key, {}).get('exported_attributes', '') or '';
        # Export a projection or all attributes
        exported_attributes = exported_attributes.split() or attributes.keys()
        # Copy custom user attributes into the assertion attributeStatement
        for key in exported_attributes:
            if key in attributes:
                value = attributes[key]
                if isinstance(value, list):
                    values = value
                else:
                    values = [ value ]
                add_attribute_values(assertion, key, values)
