# -*- coding: iso-8859-1 -*-
u"""
                             _vi
                             <Ii           _aa.
                             :I>          aZ2^
                              v`        .we^
        . .         ..        +        _2~
  ._auqXZZX   ._auqXZZZ`    ...._...   ~          ._|ii~
.aXZZY""^~~  vX#Z?""~~~._=ii|+++++++ii=,       _=|+~-
JXXX`       )XXX'    _|i+~   .__..._. +l=    -~-
SXXo        )XZX:   |i>  ._%i>~~+|ii| .i|   ._s_ass,,.    ._a%ssssssss
-SXZ6,,.    )XZX:  =l>  _li+~`   iii| .ii _uZZXX??YZ#Za, uXUX*?!!!!!!!
  "!XZ#ZZZZZXZXZ`  <i>  =i:     .|ii| .l|.dZXr      4XXo.XXXs,.
      -~^^^^^^^`   -||,  +i|=.   |ii| :i>:ZXZ(      ]XZX.-"SXZUZUXoa,,
                     +l|,  ~~|++|++i|||+~:ZXZ(      ]ZZX     ---~"?Z#m
            .__;=-     ~+l|=____.___,    :ZXZ(      ]ZXX_________auXX2
       ._||>+~-        .   -~+~++~~~-    :ZXZ(      ]ZXZZ#######UX*!"
       -+--          .>`      _
                   .<}`       3;
                 .<l>        .Zc
                .ii^         )Xo
                             ]XX

    MoinMoin - Formulaire d'inscription

    Un formulaire de préinscription au Crans

    Copyright 2009 Antoine Durand-Gasselin <adg@crans.org>

    Licence: GPLv3
"""

import os, re, locale, base64, sys, unicodedata, random
from commands import getstatusoutput as gso
sys.path.append("/usr/scripts/gestion")
from iptools import AddrInNet
from MoinMoin import wikiutil
from MoinMoin.widget import html
from MoinMoin.Page import Page
from MoinMoin.PageEditor import PageEditor
from MoinMoin.formatter.text_html import Formatter

PREINSCRIPTION_DIR = '/var/local/wiki/data/preinscription/'
ETABLISSEMENTS = [ ("ENS", u"ENS Cachan"),
                   ("IUT Cachan", u"IUT Cachan"),
                   ("Maximilien Sorre", u"Maximilien Sorre"),
                   ("Gustave Eiffel", u"Gustave Eiffel"),
                   ("P1", u"Paris I"),
                   ("P2", u"Paris II"),
                   ("P3", u"Paris III"),
                   ("P4", u"Paris IV"),
                   ("P5", u"Paris V"),
                   ("P6", u"Paris VI"),
                   ("P7", u"Paris VII"),
                   ("P8", u"Paris VIII"),
                   ("P9", u"Paris IX"),
                   ("P10", u"Paris X"),
                   ("P11", u"Paris XI"),
                   ("P12", u"Paris XII"),
                   ("P13", u"Paris XIII"),
                   ("IUFM", u"IUFM"),
                   ("other", u"Autre...") ]

LABOS = [ ("CMLA", u"CMLA - Centre de Mathématiques et de Leurs Applications"),
          ("GAPP", u"GAPP - Groupe d'Analyse des Politiques Publiques"),
          ("IDHE", u"IDHE - Institutions et Dynamiques Historiques de l'Economie"),
          ("LBPA", u"LBPA - Laboratoire de Biotechnologies et Pharmacologie génétique Appliquées"),
          ("LMT", u"LMT - Laboratoire de Mécanique et Technologie"),
          ("LPQM", u"LPQM - Laboratoire de Photonique Quantique et Moléculaire"),
          ("LSV", u"LSV - Laboratoire de Spécification et Vérification"),
          ("LURPA", u"LURPA - Laboratoire Universitaire de Recherche en Production Automatisée"),
          ("PPSM", u"PPSM - Laboratoire de Photophysique et Photochimie Supramoléculaires et Macromoléculaires"),
          ("SATIE", u"SATIE - Systèmes et Applications des Technologies de l\'Information et de l'Energie"),
          ("STEF", u"STEF - Sciences Techniques Education Formation") ]

ANNEE_ENS = [ ("1", u"1A (licence)"), ("2", u"2A (master 1)"),
              ("3", u"3A (agrégation)"), ("4", u"4A (master 2)"),
              ("5", u"5A (thèse 1)"), ("6", u"6A (thèse 2)"),
              ("7", u"7A (thèse 3)"), ("8", u"8A+") ]

ANNEE_ETUDE = [  ("-2", u"Seconde"), ("-1", u"Première"), ("0", u"Terminale"),
                 ("1", u"BAC+1 (L1)"), ("2", u"BAC+2 (L2)"), ("3", u"BAC+3 (L3)"),
                 ("4", u"BAC+4 (M1)"), ("5", u"BAC+5 (M2)"), ("6", u"BAC+6 (thèse 1)"),
                 ("7", u"BAC+7 (thèse 2)"), ("8", u"BAC+8 (thèse 3)"), ("9", "Autre") ]

SECTIONS_ENS = [ ("A0", u"A0 - Informatique"),
                 ("A1", u"A1 - Mathématiques"),
                 ("A2", u"A2 - Physique fondamentale"),
                 ("A'2", u"A'2 - Physique appliquée"),
                 ("A''2", u"A''2 - Chimie"),
                 ("A3", u"A3 - Biochimie"),
                 ("EEA", u"EEA"),
                 ("B123", u"B123 - Technologie mécanique"),
                 ("B1", u"B1 - Mécanique"),
                 ("B2", u"B2 - Génie civil"),
                 ("B3", u"B3 - Génie mécanique"),
                 ("B1", u"B1 - Mécanique"),
                 ("B2", u"B2 - Génie civil"),
                 ("B3", u"B3 - Génie mécanique"),
                 ("B4", u"B4 - Génie électrique"),
                 ("C", u"C - Art et création industrielle"),
                 ("D2", u"D2 - Economie gestion"),
                 ("D3", u"D3 - Sciences sociales"),
                 ("E", u"E - Anglais") ]

class FormElement():
    """Une classe pour représenter un élément d'un formulaire"""
    def __init__(self, wikitxt):
        self.content = wikitxt

    def render(self, request, parser):
        return wikiutil.renderText(request, parser, self.content)

class Field():
    """Une classe pour représenter les champs

    Attention, elle ne permet que de rendre les champs en html, et
    d'effectuer des tests unitaires"""

    error_txt=''
    error_msg=''
    error_field=''

    def __init__(self, id, prompt, default = "", input_type = "text",
                 check=None, CLASS="formulaire_field"):
        self.id = id
        self.prompt = html.Text(prompt)
        self.default = default
        self.input_type = input_type
        self.CLASS= CLASS
        if check != None: self.check_hook = check
        else: self.check_hook = (lambda x: True)

    def fill(self, post):
        self.input = post.get(self.id, [''])[0]

    def check(self):
        self.error_txt= '' # Devrait pourtant être déjà vide

        self.default = self.input
        ok = self.check_hook(self)

        if ok:
            self.content = self.__dict__.get('content', self.input) # des fois qu'on ait oublié de le faire
            if self.content != self.default and self.default == self.input:
                self.default = self.content

        if not self.error_txt and not ok:
            self.error_txt = u'Valeur %s incorrecte pour le champ %s.' % (self.input, self.id)
        return ok

    def render(self, request, parser):
        champ = html.UL(CLASS=self.CLASS)
        champ.append(html.LI(CLASS="formulaire_id").append(self.prompt))

        input = html.INPUT(type=self.input_type,name=self.id,value=self.default)
        champ.append(html.LI(CLASS="formulaire_input").append(input))

        if self.error_txt:
            error = wikiutil.renderText(request, parser, self.error_txt)
            champ.append(html.LI(CLASS="formulaire_error").append(error))

        if self.error_msg:
            request.add_msg(self.error_msg)
        return champ

class MenuField(Field):
    def __init__(self, id, prompt, fields):
        Field.__init__(self, id, prompt)
        self.fields = fields

    def render(self, request, parser):
        champ = html.UL(CLASS="formulaire_field_%s" % self.id)
        champ.append(html.LI(CLASS="formulaire_id").append(self.prompt))
        menu = html.SELECT(NAME=self.id, onchange='TestEtudes()')
        for opt, legend in self.fields:
            menu.append(html.OPTION(VALUE=opt).append(legend))
        champ.append(menu)
        if self.error_txt:
            error = wikiutil.renderText(request, parser, self.error_txt)
            champ.append(html.LI(CLASS="formulaire_error").append(error))

        if self.error_msg:
            request.add_msg(self.error_msg)
        return champ


class PasswordField(Field):
    def fill(self, post):
        self.input = post.get(self.id, [''])[0]
        self.input2 = post.get(self.id+'2',[''])[0]

    def check(self):
        self.error_txt= '' # Devrait pourtant être déjà vide

        self.default = ''
        if self.input == self.input2:
            self.content = self.input
            return True
        else:
            self.error_txt = u'Les deux mots de passe diffèrent'
            return False

    def render(self, request, parser):
        champ = html.UL(CLASS="formulaire_field")
        champ.append(html.LI(CLASS="formulaire_id").append(self.prompt))

        input = html.INPUT(type=self.input_type,onchange="testPassword()", name=self.id)
        champ.append(html.LI(CLASS="formulaire_input").append(input))
        champ.append(html.LI().append('<img name="verdict" />'))

        champ2 = html.UL(CLASS="formulaire_field")
        champ2.append(html.LI(CLASS="formulaire_id").append('Retapez le mot de passe'))

        input = html.INPUT(type=self.input_type, name=self.id+'2')
        champ2.append(html.LI(CLASS="formulaire_input").append(input))

        if self.error_txt:
            error = wikiutil.renderText(request, parser, self.error_txt)
            champ2.append(html.LI(CLASS="formulaire_error").append(error))

        return u'%s\n%s\n' % (champ, champ2)


def is_name(self):
    """Vérifie que le champ input de l'objet passé en argument est un nom valide."""
    analysed_content = unicodedata.normalize('NFKD', self.input)
    try: stripped_content = analysed_content.encode('ASCII', 'ignore')
    except UnicodeEncodeError: stripped_content = '<ugly utf-8>'
    if re.match('[a-z][-a-z _]*', stripped_content.lower()):
        return True
    else:
        self.error_txt = u"""Valeur %s incorrecte pour le champ %s.
Seules les lettres (éventuellement accentuées),
l'espace et le tiret '-' sont acceptés.""" % (self.input, self.id)
        return False


def is_chbre(self):
    if re.match('[abcghijp][0-9]{1,3}[gd]?', self.input.lower()):
        return True
    else:
        self.error_txt = u"""Valeur %s incorrecte pour votre chambre, celle-ci doit être de la forme Bxxx, Bxxxg ou Bxxxd,  avec B la première lettre de votre batiment (P pour le Pavillon des Jardins), xxx le numéro de votre chambre et g ou d si vous êtes dans un T1 bis selon que vous soyiez à gauche ou à droite"""
        return False


def is_phonenumber(self):
    chiffres = self.input.replace('.', '')
    if re.match('(0|\+[0-9][0-9])[0-9]{9}', chiffres):
        return True
    else:
        self.content = ''
        return True

def is_dns(self):
    dns = self.input.lower()
    if re.match('[a-z][-a-z0-9_]*', dns):
        return True
    else:
        return False

def get_mac(ip):
    "Récupère la mac"
    mac= 'XX' + ':XX'*5
    if AddrInNet(ip, '138.231.136.0/21'):
        status, mac = gso("/usr/sbin/arp %s | perl -nle '{print $& if /00(:[0-9a-f]{2}){5}/}'" % ip) # gruik, gruik, grUUIIIk !
        mac= mac.strip()
    return mac

def is_valid_mac(self):
    mac = self.input.lower()
    if re.search("00((:|-|)[a-f0-9][a-f0-9]){5}", mac):
        return True
    else:
        self.default = get_mac(self.ip)
        return False

class Formulaire():
    """Une classe qui représente un formulaire.

    Elle contient un champs ``champs'', qui contient une liste de
    Fields, qui est la liste des champs qui doivent être demandés (dans
    le bon ordre l'ordre).
"""
    def __init__(self, champs):
        self.champs = champs

    def render(self, request, parser):
        url = request.page.url(request)
        ret = html.FORM(action=url, NAME="preinscription")
        ret.append(html.INPUT(type='hidden', name='action', value='inscription'))

        f = html.UL(CLASS="formulaire_preinscription")

        for field in self.champs:
            champ = field.render(request, parser)
            f.append(html.LI().append(champ))

        ret.append(f)
        ret.append(html.HR(CLASS= "invisiblesep"))
        ret.append(html.INPUT(type="submit", name="inscrire", value=u"Me préinscrire"))

        return unicode(ret)


    def check(self, post):
        u"""Vérifie les paramètres postés par l'utilisateur.

    Vérifie que toutes les entrées du formulaire (formulaire.fields)
    sont présentes et bien valides, (en appelant check() pour chaque
    champs).
    """
        errors = []
        for field in self.champs:
            field.fill(post)
        for field in self.champs:
            if not field.check():
                errors.append(field.id)

        # est-ce que les test unitaires passent ?
        return errors



def _create_inscription_form(request):
    """Renvoie les champs du formulaire inscription pour créer un Formulaire."""
    ip = request.remote_addr

    mac_field = Field("mac", u"Adresse physique de votre carte réseau", check=is_valid_mac, default=get_mac(ip))
    mac_field.ip = ip


    return [
        # informations personnelles
        Field("nom", "Nom", check=is_name),
        Field("prenom", u"Prénom", check=is_name),
        Field("chbre", u"Chambre", check=is_chbre),
        MenuField('etablissement', u"Établissement d'études", ETABLISSEMENTS),
        Field("etablissement_autre", u"Précisez votre établissement d'études",
              CLASS='formulaire_field_etablissement_autre'),
        MenuField('annee_ens', u"Année scolaire à l'ENS", ANNEE_ENS),
        MenuField('annee', u"Choisissez votre année scolaire", ANNEE_ETUDE),
        MenuField('section_ens', u"Section", SECTIONS_ENS),
        MenuField('labo', u"Laboratoire", LABOS),
        Field("section", u"Précisez votre section", CLASS="formulaire_field_section"),
        Field("tel", u"Numéro de téléphone", check=is_phonenumber),

        # compte crans
        PasswordField("pass", u"Mot de passe", input_type='password'),

        # Votre machine
        Field("dns", u"Nom de votre ordinateur", check=is_dns),
        mac_field
        ]

def _perform_inscription(request, formulaire):
    rand=random.Random()
    rand.seed()
    for i in range(1000):
        numero = rand.randint(100000, 999999)
        if not os.path.exists( os.path.join( PREINSCRIPTION_DIR, str( numero ) ) ):
            break

    else: # JAMAIS JAMAIS exécuté
        request.theme.add_msg(u"Erreur côté serveur, merci de réessayer", "error")
        return request.page.send_page()

    print "ok"
    fichier = open (os.path.join( PREINSCRIPTION_DIR, str( numero ) ), 'w')
    for field in formulaire.champs:
#        if type(field) == Field:
            content = field.content.split('\n')[0]
            fichier.write(u'%s: %s\n' % (field.id, content))
    fichier.close()
    print "ok 2"
    # tests of redundancy
    request.theme.add_msg(u"Votre préinscription est réalisée, elle a le numero %d" % numero)
    return Page(request, "VieCrans/PreinscriptionOk").send_page()


#     form = {}
#     for field in formulaire.champs:
#         if type(field) == Field:
#             form[field.id] = field.content
#     adh = {}
#     adh['nom'] = form['nom']
#     adh['prenom'] = form['prenom']
#     adh['chbre'] = form['chbre']
#     adh['tel'] = form['tel']
#     if form['etablissement'] == 'ENS':
#         if int(form['annee_ens']) > 4:
#             adh['etudes'] = "ENS\n%(annee_ens)s\n%(labo)s" % form
#         else:
#             adh['etudes'] = "ENS\n%(annee_ens)s\n%(section_ens)s" % form
#     else:
#         adh['etudes'] = "%(etablissement)s\n%(annee)s\n%(secion)s" %form
# 
#     machine = {}
#     machine['macAdress'] = form['mac']
#     machine['host'] = form['dns']

def execute(pagename, request):
    request.page = Page(request, pagename)
    request.formatter.setPage(request.page)
    request.loadTheme('crans-www')
    formulaire = Formulaire(_create_inscription_form(request))
    post = request.form
    parser = wikiutil.searchAndImportPlugin(request.cfg, "parser", request.page.pi['format'])
    if not request.dicts.has_member("GroupeAdmin", request.user.name) and not request.user == 'AntoineDurandGasselin':
        request.theme.add_msg(u"Non, car tu es méchant", "error")
        return(request.page.send_page())

    if post.has_key('inscrire'):
        if formulaire.check(post) == []:
            return(_perform_inscription(request, formulaire))
        else:
            request.theme.add_msg(u'des erreurs', 'error')

    request.emit_http_headers()
    request.theme.send_title(u"Formulaire de préinscription", pagename=pagename, html_head='<script type="text/javascript" src="/wiki/crans-www/js/passwd.js"></script>')
    request.write(request.formatter.startContent("content"))

    form = formulaire.render(request, parser)
    # THIS IS A BIG HACK. IT NEEDS TO BE CLEANED UP
    request.write(form)
    request.write(request.formatter.endContent())
    request.theme.send_footer(pagename)
    request.theme.send_closing_html()

