import sys
import random

from quixote import get_publisher, get_response, redirect, get_request
from quixote.directory import Directory
from quixote.errors import TraversalError

import admin
import liberty
import saml2
import httplib
import urllib

import errors
import logger
import misc
import template
import emails

from users import User
from hosts import Host
from form import *

class LibertySite(Directory):

    _q_exports = ['', 'login', 'logout', 'admin_token', 'admin_new_user', 'token', 'liberty']
    
    liberty = liberty.Liberty()

    def __init__(self, component):
        self.name = component

    def _q_index (self):
        raise errors.TraversalError()

    def login [html] (self):
        logger.info('login')
        host = Host.get_host_from_url()
        if host is None:
            return template.error_page(_('SSO support is not yet configured'))
        idps = host.idps

        if len(idps) == 0:
            return template.error_page(_('SSO support is not yet configured'))

        if len(idps) == 1:
            # if there is only one visible IdP, perform login automatically on
            # this one.
            server = misc.get_lasso_server('liberty')
            if server is None:
                return template.error_page(_('SSO support is not yet configured'))
            for x in server.providerIds:
                key_provider_id = x.replace(str('://'), str('-')).replace(str('/'), str('-'))
                return self.liberty.perform_login(x)

            server = misc.get_lasso_server('saml2')
            for x in server.providerIds:
                key_provider_id = x.replace(str('://'), str('-')).replace(str('/'), str('-'))
                return self.saml.perform_login(x)

        return template.error_page("Can't use several Identity Providers for one Service Provider at the moment")

        form = Form(enctype='multipart/form-data')
        options = []
        # XXX: use intro cookie to get preferred value
        value = None
        providers = {}
        for kidp, idp in misc.cfg.get('idp', {}).items():
            if idp.get('hide'):
                continue
            p = lasso.Provider(lasso.PROVIDER_ROLE_IDP,
                    misc.get_abs_path(idp['metadata']),
                    misc.get_abs_path(idp['publickey']), None)
            providers[p.providerId] = p

        include_protocol = True
        if len([x for x in providers.values() if 
                x.getProtocolConformance() == lasso.PROTOCOL_SAML_2_0]) in (0, len(providers)):
            include_protocol = False

        for p in providers.values():
            label = misc.get_provider_label(p)
            if include_protocol:
                if p.getProtocolConformance() == lasso.PROTOCOL_SAML_2_0:
                    label = '%s (SAML 2.0)' % label
                else:
                    label = '%s (Liberty ID-FF 1.2)' % label
            options.append((p.providerId, label))
            if not value:
                value = p.providerId
        form.add(RadiobuttonsWidget, 'idp', value = value, options = options, delim = '<br/>')
        form.add_submit('submit', _('Submit'))

        if form.is_submitted() and not form.has_errors():
            idp = form.get_widget('idp').parse()
            p = providers[form.get_widget('idp').parse()]
            if p.getProtocolConformance() == lasso.PROTOCOL_SAML_2_0:
                return self.saml.perform_login(idp)
            else:
                return self.liberty.perform_login(idp)

        template.html_top(_('Login'))
        '<p>%s</p>' % _('Select the identity provider you want to use.')
        form.render()

    def logout(self):
        logger.info('logout')
        session = get_session()
        if not session:
            return redirect('/')
        # add settings to disable single logout?
        #   (and to set it as none/get/soap?)
        return self.liberty.singleLogout()

    def defederate(self):
        logger.info('defederate')
        session = get_session()
        if not session:
            return redirect('/')
        host = Host.get_host_from_url()
        if host is None:
            return template.error_page(_('SSO support is not yet configured'))
        idps = host.idps

        if len(idps) == 0:
            return template.error_page(_('SSO support is not yet configured'))

        if len(idps) == 1:
            # if there is only one visible IdP, perform login automatically on
            # this one.
            server = misc.get_lasso_server('liberty')
            if server is None:
                # Get a templated page instead
                return template.error_page(_('SSO support is not yet configured'))
            for x in server.providerIds:
                key_provider_id = x.replace(str('://'), str('-')).replace(str('/'), str('-'))
                return self.liberty.defederate(x)

    def admin_token [html] (self):
        request = get_request()
        user_name = request.get_field('id')
    
        form = Form(enctype="multipart/form-data", use_tokens = False)
        form.add_submit("submit", _("Generate"))
        form.add_submit("cancel", _("Cancel"))

        del get_response().breadcrumb

        if not form.is_submitted() or form.has_errors():
            template.html_top(_('Identification Token'))
            '<p>User %s has no token yet</p>' % user_name
            form.render()
        else:
            if request.form.has_key('submit'):
                template.html_top(_('Identification Token'))
                token = '-'.join(['%04d' % random.randint(1, 9999) for x in range(4)])

                # Save token on disk
                if user_name is not None:
                    token_dir = str(os.path.join(misc.get_proxied_site_path(), 'tokens'))
                    if not os.path.isdir(token_dir):
                        os.mkdir(token_dir)
                    token_file_name = str(os.path.join(token_dir, token))
                    if not os.path.isfile(token_file_name):
                        token_file = open(token_file_name, str('w'))
                        token_file.write(user_name)
                        token_file.close()

                "<p>"
                _('Identification Token for %s :') % user_name
                " %s</p>" % token

                form = Form(enctype="multipart/form-data", use_tokens = False)
                form.add_string('email', title = _('Email'))
                form.add_hidden('token', value = token)
                form.add_submit('send', _('Send it by email'))
                form.add_submit('back', _('Back'))
                form.render()
            else:
                if request.form.has_key('send'):
                    token = request.get_field('token')
                    email = request.get_field('email')
                    site_url = '%s://%s/liberty/%s/token?token=%s' \
                        % (request.get_scheme(), request.get_server(), misc.get_proxied_site_name(), token)
                    body = _("""You have been given an identification token.

Your token is %s.

Click here to use it : %s

""") % (token, site_url)
                    emails.email(_('Identification Token'), body, email)
                return redirect(misc.get_site_root_url())


    def admin_new_user(self):
        host = Host.get_host_from_url()
        if host is None or not hasattr(host, 'admin_new_user_url'):
            return

        request = get_request()
        session = get_session()
        
        fields = request.get_fields() 

        # Should test email as well
        if fields['user_id'] == '' or fields['user_nom'] == '':
            redirect(host.admin_new_user_url)

        user_id = fields['user_id']
        user_email = fields['user_email']
        password = '-'.join(['%04d' % random.randint(1, 9999) for x in range(4)])
        fields['user_pwd'] = password

        if self.admin_new_user_post(fields, host.admin_new_user_url) != 302:
            return redirect(host.admin_new_user_url)

        token = '-'.join(['%04d' % random.randint(1, 9999) for x in range(4)])
        
        # Save token on disk
        token_dir = str(os.path.join(misc.get_proxied_site_path(), 'tokens'))
        if not os.path.isdir(token_dir):
            os.mkdir(token_dir)
        token_file_name = str(os.path.join(token_dir, token))
        if not os.path.isfile(token_file_name):
            token_file = open(token_file_name, str('w'))
            token_file.write(user_id + '\n')
            token_file.write(password + '\n')
            if user_email != '':
                token_file.write(user_email)
            token_file.close()
            
        # Send it by email
        site_url = '%s://%s/liberty/%s/token?token=%s' \
                    % (request.get_scheme(), request.get_server(), misc.get_proxied_site_name(), token)
        body = _("""You have been given an identification token.

Your token is %s.

Click here to use it : %s

""") % (token, site_url)
        emails.email(_('Identification Token'), body, user_email)            

        return redirect(host.admin_new_user_return_url)

    def admin_new_user_post(self, fields, url):
        if url.startswith('http://'):
            host, query = urllib.splithost(url[5:])
            conn = httplib.HTTPConnection(host)
        else:
            host, query = urllib.splithost(url[6:])
            conn = httplib.HTTPSConnection(host)
        body = urllib.urlencode(fields)
        conn.request('POST', query, body, {'Content-Type': 'application/x-www-form-urlencoded', 'Cookie': 'dc_admin=a%3A3%3A%7Bs%3A7%3A%22user_id%22%3Bs%3A7%3A%22heretik%22%3Bs%3A8%3A%22user_pwd%22%3Bs%3A32%3A%22cc414bfc9c00475b59c87595299ff31d%22%3Bs%3A8%3A%22remember%22%3Bb%3A0%3B%7D'})
        response = conn.getresponse()
        conn.close()
        return response.status

    def token [html] (self):
        #if not get_request().user:
        #    raise errors.AccessUnauthorizedError()

        del get_response().breadcrumb

        session = get_session()
        token = get_request().get_field('token')
        get_session().token = token
        
        redirect('/liberty/%s/login' % misc.get_proxied_site_name())

    def get_user_cookie(self, user_id):
        host = Host.get_host_from_url()
        if host is None:
            return redirect('/')
        return_url = host.get_return_url()
        user_dir = misc.get_abs_path(os.path.join(misc.get_proxied_site_path(), 'users'))
        for user_file_name in os.listdir(user_dir):
            user_file = open(os.path.join(user_dir, user_file_name), 'r')
            data = user_file.read().split()
            user_file.close()
            # Return cookie
            if data[0] == user_id:
                return data[2]
        return None
