# -*- coding: utf8 -*-
from pyramid.httpexceptions import HTTPFound, HTTPNotFound, HTTPForbidden
from pyramid.httpexceptions import HTTPBadRequest, HTTPUnauthorized
from pyramid.renderers import render_to_response
from pyramid.view import notfound_view_config, forbidden_view_config
from pyramid.view import view_config
from pyramid.response import Response
from mako.template import Template
from pyramid_mailer.message import Message
from .upload import IMAGEPATH, MediaPath
# Import Web Forms
from .forms import *
# Database access imports
from .models import *
from .helpers import Orga_helpers
from sqlalchemy import func, or_, text, and_
from sqlalchemy.orm import aliased
from os import path, makedirs, listdir
# Usefull tools
from slugify import slugify
from icalendar import Calendar
from pytz import timezone
from icalendar import Event as Evt
from pyramid_mailer.message import Message
# Then, standard libs
import csv
import cStringIO as StringIO
import webhelpers.paginate as paginate
import unicodedata
import datetime
import re
import shutil
import glob
from jm2l.const import CurrentYear

## =-=- Here, We keep some usefull function -=-=
def remove_accents(input_str):
    """ This function is intended to remove all accent from input unicode string """
    nkfd_form = unicodedata.normalize('NFKD', input_str)
    only_ascii = nkfd_form.encode('ASCII', 'ignore')
    return only_ascii

def embeed_video(mime_type, link):
    Container = "<video controls='controls' preload='metadata' style='width:60%'>"
    Container += "<source type='%s' " % mime_type
    Container += "src='%s' />" % link
    Container += "</video>"
    return Container


@view_config(route_name='Live', renderer="jm2l:templates/Live.mako")
def Live(request):
    year = int(request.matchdict.get('year', CurrentYear))
    tz = timezone('Europe/Paris')
    curtime = datetime.datetime.now().replace(tzinfo=tz, day=28) #, hour=10, minute=00 )
    Events = DBSession.query(Event)\
                .filter(Event.for_year == year)\
                .filter(Event.event_type != 'Stand')\
                .filter(and_(Event.start_time <= curtime, Event.end_time >= curtime) )\
                .order_by(Event.start_time)
    return {'year': year, "DisplayYear": year, 'events':Events, "logged_in":request.authenticated_userid }

## =-=- Here, We handle ICal requests -=-=
@view_config(route_name='progr_iCal', renderer="string")
def ICal_Progamme_Request(request):
    year = int(request.matchdict.get('year', CurrentYear))
    # Initialization
    # Compute days used by all events matching the specified input year
    Events = DBSession.query(Event)\
                .filter(Event.for_year == year)\
                .filter(Event.event_type != 'Stand')\
                .order_by(Event.start_time)
    
    cal = Calendar()
    cal.add('prodid', '-//Programme %d//jm2l.linux-azur.org//' % year)
    cal.add('version', '2.0')
    tz = timezone('Europe/Paris')
    for ev in Events:
        if ev.event_type:
            event = Evt()
            event['uid'] = "%d/%d" % ( year, ev.uid )
            event.add('summary', ev.name )
            event.add('dtstart', ev.start_time.replace(tzinfo=tz) )
            event.add('dtend', ev.end_time.replace(tzinfo=tz) )
            event.add('created', ev.last_change.replace(tzinfo=tz) )
            event.add('description', "http://www.linux-azur.org/event/%s/%s" % (ev.for_year, ev.slug)  )
            event.add('url', "http://www.linux-azur.org/event/%s/%s" % (ev.for_year, ev.slug) )
            event.add('priority', 5)
            cal.add_component(event)
    request.response.content_type = "text/calendar"
    return cal.to_ical()

## =-=- Here, We handle ICal requests -=-=
@view_config(route_name='progr_dyn_iCal', renderer="string")
def ICal_Progamme_Dyn_Request(request):
    year = int(request.matchdict.get('year', CurrentYear))
    # Initialization
    # Compute days used by all events matching the specified input year
    Events = DBSession.query(Event)\
                .filter(Event.for_year == year)\
                .filter(Event.event_type != 'Stand')\
                .order_by(Event.start_time)

    cal = Calendar()
    cal.add('prodid', '-//Programme %d//jm2l.linux-azur.org//' % year)
    cal.add('version', '2.0')
    today = datetime.datetime.now()
    tz = timezone('Europe/Paris')
    
    event = Evt()
    event['uid'] = "%d/%d" % ( year, 100 )
    event.add('summary', "Les stands JM2L %s" % year )
    event.add('dtstart', datetime.datetime.now().replace(tzinfo=tz, hour=10, minute=00 ) )
    event.add('dtend', datetime.datetime.now().replace(tzinfo=tz, hour=18, minute=00 ) )
    event.add('created', datetime.datetime.now().replace(tzinfo=tz, hour=10, minute=00 ) )
    event.add('description', "https://www.youtube.com/watch?v=91X65eEKxvU&t=6s" )
    event.add('location', "http://jm2l.linux-azur.org/img/325.gif" )
    event.add('url', "http://jm2l.linux-azur.org/%s/le-programme" % CurrentYear)
    event.add('priority', 5)
    cal.add_component(event)

    TabCorr = {
        135:"Koneko",
        131:"cam-jm2l-a",
        132:"cam-jm2l-b",
        115:"cam-jm2l-e",
        114:"cam-jm2l-f",
        116:"cam-jm2l-g",
        139:"cam-jm2l-y" 
    }
    
    for i, ev in enumerate(Events):
        if ev.event_type:
            event = Evt()
            event['uid'] = "%d/%d" % ( year, ev.uid )
            event.add('summary', ev.name )
            event.add('dtstart', ev.start_time.replace(tzinfo=tz, day=today.day, month = today.month, hour=(ev.start_time.hour)%24 ) )
            event.add('dtend', ev.end_time.replace(tzinfo=tz, day=today.day, month = today.month, hour=(ev.end_time.hour)%24 ) )
            event.add('created', ev.last_change.replace(tzinfo=tz) )
            event.add('description', "http://jm2l.linux-azur.org:8080/%s.webm" % TabCorr.get(ev.Salle.phy_salle_id, ev.Salle.phy_salle_id) )
            event.add('location', "http://jm2l.linux-azur.org/img/%d.gif" % ev.Salle.phy_salle_id )
            event.add('url', "http://www.linux-azur.org/event/%s/%s" % (ev.for_year, ev.slug) )
            event.add('priority', 5)
            cal.add_component(event)
    request.response.content_type = "text/calendar"
    return cal.to_ical()


## =-=- Here, We handle Json requests -=-= 
@view_config(route_name='users_json', renderer="json")
def JSON_User_Request(request):
    """ Build a JSON answer with active users and pagination handling """
    # Check arguments consitency 
    pageSize = request.params.get('pageSize',"8")
    current_page = request.params.get('pageNum',"1")
    UserQuery = request.params.get('searchTerm', u"")
    # Don't answer to users that aren't logged    
    if not request.user:
        raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
    # Check consistancy of parameters        
    if pageSize.isdigit() and current_page.isdigit():
        current_page = int(current_page)
        pageSize = int(pageSize)
    else:
        return HTTPBadRequest('pageSize and pageNum accept only digits.')    
    # Query database
    Users = DBSession.query(User.uid, User.nom, User.prenom)\
        .filter(User.slug.contains( remove_accents(UserQuery) ))
    page_url = paginate.PageURL_WebOb(request)
    records = paginate.Page(Users, current_page, url=page_url, items_per_page=pageSize)
    ListMatchUser = map( lambda u:{"id": u.uid, "text":"%s %s" % ( u.prenom, u.nom )}, records )
    return { "Results": ListMatchUser, "Total":records.item_count,
            "logged_in":request.authenticated_userid }

@view_config(route_name='tiers_json', renderer="json")
def JSON_Tiers_Request(request):
    """ Build a JSON answer with active users and pagination handling """
    # Check arguments consitency 
    pageSize = request.params.get('pageSize',"8")
    current_page = request.params.get('pageNum',"1")
    TiersQuery = request.params.get('searchTerm', u"")
    # Don't answer to users that aren't logged    
    if not request.user:
        raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
    # Check consistancy of parameters        
    if pageSize.isdigit() and current_page.isdigit():
        current_page = int(current_page)
        pageSize = int(pageSize)
    else:
        return HTTPBadRequest('pageSize and pageNum accept only digits.')    
    # Query database
    JTiers = DBSession.query(Tiers.uid, Tiers.name)\
        .filter(Tiers.slug.contains( remove_accents(TiersQuery) ))
    page_url = paginate.PageURL_WebOb(request)
    records = paginate.Page(JTiers, current_page, url=page_url, items_per_page=pageSize)
    ListMatchTiers = map( lambda t:{"id": t.uid, "text": t.name }, records )
    return { "Results": ListMatchTiers, "Total":records.item_count,
            "logged_in":request.authenticated_userid }

@view_config(route_name='progr_json', renderer="json")
def JSON_Progamme_Request(request):
    year = int(request.matchdict.get('year', CurrentYear))
    # Initialization
    DicResult = dict()
    # Query database
    # Compute days used by all events matching the specified input year
    Days = DBSession.query( func.strftime('%d', Event.start_time).label('day') )\
            .filter(Event.for_year == year)\
            .filter(Event.event_type != None)\
            .group_by(func.strftime('%d', Event.start_time)).all()

    for Day in Days:
        Events = DBSession.query(Event)\
                    .filter(Event.for_year == year)\
                    .filter(Event.event_type != 'Stand')\
                    .filter(text("strftime('%d', start_time) = :dow")).params(dow=Day.day)\
                    .order_by(Event.start_time)
                    
        ListEv = []
        for ev in Events:
            if ev.event_type:
                ListEv.append( {
                    "uid":"%d/%d" % ( year, ev.uid ),
                    "desc":ev.name,
                    "startDate":ev.start_time.strftime('%Y-%m-%dT%H:%M:%S+01:00'),
                    "endDate":ev.end_time.strftime('%Y-%m-%dT%H:%M:%S+01:00'),
                    "placeName":ev.Salle and (ev.Salle.name or "unk") ,
                    "status":ev.event_type
                } )
        DicResult[Day.day] = ListEv



    return { 'all':DicResult }

@view_config(route_name='timeline_json', renderer="json")
def JSON_TimeLine_Request(request):
    year = int(request.matchdict.get('year', CurrentYear))
    # Initialization
    DicResult = dict()
    # Query database
    # Compute days used by all events matching the specified input year
    Days = DBSession.query( func.strftime('%d', Event.start_time).label('day') )\
            .filter(Event.for_year == year)\
            .filter(Event.event_type != None)\
            .group_by(func.strftime('%d', Event.start_time)).all()
    ListEv = []
    for Day in Days:
        Events = DBSession.query(Event)\
                    .filter(Event.for_year == year)\
                    .filter(Event.event_type != 'Stand')\
                    .filter(text("strftime('%d', start_time) = :dow")).params(dow=Day.day)\
                    .order_by(Event.start_time)
                    
        #ListEv = []
        for ev in Events:
            if ev.event_type:
                CurMedia = ev.video.first() or ""
                if CurMedia:
                    Container = "<video controls='controls' preload='metadata' style='width:60%'>"
                    Container += "<source type='%s' " % CurMedia.mime_type 
                    Container += "src='%s' />" % CurMedia.get_path
                    Container += "</video>"
                else:
                    Container = ""
                ListEv.append( {
                    #"uid":"%d/%d" % ( year, ev.uid ),
                    "headline":'<a href="/event/%s/%s">%s</a>' % (ev.for_year, ev.slug, ev.name),
                    "startDate":ev.start_time.strftime('%Y,%m,%d,%H,%M'),
                    "endDate":ev.end_time.strftime('%Y,%m,%d,%H,%M'),                
                    "text": ev.Salle and (ev.Salle.name or "unk"),
                    #"text":ev.description[:100],
                    "tags":ev.Salle and (ev.Salle.salle_id or "unk") ,
                    #"status":ev.event_type,
                    "asset": {
                        "media": Container,
                        "credit": ",".join(["%s %s" % (i.prenom, i.nom) for i in ev.intervenants]),
                        "caption":"" }
                } )
    if year==2017:
        DicResult = {
            "lang":"fr",
            "headline":"JM2L 2017",
            "type":"default",
            "startDate":"2017,11,25,10",
            "text":"<i><span class='c1'>10ème Édition</span></i>",
            "asset":
            {
                #"media":"https://www.youtube.com/watch?v=91X65eEKxvU&t=6s",
                "media":embeed_video("video/ogg","http://jm2l.linux-azur.org/resources/2015/Video/jm2l_france3-2015.ogv"),
                "credit":"Reportage France 3",
                "caption":"JM2L 2015"
            }
        }
    elif year==2015:
        DicResult = {
            "lang":"fr",
            "headline":"JM2L 2015",
            "type":"default",
            "startDate":"2015,11,28,10",
            "text":"<i><span class='c1'>9ème Édition</span></i>",
            "asset":
            {
                #"media":"https://www.youtube.com/watch?v=91X65eEKxvU&t=6s",
                "media":embeed_video("video/ogg","http://jm2l.linux-azur.org/resources/2015/Video/jm2l_france3-2015.ogv"),
                "credit":"Reportage France 3",
                "caption":"JM2L 2015"
            }
        }
    elif year==2011:
        DicResult = {
            "lang":"fr",
            "headline":"JM2L 2011",
            "type":"default",
            "startDate":"2011,11,25,10",
            "text":"<i><span class='c1'>6ème Édition</span></i>",
            "asset":
            {
                "media":"https://www.youtube.com/embed/rcaNeXuAEhs",
                "credit":"JM2L",
                "caption":"Reportage FR3"
            },
        }
    elif year==2010:
        DicResult = {
            "lang":"fr",
            "headline":"JM2L 2010",
            "type":"default",
            "text":"<i><span class='c1'>5ème Édition</span></i>",
            "asset":
            {
                "media":embeed_video("video/ogg","http://jm2l.linux-azur.org/resources/2010/Video/reportages/JM2L2010-PleinSudTV.ogv"),
                "credit":"<a href='http://pleinsudtv.com/index.php/casa/affichage-en-vignettes/93-casa-culture/582-les-jm-du-logiciel-libre-2010'>Le reportage Plein-sud TV</a>",
                "caption":"JM2L",
            }
        }
    elif year==2007:
        DicResult = {
            "lang":"fr",
            "headline":"JM2L 2007",
            "type":"default",
            "text":"<i><span class='c1'>2ème Édition</span></i>",
            "asset":
            {
                "media":embeed_video("video/ogg","http://jm2l.linux-azur.org/resources/2007/Video/20071110-linux.ogv"),
                "credit":"<a href='http://pleinsudtv.com/index.php/casa/affichage-en-vignettes/93-casa-culture/245-logiciel-libre-linux-jm2l'>Le reportage Plein-sud TV</a>",
                "caption":"JM2L 2007",
            }
        }
    else:
        DicResult = {
            "lang":"fr",
            "headline":"JM2L %d" % year,
            "type":"default",
            "asset":
            {
                "media":"",
                "credit":"JM2L",
                "caption":""
            }
        }
    DicResult["date"] = ListEv
    return { 'timeline':DicResult }

## =-=- Here, We handle HTTP requests - Public Part -=-=
@view_config(route_name='home', renderer="jm2l:templates/NewIndex.mako")
def index_page(request):
    year = request.matchdict.get('year')
    if year:
        year=int(year[:-1])
        content = DBSession.query(JM2L_Year).filter(JM2L_Year.year_uid==year).first()
        if content:
            content = content.description
        else:
            content = ""
        if 2004<year<=CurrentYear:
            if year==2006:
                return {'year': year, 'content':content, 'edition':u"1<sup>ère</sup>" }
            elif year==2015:
                return {'year': year, 'content':content, 'edition':u"9<sup>ème</sup>" }
            elif year==2017:
                return {'year': year, 'content':content, 'edition':u"10<sup>ème</sup>" }
            else:
                edition = year - 2005
                return {'year': year, 'content':content, 'edition':u"%d<sup>ème</sup>" % edition }
        else:
            raise HTTPNotFound()
    else:
        content = DBSession.query(JM2L_Year).filter(JM2L_Year.year_uid==CurrentYear).first().description
    TargetDir = "jm2l/static/img/%s/Photos" % (year or CurrentYear)
    TargetUrl = "/static/img/%s/Photos/" % (year or CurrentYear)
    if path.isdir(TargetDir):
        ListPhotos =  map(lambda x: TargetUrl + x, listdir(TargetDir))
    else:
        ListPhotos = []
    return {'year': CurrentYear, 'content':content, 'edition':u"10<sup>ème</sup>", 'ListPhotos': ListPhotos}

@view_config(route_name='edit_index', renderer="jm2l:templates/Staff/EditIndex.mako")
def edit_index(request):
    year = int(request.matchdict.get('year', CurrentYear))
    if not request.user.Staff:
        # Don't answer to users that aren't logged
        raise HTTPForbidden(u'Vous n\'avez pas l\'autorité suffisante pour effectuer cette action.')
    content = DBSession.query(JM2L_Year).filter(JM2L_Year.year_uid==year).first()
    form = IndexForm(request.POST, content, meta={'csrf_context': request.session})
    if request.method == 'POST' and form.validate():
        form.populate_obj(content)
        return HTTPFound(location=request.route_url('home', year="%d/" % year))
    MainTab = {'home':'active', "logged_in":request.authenticated_userid,
            'form':form, 'DisplayYear':year}
    return MainTab

@view_config(route_name='programme', renderer="jm2l:templates/Public/Programme.mako")
def programme(request):
    year = int(request.matchdict.get('year'))
    if 2006 > year:
        return HTTPBadRequest('The first JM2L event was in 2006.')
    # Query database about selected Year.
    Events = DBSession.query(Event)\
                .filter(Event.for_year == year)\
                .order_by(Event.start_time)
    Days = DBSession.query(func.strftime('%d-%m-%Y', Event.start_time))\
                .filter(Event.for_year == year)\
                .filter(Event.event_type != None)\
                .group_by(func.strftime('%d', Event.start_time)).all()
    ListDay = []
    for day in Days:
        RefDay = datetime.datetime.strptime(day[0],'%d-%m-%Y')
        ListDay.append( ( RefDay.strftime('%A %d %b %Y'), 
                          RefDay.strftime('%d') ) )
    MainTab = {'programme':'active','DisplayYear':year, \
        'Events':Events, 'Event':Event, 'Days':ListDay, "logged_in":request.authenticated_userid  }
    return MainTab

@view_config(route_name='presse', renderer="jm2l:templates/Public/Presse.mako")
def static_presse(request):
    year = int(request.matchdict.get('year', None))
    content = DBSession.query(JM2L_Year).filter(JM2L_Year.year_uid==year).first()
    MainTab = {'presse':'active', "logged_in":request.authenticated_userid, 'content':content, 'DisplayYear':year}
    return MainTab

@view_config(route_name='edit_presse', renderer="jm2l:templates/Staff/EditPresse.mako")
def edit_presse(request):
    year = int(request.matchdict.get('year', None))
    if request.user is None:
        # Don't answer to users that aren't logged
        raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
    if not request.user.Staff:
        # Don't answer to users that aren't logged
        raise HTTPForbidden(u'Vous n\'avez pas l\'autorité suffisante pour effectuer cette action.')
    content = DBSession.query(JM2L_Year).filter(JM2L_Year.year_uid==year).first()
    form = DossPresse(request.POST, content, meta={'csrf_context': request.session})
    if request.method == 'POST' and form.validate():
        form.populate_obj(content)
    MainTab = {'presse':'active', "logged_in":request.authenticated_userid, 'form':form, 'DisplayYear':year}
    
    return MainTab

@view_config(route_name='plan', renderer="jm2l:templates/Public/Plan.mako")
def static_plan(request):
    session = request.session
    session['year'] = CurrentYear
    MainTab = {'plan':'active', "logged_in":request.authenticated_userid }
    return MainTab

## =-=- Here, We handle HTTP requests - Staff Logged Part -=-=
@view_config(route_name='list_task', renderer='jm2l:templates/Staff/list.mako')
def list_view(request):
    year = int(request.matchdict.get('year', CurrentYear))
    if request.user is None:
        # Don't answer to users that aren't logged
        raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
    if not request.user.Staff:
        # Don't answer to users that aren't logged
        raise HTTPForbidden(u'Vous n\'avez pas l\'autorité suffisante pour effectuer cette action.')
    DicTask = {}
    taskgroup = DBSession.query( TasksArea ).filter( TasksArea.year_uid == year).all()
    for grp in taskgroup:
        tasks = DBSession.query( Tasks )\
            .filter( Tasks.area_uid==grp.uid ) \
            .filter( Tasks.year_uid == year) \
            .order_by(Tasks.closed, Tasks.due_date).all()
        DicTask[grp] = tasks
    return {'tasks': DicTask, 'year':year }


@view_config(route_name='list_expenses',  renderer='jm2l:templates/Staff/compta.mako')
def expenses(request):
    year = int(request.matchdict.get('year', CurrentYear))
    if request.user is None:
        # Don't answer to users that aren't logged
        raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
    if not request.user.Staff:
        # Don't answer to users that aren't logged
        raise HTTPForbidden(u'Vous n\'avez pas l\'autorité suffisante pour effectuer cette action.')

    output = []
    dic_out = {}
    for name in glob.glob('jm2l/upload/images/users/*/RIB/*'):
        tab_path = name.split('/')
        if tab_path[6]=='thumbnails' or tab_path[6].endswith('.type'):
            continue
        if dic_out.get(tab_path[4]) is None:
            dic_out[tab_path[4]] = {}
        if dic_out[tab_path[4]].get('RIB') is None:
            dic_out[tab_path[4]]['RIB'] = {'files':[], 'thumb':[]}
            u = User.by_slug(tab_path[4])
            dic_out[tab_path[4]]['User'] = {
                'uid':u.uid,
                'nom':u.nom,
                'prenom':u.prenom,
                'slug':u.slug
            }
        dic_out[tab_path[4]]['RIB']['files'].append( name )
        dic_out[tab_path[4]]['RIB']['thumb'].append( name + ".jpg" )

    for name in glob.glob('jm2l/upload/images/users/*/Justif/*'):
        tab_path = name.split('/')
        if tab_path[6]=='thumbnails' or tab_path[6].endswith('.type'):
            continue
        if dic_out.get(tab_path[4]) is None:
            dic_out[tab_path[4]] = {}
        if dic_out[tab_path[4]].get('Justif') is None:
            dic_out[tab_path[4]]['Justif'] = {'files':[], 'thumb':[]}
            u = User.by_slug(tab_path[4])
            dic_out[tab_path[4]]['User'] = {
                'uid':u.uid,
                'nom':u.nom,
                'prenom':u.prenom,
                'slug':u.slug
            }
        dic_out[tab_path[4]]['Justif']['files'].append( name )
        dic_out[tab_path[4]]['Justif']['thumb'].append( name + ".jpg" )

    return dict(found=dic_out, year=year )


@view_config(route_name='handle_task', renderer='jm2l:templates/Staff/tasks.mako')
def tasks(request):
    year = int(request.matchdict.get('year', CurrentYear))
    if request.user is None:
        # Don't answer to users that aren't logged
        raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
    if not request.user.Staff:
        # Don't answer to users that aren't logged
        raise HTTPForbidden(u'Vous n\'avez pas l\'autorité suffisante pour effectuer cette action.')
    task_id = request.matchdict.get('task_id')
    # Convert the pole_id GET parameter to int or 0
    if request.params.get('pole_id') and request.params.get('pole_id').isdigit():
        pole_id = int(request.params.get('pole_id'))
    else:
        pole_id = None

    # Get areas from db
    Areas = DBSession.query(TasksArea.uid, TasksArea.name) \
                .filter(TasksArea.year_uid == year) \
                .order_by('name').all()
    # Get users from db
    Users = DBSession.query(User)\
                .filter(User.Staff==1)\
                .order_by('nom').all()

    if task_id:
        TmpTask = Tasks.by_id(int(task_id))
        if not TmpTask:
            raise HTTPNotFound()
        form = EditStaffTasks(request.POST, TmpTask, meta={'csrf_context': request.session})
    else:
        TmpTask = Tasks()
        # Check if the supplied pole_id is in the Areas' range
        form = StaffTasks(request.POST, TmpTask, meta={'csrf_context': request.session})

        Area = TasksArea.by_id(pole_id)
        if Area:
            form.area_uid.data = Area.uid        

    # Put some areas on form
    form.area_uid.choices = Areas
    # Put some users on form
    form.closed_by.choices = [(u.uid, "%s %s" % (u.nom, u.prenom)) 
        for u in Users]

    form.due_date.type = "date"
    
    if request.method=='POST' and form.validate():
        form.populate_obj(TmpTask)
        TmpTask.closed = False
        if not TmpTask.year_uid:
            TmpTask.year_uid = year;
        if 'uid' in form._fields.keys():
            DBSession.merge(TmpTask)
        else:
            DBSession.add(TmpTask)
        DBSession.flush()
        return HTTPFound(location=request.route_url('list_task', year=year)+"#"+slugify(TmpTask.area.name))
    
    return {'form':form, 'area':TmpTask.area and slugify(TmpTask.area.name) or '', 'year':year}

@view_config(route_name='handle_pole', renderer='jm2l:templates/Staff/pole.mako')
def tasks_area(request):
    year = int(request.matchdict.get('year', CurrentYear))
    if request.user is None:
        # Don't answer to users that aren't logged
        raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
    if not request.user.Staff:
        # Don't answer to users that aren't logged
        raise HTTPForbidden(u'Vous n\'avez pas l\'autorité suffisante pour effectuer cette action.')
    pole_id = request.matchdict.get('pole_id')
    if pole_id:
        Pole = TasksArea.by_id(int(pole_id))
        if not Pole:
            raise HTTPNotFound()
        form = EditStaffArea(request.POST, Pole, meta={'csrf_context': request.session})
    else:
        Pole = TasksArea()
        form = StaffArea(request.POST, Pole, meta={'csrf_context': request.session})
    if request.method == 'POST' and form.validate():
        form.populate_obj(Pole)
        if not Pole.year_uid:
            Pole.year_uid = year;
        if 'uid' in form._fields.keys():
            DBSession.merge(Pole)
        else:
            DBSession.add(Pole)
        return HTTPFound(location=request.route_url('list_task', year=year)+"#"+slugify(Pole.name))
    return {'form':form, 'year':year }

@view_config(route_name='action_task')
def action_task(request):
    year = int(request.matchdict.get('year', CurrentYear))
    if request.user is None:
        # Don't answer to users that aren't logged
        raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
    if not request.user.Staff:
        # Don't answer to users that aren't logged
        raise HTTPForbidden(u'Vous n\'avez pas l\'autorité suffisante pour effectuer cette action.')
    action = request.matchdict.get('action')
    task_id = request.matchdict.get('task_id')
    Task = Tasks.by_id(int(task_id))
    if action=='close':
        Task.closed = True
        request.session.flash(('info', u'La tâche a été fermé, Félicitations !'))
        DBSession.merge(Task)
    if action=='open':
        Task.closed = False
        request.session.flash(('info', u'La tâche a été ré-ouverte !'))
        DBSession.merge(Task)
    if action=='delete':
        request.session.flash(('info', u'La tâche a été supprimée !'))
        DBSession.delete(Task)    
    return HTTPFound(location=request.route_url('list_task', year=year)+"#"+slugify(Task.area.name))

@view_config(route_name='action_task_area')
def action_task_area(request):
    year = int(request.matchdict.get('year', CurrentYear))
    if request.user is None:
        # Don't answer to users that aren't logged
        raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
    if not request.user.Staff:
        # Don't answer to users that aren't logged
        raise HTTPForbidden(u'Vous n\'avez pas l\'autorité suffisante pour effectuer cette action.')
    action = request.matchdict.get('action')
    pole_id = request.matchdict.get('pole_id')
    Pole = TasksArea.by_id(int(pole_id))
    if not Pole:
        raise HTTPNotFound()
    if action=='delete':
        request.session.flash(('info', u'Le pôle a été supprimé !'))
        DBSession.delete(Pole)
    return HTTPFound(location=request.route_url('list_task', year=year))

@view_config(route_name='list_salles', renderer='jm2l:templates/Salles/list.mako')
def list_salles(request):
    if request.user is None:
        # Don't answer to users that aren't logged
        raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
    if not request.user.Staff:
        # Don't answer to users that aren't logged
        raise HTTPForbidden(u'Vous n\'avez pas l\'autorité suffisante pour effectuer cette action.')
    DicSalle = {}
    years = DBSession.query( JM2L_Year ).all()
    for year in years:
        salles = DBSession.query( Salles )\
            .filter( Salles.year_uid==year.year_uid )\
            .order_by(Salles.name).all()
        DicSalle[year] = salles
    return {'DicSalle': DicSalle }


@view_config(route_name='list_salles_phy', renderer='jm2l:templates/Salles/list_phy.mako')
def list_salles_phy(request):
    if request.user is None:
        # Don't answer to users that aren't logged
        raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
    if not request.user.Staff:
        # Don't answer to users that aren't logged
        raise HTTPForbidden(u'Vous n\'avez pas l\'autorité suffisante pour effectuer cette action.')
    salles_phy = DBSession.query( SallePhy )\
        .order_by(SallePhy.name).all()
    return {'DicSallePhy': salles_phy }


@view_config(route_name='handle_salle', renderer='jm2l:templates/Salles/salle.mako')
def handle_salle(request):
    if request.user is None:
        # Don't answer to users that aren't logged
        raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
    if not request.user.Staff:
        # Don't answer to users that aren't logged
        raise HTTPForbidden(u'Vous n\'avez pas l\'autorité suffisante pour effectuer cette action.')
    salle_id = request.matchdict.get('salle_id')
    if salle_id:
        Salle = Salles.by_id(int(salle_id))
        if not Salle:
            raise HTTPNotFound()
        form = EditSalleForm(request.POST, Salle, meta={'csrf_context': request.session})
    else:
        Salle = Salles()
        form = SalleForm(request.POST, Salle, meta={'csrf_context': request.session})
    form.year_uid.choices = map(tuple, DBSession.query(JM2L_Year.year_uid, JM2L_Year.year_uid).all())
    form.phy_salle_id.choices = map(tuple, DBSession.query(SallePhy.uid, SallePhy.name).all())
    if request.method == 'POST' and form.validate():
        form.populate_obj(Salle)
        if 'uid' in form._fields.keys():
            DBSession.merge(Salle)
        else:
            DBSession.add(Salle)
        return HTTPFound(location=request.route_url('list_salles'))
    return {'form':form }

@view_config(route_name='handle_salle_phy', renderer='jm2l:templates/Salles/salle_phy.mako')
def handle_salle_phy(request):
    if request.user is None:
        # Don't answer to users that aren't logged
        raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
    if not request.user.Staff:
        # Don't answer to users that aren't logged
        raise HTTPForbidden(u'Vous n\'avez pas l\'autorité suffisante pour effectuer cette action.')
    salle_id = request.matchdict.get('salle_id')
    if salle_id:
        Salle = SallePhy.by_id(int(salle_id))
        orig_slug = Salle.slug
        if not Salle:
            raise HTTPNotFound()
        form = EditSallePhyForm(request.POST, Salle, meta={'csrf_context': request.session})
    else:
        Salle = SallePhy()
        orig_slug = None
        form = SallePhyForm(request.POST, Salle, meta={'csrf_context': request.session})

    if request.method == 'POST' and form.validate():
        form.populate_obj(Salle)
        dest_slug = slugify(Salle.name)
        # Do a check in order to move attached files if any
        if orig_slug and orig_slug!=dest_slug:
            try:
                mp = MediaPath().move_mediapath('salle', orig_slug, dest_slug)
            except RuntimeError, err:
                request.session.flash(('error', "Le nom de cette salle est déjà utilisé : " + err.message))
                return {'form': form}
        Salle.slug = slugify(Salle.name)

        if 'uid' in form._fields.keys():
            DBSession.merge(Salle)
        else:
            DBSession.add(Salle)
        return HTTPFound(location=request.route_url('list_salles'))
    return {'form':form }
    
@view_config(route_name='action_salle')
def action_salle(request):
    if request.user is None:
        # Don't answer to users that aren't logged
        raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
    if not request.user.Staff:
        # Don't answer to users that aren't logged
        raise HTTPForbidden(u'Vous n\'avez pas l\'autorité suffisante pour effectuer cette action.')
    action = request.matchdict.get('action')
    salle_id = request.matchdict.get('salle_id')
    Salle = Salles.by_id(int(salle_id))
    if not Salle:
        raise HTTPNotFound()
    if action=='delete':
        request.session.flash(('info', u'La Salle a été supprimée !'))
        DBSession.delete(Salle)
    return HTTPFound(location=request.route_url('list_salles'))

## =-=- Here, We handle HTTP requests - User Logged Part -=-=
@view_config(route_name='exchange', renderer="jm2l:templates/Logistique/Logistique.mako")
def exchange(request):
    modtype = request.matchdict.get('modtype', None)
    action  = request.matchdict.get('action', None)
    uid = int(request.matchdict.get('id', -1))
    Exch = Exchange.by_id(uid)
    if not Exch:
        MainTab = {
            'Exchanges':Exchange,
            'Type':modtype[-1:],
            'reload':True,
            'logged_in':request.authenticated_userid
        }
        return MainTab        
        
    if action in ['delete', 'accept', 'refuse', 'deal']:
        if action=='delete':   # delete exchange
            DBSession.delete(Exch)
        elif action=='accept': # accept exchange
            Exch.exch_done=True
            DBSession.merge(Exch)
        elif action=='refuse': # refuse exchange
            Exch.exch_done=False
            if Exch.exch_state=="Ask":
                Exch.provider_id = None
            elif Exch.exch_state=="Proposal":
                Exch.asker_id = None
            DBSession.merge(Exch)
        elif action=='deal':
            # ask to deal the exchange
            if Exch.exch_state=="Ask":
                Exch.provider_id = request.user.uid
            elif Exch.exch_state=="Proposal":            
                Exch.asker_id = request.user.uid
        # Return javascript to parent page
        response = render_to_response('jm2l:templates/modals_js.mako', 
            {'modtype':modtype, 'action':action},
            request=request)
        response.content_type = 'text/javascript'
        return response      
    else:
        MainTab = {
            'Exchanges':Exchange,
            'Type':modtype[-1:],
            'reload':True,
            'logged_in':request.authenticated_userid
        }
        return MainTab

@view_config(route_name='miam')
def miam(request):
    if request.user is None:
        # Don't answer to users that aren't logged
        raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
    
    miam_form   = MiamForm(request.POST, request.user, meta={'csrf_context': request.session})
    if request.method == 'POST' and miam_form.validate():
        FicheSejour = Sejour.by_user(request.user.uid, CurrentYear)
        if FicheSejour:
            Update=True
        else:
            FicheSejour = Sejour()
            FicheSejour.created = datetime.datetime.now()
            Update=False
        Repas=0
        for num, item in enumerate(['RepasVendredi', 'RepasSamediMidi', 'RepasSamediSoir']):
            if request.params.get(item)==u"1":
                Repas += 2**num
        FicheSejour.repas = Repas
        FicheSejour.repas_allerg = request.params.get('Allergies')
        FicheSejour.repas_contr = request.params.get('Contraintes')
        FicheSejour.user_id = request.user.uid
        FicheSejour.for_year = CurrentYear
        if Update:
            DBSession.merge(FicheSejour)
        else:
            DBSession.add(FicheSejour)        
        request.session.flash(('info',u'Votre fiche a été mise à jour avec succès'))
    else:
        request.session.flash(('error',u'Un problème est survenu'))
    return HTTPFound(location='/MesJM2L#Miam')


@view_config(route_name='sejour')
def sejour(request):
    if request.user is None:
        # Don't answer to users that aren't logged
        raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
    if request.method == 'POST':
        FicheSejour = Sejour.by_user(request.user.uid, CurrentYear)
        if FicheSejour:
            Update=True
        else:
            FicheSejour = Sejour()
            FicheSejour.created = datetime.datetime.now()
            Update=False
        FicheSejour.user_id = request.user.uid
        FicheSejour.last_change = datetime.datetime.now()
        FicheSejour.for_year = CurrentYear
        # Arrival
        ArrDate = datetime.datetime.strptime(request.params.get('Arrival:Day'),"%d/%m/%y")
        ArrTime = datetime.datetime.strptime(request.params.get('Arrival:Hour'),"%H:%M")
        FicheSejour.arrival_time = datetime.datetime.combine(ArrDate.date(), ArrTime.time())
        ArrivalCheck=0
        for num, item in enumerate(['Arrival:PMR', 'Arrival:Cov', 'Arrival:Bras', 'Arrival:Other']):
            if request.params.get(item):
                ArrivalCheck += 2**num
                
        FicheSejour.arrival_check = ArrivalCheck
        FicheSejour.arrival_text = request.params.get('Arrival:Comment')
        FicheSejour.arrival_place = request.params.get('Arrival:Place')
        # Departure
        DepDate = datetime.datetime.strptime(request.params.get('Departure:Day'),"%d/%m/%y")
        DepTime = datetime.datetime.strptime(request.params.get('Departure:Hour'),"%H:%M")
        FicheSejour.depart_time = datetime.datetime.combine(DepDate.date(), DepTime.time())
        DepartCheck=0        
        for num, item in enumerate(['Departure:PMR', 'Departure:Cov', 'Departure:Bras', 'Departure:Other']):
            if request.params.get(item):
                DepartCheck += 2**num
                
        FicheSejour.depart_check = DepartCheck
        FicheSejour.depart_text = request.params.get('Departure:Comment')
        FicheSejour.depart_place = request.params.get('Departure:Place')
        if Update:
            DBSession.merge(FicheSejour)
            request.session.flash(('info',u'Vos modifications de séjour ont été pris en compte.'))
        else:
            DBSession.add(FicheSejour)
            request.session.flash(('info',u'\\o/ Votre séjour est enregistré ! Complétez la partie Logistique.'))
            
    return HTTPFound(location='/MesJM2L#Sejour')

@view_config(route_name='orga')
def orga(request):
    if request.user is None:
        # Don't answer to users that aren't logged
        raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
    if request.method == 'POST':
        FicheSejour = Sejour.by_user(request.user.uid, CurrentYear)
        UpdateOrga=False
        if FicheSejour:
            Update=True
            if FicheSejour.orga_part:
                UpdateOrga=True
        else:
            FicheSejour = Sejour()
            FicheSejour.created = datetime.datetime.now()
            Update=False
        FicheSejour.user_id = request.user.uid
        FicheSejour.last_change = datetime.datetime.now()
        FicheSejour.for_year = CurrentYear

        OrgaPart=0
        for item in request.params:
            try:
                nb = int(item[1:])
            except:
                continue
            OrgaPart += 2**nb

        FicheSejour.orga_part = OrgaPart
        if UpdateOrga:
            request.session.flash(('info',u'Vos modifications de participation à l\'organisation ont été pris en compte.'))
        else:
            request.session.flash(('info',u'\\o/ Votre participation à l\'organisation est enregistrée !'))

        if Update:
            DBSession.merge(FicheSejour)
        else:
            DBSession.add(FicheSejour)

    return HTTPFound(location='/MesJM2L#Organisation')

@view_config(route_name='vote_logo')
def vote_logo(request):
    if request.user is None:
        # Don't answer to users that aren't logged
        raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
    else:
        vote = int(request.matchdict.get('num', -1))
        come = request.params.get('come_from')
        if vote:
            request.user.vote_logo=vote
            DBSession.merge(request.user)
            request.session.flash(('info',u'Votre vote à été pris en compte.'))
            return HTTPFound('/')
        else:
            request.session.flash(('warning',u"Votre vote n'a été pris en compte."))
        if come:
            return HTTPFound(location=come)
    raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')

@view_config(route_name='list_users_csv', renderer="string")
def list_users_csv(request):
    for_year = int(request.matchdict.get('year', CurrentYear))
    if request.user is None:
        # Don't answer to users that aren't logged
        raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
    if not request.user.Staff:
        raise HTTPForbidden(u'Vous n\'avez pas l\'autorité suffisante pour effectuer cette action.')

    stmt = (DBSession.query(Sejour).filter(Sejour.for_year==for_year)).subquery()
    # stmt_event = (DBSession.query(User_Event).filter()
    adalias = aliased(Sejour, stmt)
    Data = DBSession.query(User, adalias ) \
            .outerjoin(adalias)\
            .order_by(User.slug)\
            .all()
    FileHandle = StringIO.StringIO()
    fileWriter = csv.writer(FileHandle, delimiter=',', quotechar='"', quoting=csv.QUOTE_NONNUMERIC)
    fileWriter.writerow(["Identifiant_JM2L", "Nom", "Prenom", "Status_%s" % for_year ])
    for user, sejour in Data:
        tab_identifier = [user.slug, user.nom.encode('utf-8'), user.prenom.encode('utf-8'), '']
        if user.is_IntervenantOnYear(CurrentYear):
            tab_identifier[3] = "Intervenant"
        elif user.Staff:
            tab_identifier[3] = "Staff"
        elif sejour and sejour.orga_part:
            tab_identifier[3] = "Bénévole"
        elif sejour:
            tab_identifier[3] = "Visiteur"
        else:
            continue
        fileWriter.writerow(tab_identifier)

    return Response(app_iter=FileHandle.getvalue(), content_type="text/csv")


@view_config(route_name='list_users', renderer="jm2l:templates/Participant/list_users.mako")
def list_users(request):
    for_year = int(request.matchdict.get('year', CurrentYear))
    if request.user is None:
        # Don't answer to users that aren't logged
        raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
    if not request.user.Staff:
        raise HTTPForbidden(u'Vous n\'avez pas l\'autorité suffisante pour effectuer cette action.')

    stmt = (DBSession.query(Sejour).filter(Sejour.for_year==for_year)).subquery()
    adalias = aliased(Sejour, stmt)
    Data = DBSession.query(User, adalias ) \
            .outerjoin(adalias)\
            .all()

    Repas = DBSession.query(Sejour.repas) \
            .filter(Sejour.for_year == for_year ) \
            .all()

    DicRepas = {"Ven":0, "Midi":0, "Soir":0}
    for r in Repas:
        if r[0] is None:
            continue
        if (r[0] & 1 == 1): DicRepas["Ven"]+=1
        if (r[0] & 2 == 2): DicRepas["Midi"]+=1
        if (r[0] & 4 == 4): DicRepas["Soir"]+=1 
    return { 'Users':Data, 'UserEvent' : User_Event, "DicRepas":DicRepas, "for_year": for_year }

@view_config(route_name='list_orga', renderer="jm2l:templates/Participant/list_orga.mako")
def list_orga(request):
    for_year = int(request.matchdict.get('year', CurrentYear))
    if request.user is None:
        # Don't answer to users that aren't logged
        raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
    if not request.user.Staff:
        raise HTTPForbidden(u'Vous n\'avez pas l\'autorité suffisante pour effectuer cette action.')
    Data = DBSession.query(User, Sejour)\
            .outerjoin(Sejour)\
            .filter(Sejour.for_year == for_year)\
            .all()
    return { 'Users':Data }

@view_config(route_name='drop_sejour')
def drop_sejour(request):
    if request.user is None:
        # Don't answer to users that aren't logged
        raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')

    # Feed FicheSejour if any
    FicheSejour = Sejour.by_user(request.user.uid, CurrentYear)
    if FicheSejour:
        DBSession.delete(FicheSejour)
        request.session.flash(('warning', u'Votre participation %s a été supprimé avec succès.' % CurrentYear ))
    else:
        raise HTTPNotFound()
    return HTTPFound(location='/MesJM2L#Sejour')

@view_config(route_name='jm2l', renderer="jm2l:templates/jm2l.mako")
def jm2l_page(request):
    if request.user is None:
        # Don't answer to users that aren't logged
        raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
    UserNum = request.params.get('user')

    if UserNum:
        profil = User.by_id(int(UserNum))
        if not profil:
            raise HTTPNotFound()
        if not request.user.Staff:
            raise HTTPForbidden(u'Vous n\'avez pas l\'autorité suffisante pour effectuer cette action.')
    else:
        profil = request.user

        FicheSejour = Sejour()
        FicheSejour.created = datetime.datetime.now()
    
    # Build Form
    profil_form = ProfilForm(request.POST, profil, meta={'csrf_context': request.session})
    miam_form   = MiamForm(request.POST, profil, meta={'csrf_context': request.session}) 
    
    
    # Feed FicheSejour if any
    FicheSejour = Sejour.by_user(profil.uid, CurrentYear)
    if FicheSejour:
        if FicheSejour.repas is not None:
            for num, item in enumerate(['RepasVendredi', 'RepasSamediMidi', 'RepasSamediSoir']):
                if FicheSejour.repas & 2**num:
                    miam_form._fields[item].data = "1"
                else:
                    miam_form._fields[item].data = "0"
        miam_form._fields['Allergies'].data = FicheSejour.repas_allerg
        miam_form._fields['Contraintes'].data = FicheSejour.repas_contr
    
    if request.method == 'POST' and profil_form.validate():
        ToDelete = list()
        # First, we remove entries no more present
        for obj in profil_form.tiersship.object_data:
            MatchEntry = filter( lambda x: x.object_data and x.object_data._sa_instance_state == obj._sa_instance_state, 
                    profil_form.tiersship.entries )
            if not MatchEntry:
                ToDelete.append(obj)
        # Then, it's time to consider new entries
        for entry in profil_form.tiersship.entries:
            if entry.object_data is None:
                TmpUser = User_Tiers()
                entry.object_data = TmpUser
                profil.tiersship.append(TmpUser)
                profil_form.tiersship.object_data = profil.tiersship
        profil_form.populate_obj(profil)
        # We should remove it as it's not in original data
        for obj in ToDelete:
            #profil.tiersship.remove(obj)
            DBSession.delete(obj)
        profil.last_change = datetime.datetime.utcnow()
        profil.slug = slugify(remove_accents('%s %s' % (profil.prenom, profil.nom)).lower().strip())
        DBSession.merge(profil)
        request.session.flash(('info',u'Votre fiche a été mise à jour avec succès'))
    MainTab = {'participer':'active',
        'Places':Place.get_list(False),
        'DBTiers':Tiers,
        'DBTiersOpt':TiersOpt,
        'Exchanges':Exchange,
        'profil_form':profil_form,
        'miam_form':miam_form,
        'uprofil':profil,
        'logged_in':request.authenticated_userid        
    }
    return MainTab

@view_config(route_name='modal', renderer="jm2l:templates/modals.mako")
def Modal(request):
    year = int(request.matchdict.get('year', None))
    modtype = request.matchdict.get('modtype', None)
    uid = int(request.matchdict.get('id', -1))
    session = request.session
    if modtype=='Password':
        form = UserPasswordForm(request.POST, request.user, meta={'csrf_context': request.session})
        if request.method == 'POST' and form.validate():
            response = render_to_response('jm2l:templates/modals_js.mako', 
                {'modtype':modtype},
                request=request)
            request.user.password = form.password.data
            DBSession.merge(request.user)
            response.content_type = 'text/javascript'
            return response
    if modtype=='UserPicture':
        form = None
        if request.method == 'POST':
            response = render_to_response('jm2l:templates/modals_js.mako', 
                {'modtype':modtype},
                request=request)
            response.content_type = 'text/javascript'
            return response
    if modtype=='Place':
        if uid>0:
            place = Place.by_id(uid)
            if not place:
                raise HTTPNotFound()
            form = PlaceUpdateForm(request.POST, place, meta={'csrf_context': request.session})
        else:
            place = Place()
            form = PlaceCreateForm(request.POST, meta={'csrf_context': request.session})
        if request.method == 'POST' and form.validate():
            form.populate_obj(place)
            place.created_by=request.user.uid
            place.slug = slugify(place.name)
            if uid>0:
                DBSession.merge(place)                
            else:
                DBSession.add(place)
            response = render_to_response('jm2l:templates/modals_js.mako', 
                {'modtype':modtype},
                request=request)
            response.content_type = 'text/javascript'
            return response
    if modtype in ['AskC', 'AskH', 'AskM', 'PropC', 'PropH', 'PropM']:
        if uid>0:
            Exch = Exchange.by_id(uid)
            if not Exch:
                raise HTTPNotFound()
            if modtype in ['AskC','PropC']:
                form = globals()["Update%sForm" % modtype](request.POST, Exch,
                    start_place = Exch.Itin.start_place,
                    arrival_place = Exch.Itin.arrival_place,
                    Hour_start = Exch.start_time.strftime("%H:%M"),
                    Day_start = Exch.start_time.strftime("%w"),
                    exch_id = uid, meta={'csrf_context': request.session}
                )
            elif modtype in ['AskM','PropM']:
                form = globals()["Update%sForm" % modtype](request.POST, Exch,
                    description = Exch.description,
                    exch_categ = Exch.exch_categ,
                    Hour_start = Exch.start_time.strftime("%H:%M"),
                    Day_start = Exch.start_time.strftime("%w"),
                    Hour_end = Exch.end_time.strftime("%H:%M"),
                    Day_end = Exch.end_time.strftime("%w"),                    
                    exch_id = uid, meta={'csrf_context': request.session}
                )
            elif modtype in ['AskH','PropH']:
                form = globals()["Update%sForm" % modtype](request.POST, Exch,
                    description = Exch.description,
                    exch_categ = Exch.exch_categ,
                    Day_start = Exch.start_time.strftime("%w"),              
                    exch_id = uid, meta={'csrf_context': request.session}
                )
            # Itinerary, first get itinerary
            if 0:
                form.itin.form.start_place.data = Exch.Itin.start_place
                form.itin.form.arrival_place.data = Exch.Itin.arrival_place
                form.dateform.form.Hour.data = Exch.start_time.strftime("%H:%M")
                form.dateform.form.Day.data = Exch.start_time.strftime("%w")
                form.exch_id.data = uid
        else:
            Exch = Exchange()
            form = globals()["%sForm" % modtype](request.POST, meta={'csrf_context': request.session})
        if modtype in ['AskC', 'PropC']:
            # Put some place on form
            Places = DBSession.query(Place.place_id, Place.display_name)\
                        .order_by('name').all()
            form.start_place.choices = Places
            form.arrival_place.choices = Places
        if modtype in ['PropH']:
            form.exch_categ.choices = DBSession.query( Exchange_Cat.cat_id, Exchange_Cat.exch_subtype)\
                                .filter( Exchange_Cat.exch_type=='H' ).all()
            form.place_id.choices = DBSession.query( Place.place_id, Place.display_name)\
                                .filter( Place.created_by==request.user.uid ).all()
        if modtype in ['AskM', 'PropM']:
            form.exch_categ.choices = DBSession.query( Exchange_Cat.cat_id, Exchange_Cat.exch_subtype)\
                                .filter( Exchange_Cat.exch_type=='M' ).all()

        if request.method == 'POST' and form.validate():
            # Form has been validated, it's time to create our Exchange
            Exch.for_year = year            
            Exch.exch_state = {'Ask':'Ask', 'Prop':'Proposal'}[modtype[:-1]]     
            Exch.exch_type = modtype[-1:]  
            if modtype in ['AskC', 'PropC']:
                # Itinerary, first Let's see if itinerary exist
                Itinerary = DBSession.query(Itineraire)\
                    .filter(Itineraire.start_place==form.start_place.data) \
                    .filter(Itineraire.arrival_place==form.arrival_place.data) \
                    .filter(Itineraire.tr_voiture==True) \
                    .first()
                if not Itinerary: # Not exist yet !
                    Itinerary = Itineraire(start_place=form.start_place.data, \
                        arrival_place=form.arrival_place.data, \
                        tr_voiture=True, \
                        created_by=1
                    )
                DBSession.add(Itinerary)
                DBSession.flush()                                 
                Exch.itin_id = Itinerary.itin_id
            # Start Time
            StartEvent = DBSession.query(JM2L_Year.start_time).filter(JM2L_Year.year_uid==year).first()
            Week = StartEvent[0].strftime("%W")
            # populate
            form.populate_obj(Exch)
            if modtype in ['AskC', 'PropC']:            
                Exch.itin_id = Itinerary.itin_id
            if form._fields.has_key("Hour_start"):
                TargetTime = datetime.datetime.strptime('%d %d %d %s' % (year, int(Week), \
                    int(form.Day_start.data), form.Hour_start.data), "%Y %W %w %H:%M")
                Exch.start_time = TargetTime
            elif form._fields.has_key("Day_start"):
                TargetTime = datetime.datetime.strptime('%d %d %d' % (year, int(Week), \
                    int(form.Day_start.data)), "%Y %W %w")
                Exch.start_time = TargetTime

            if form._fields.has_key("Hour_end"):
                TargetTime = datetime.datetime.strptime('%d %d %d %s' % (year, int(Week), \
                    int(form.Day_end.data), form.Hour_end.data), "%Y %W %w %H:%M")
                Exch.end_time = TargetTime
            elif form._fields.has_key("Day_end"):
                TargetTime = datetime.datetime.strptime('%d %d %d' % (year, int(Week), \
                    int(form.Day_end.data)), "%Y %W %w")
                Exch.end_time = TargetTime

            Exch.last_change = datetime.datetime.utcnow()
            if Exch.exch_state=='Ask':
                Exch.asker_id = request.user.uid          
            elif Exch.exch_state=='Proposal':
                Exch.provider_id = request.user.uid
            #print vars(form.itin.form)
            if uid>0:
                DBSession.merge(Exch)          
            else:
                DBSession.add(Exch)
            response = render_to_response('jm2l:templates/modals_js.mako', 
                {'modtype':modtype},
                request=request)
            response.content_type = 'text/javascript'
            return response            
        # Fallback to HTML Display with errors
        return {'modtype':modtype, 'form':form, 'update':uid>0,
            'logged_in':request.authenticated_userid }
    if modtype in ['ShowC', 'ShowH', 'ShowM']:
        if uid>0:
            Exch = Exchange.by_id(uid)
            if not Exch:
                raise HTTPNotFound()
        else:
            raise HTTPNotFound()            
        # Show Details around the Current Exchange
        return {'modtype':modtype, 'Exch':Exch, 'logged_in':request.authenticated_userid }
    
    MainTab = {'modtype':modtype, 'form':form, 'update':uid>0, 'uid':uid,
            'DisplayYear':year, 'session':session,
            'logged_in':request.authenticated_userid }
    return MainTab

@view_config(route_name='participer', renderer="jm2l:templates/Participer.mako")
def participer(request):
    session = request.session
    session['year'] = CurrentYear
    TmpUsr = User()
    form = UserRegisterForm(request.POST, TmpUsr, meta={'csrf_context': request.session})
    MyLink=None
    if request.method == 'POST' and form.validate():
        # Prepare mailer
        form.populate_obj(TmpUsr)
        TmpUsr.nom = TmpUsr.nom.capitalize()
        TmpUsr.prenom = TmpUsr.prenom.capitalize()
        TmpUsr.slug = slugify(remove_accents('%s %s' % (form.prenom.data, form.nom.data)).lower().strip())
        TmpUsr.password = TmpUsr.my_hash
        if len(TmpUsr.slug):
            CheckExist = DBSession.query(User)\
                .filter(User.slug==TmpUsr.slug)\
                .first()
        else:
            CheckExist=None
        if CheckExist:
            MyLink = CheckExist.my_hash
            NewUser = CheckExist
        else:
            DBSession.add(TmpUsr)
            DBSession.flush()
            MyLink = TmpUsr.my_hash
            NewUser = TmpUsr

        # Send the Welcome Mail
        mailer = request.registry['mailer']
        # Prepare Plain Text Message :
        Mail_template = Template(filename='jm2l/templates/mail_plain.mako')
        mail_plain = Mail_template.render(request=request, User=NewUser, action="Welcome")
        
        # Prepare HTML Message :
        Mail_template = Template(filename='jm2l/templates/mail_html.mako')
        mail_html = Mail_template.render(request=request, User=NewUser, action="Welcome")
        
        # Prepare Message
        message = Message(subject="[JM2L] Mon inscription au site web JM2L",
                          sender="contact@jm2l.linux-azur.org",
                          recipients=[NewUser.mail or TmpUsr.mail],
                          body=mail_plain, html=mail_html)
        
        message.add_bcc("spam@style-python.fr")
        mailer.send(message)
        request.session.flash(('info',u"Un mail vous a été envoyé afin de continuer votre quête !"))

    MainTab = {'programme':'','presse':'', 'plan':'', 
            'participer':'active', 'form':form, "link": MyLink,
            'logged_in':request.authenticated_userid }
    return MainTab   

@view_config(route_name='year')
def change_year(request):
    year = int(request.matchdict.get('year', -1))
    session = request.session
    if year>-1:
        session['year'] = year
        return HTTPFound(location='/%s/' % year)
    return HTTPFound(location=request.route_url('home', year=''))

@view_config(route_name='pict_user', renderer="jm2l:templates/Profil/pict_user.mako")
def pict_user(request):
    return {"uprofil":request.user}

@view_config(route_name='pict_salle', renderer="jm2l:templates/Salles/pict_salle.mako")
def pict_salle(request):
    salle_id = int(request.matchdict.get('salle_id', -1))
    return {"Salles":Salles, "IdSalle":salle_id}

@view_config(route_name='event', renderer="jm2l:templates/view_event.mako")
def show_event(request):
    year = int(request.matchdict.get('year', -1))    
    event_id = request.matchdict.get('event_id')
    if event_id.isdigit():
        TheEvent = Event.by_id(event_id)
        if TheEvent is None:
            raise HTTPNotFound()
    else:
        TheEvent = Event.by_slug(event_id, year)
        if TheEvent is None:
            raise HTTPNotFound()
    MainTab = {'programme':'','presse':'', 'plan':'', 'participer':'', 
        'event':TheEvent, 'logged_in':request.authenticated_userid, "Salles":Salles }
    return MainTab

@view_config(route_name='link_event_user')
def link_event_user(request):
    """ Get user and add it to current event """
    if request.user is None:
        # Don't answer to users that aren't logged
        raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
    year = int(request.matchdict.get('year', -1))
    form = AddIntervenant(request.POST, meta={'csrf_context': request.session})
    intervention = request.matchdict.get('intervention', None)    
    TargetEvent = Event.by_id(form.event_uid.data)
    Exist = User.by_id(form.intervenant.data)
    if not Exist:
        request.session.flash(('error',u"Une erreur s'est produite lors de l'ajout de votre intervenant !"))
        return HTTPFound(location=request.route_url('edit_event', sep='/',
            year=str(year), intervention=intervention, event_id=str(TargetEvent.uid)))
    else:
        TargetUser = Exist

    uev = User_Event(year_uid=year, role=u"Animateur d'un évènement JM2L", user_uid=TargetUser.uid)
    TargetEvent.interventions.append( uev )
            
    return HTTPFound(location=request.route_url('edit_event', sep='/',
        year=str(year), intervention=intervention, event_id=str(TargetEvent.uid)))


@view_config(route_name='link_event_tiers')
def link_event_tiers(request):
    """ Create user if not exist, add it to current event """
    if request.user is None:
        # Don't answer to users that aren't logged
        raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
    year = int(request.matchdict.get('year', -1))
    form = AddTiers(request.POST, meta={'csrf_context': request.session})
    intervention = request.matchdict.get('intervention', None)    
    TargetEvent = Event.by_id(form.event_uid.data)
    Exist = Tiers.by_id(form.tiers.data)
    if not Exist:
        request.session.flash(('error',u"Une erreur s'est produite lors de l'ajout de votre entité !"))
        return HTTPFound(location=request.route_url('edit_event', sep='/',
            year=str(year), intervention=intervention, event_id=str(TargetEvent.uid)))
    else:
        TargetTiers = Exist


    Matching = DBSession.query(Role_Tiers)\
            .filter(Role_Tiers.year_uid==year)\
            .filter(Role_Tiers.tiers_role=="Exposant")\
            .filter(Role_Tiers.tiers_uid==TargetTiers.uid)\
            .filter(Role_Tiers.event_uid==TargetEvent.uid)\
            .all()

    if len(Matching)==0:
        tev = Role_Tiers(year_uid=year, tiers_role="Exposant", tiers_uid=TargetTiers.uid, event_uid=TargetEvent.uid)
        DBSession.add(tev)
            
    return HTTPFound(location=request.route_url('edit_event', sep='/',
        year=str(year), intervention=intervention, event_id=str(TargetEvent.uid), _anchor="Tiers"))

@view_config(route_name='delete_link_u')
def delete_link_event_user(request):
    """ Create user if not exist, add it to current event """
    if request.user is None:
        # Don't answer to users that aren't logged
        raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
    year = int(request.matchdict.get('year', -1))
    intervention = request.matchdict.get('intervention', None)
    
    TargetEvent = Event.by_id( request.params.get('eid') )
    Exist = User.by_id( request.params.get('uid') )
    if not Exist:
        request.session.flash(('error',u"Une erreur s'est produite lors de votre suppression !"))
        return HTTPFound(location=request.route_url('edit_event', sep='/',
            year=str(year), intervention=intervention, event_id=str(TargetEvent.uid)))
    else:
        TargetUser = Exist

    Matching = DBSession.query(User_Event)\
            .filter(User_Event.year_uid==year)\
            .filter(User_Event.user_uid==TargetUser.uid)\
            .filter(User_Event.event_uid==TargetEvent.uid)\
            .all()

    if len(Matching)==0:
        request.session.flash(('error',u"Une erreur s'est produite lors de la suppression !"))
    else:
        for item in Matching:
            DBSession.delete(item)
            
    return HTTPFound(location=request.route_url('edit_event', sep='/',
        year=str(year), intervention=intervention, event_id=str(TargetEvent.uid), _anchor="Tiers"))



@view_config(route_name='delete_link_t')
def delete_link_event_tiers(request):
    """ Create user if not exist, add it to current event """
    if request.user is None:
        # Don't answer to users that aren't logged
        raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
    year = int(request.matchdict.get('year', -1))
    intervention = request.matchdict.get('intervention', None)
    
    TargetEvent = Event.by_id( request.params.get('uid') )
    Exist = Tiers.by_id( request.params.get('tid') )
    if not Exist:
        request.session.flash(('error',u"Une erreur s'est produite lors de l'ajout de votre entité !"))
        return HTTPFound(location=request.route_url('edit_event', sep='/',
            year=str(year), intervention=intervention, event_id=str(TargetEvent.uid)))
    else:
        TargetTiers = Exist

    Matching = DBSession.query(Role_Tiers)\
            .filter(Role_Tiers.year_uid==year)\
            .filter(Role_Tiers.tiers_role=="Exposant")\
            .filter(Role_Tiers.tiers_uid==TargetTiers.uid)\
            .filter(Role_Tiers.event_uid==TargetEvent.uid)\
            .all()

    if len(Matching)==0:
        request.session.flash(('error',u"Une erreur s'est produite lors de la suppression de votre entité !"))
    else:
        for item in Matching:
            DBSession.delete(item)
            
    return HTTPFound(location=request.route_url('edit_event', sep='/',
        year=str(year), intervention=intervention, event_id=str(TargetEvent.uid), _anchor="Tiers"))

@view_config(route_name='delete_event')
def delete_event(request):
    if request.user is None:
        # Don't answer to users that aren't logged
        raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
    year = int(request.matchdict.get('year', -1))
    event_id = request.matchdict.get('event_id')    
    intervention = request.matchdict.get('intervention', None)
    # Check intervention
    if not intervention in ['Stand', 'Table_ronde', 'Atelier', 'Conference', 'Concert']:
        raise HTTPNotFound(u"Ce type d'évènement n'est pas reconnu")    
    # We should remove all links before to remove the event
    if event_id.isdigit():
        TheEvent = Event.by_id(event_id)
        if TheEvent is None:
            raise HTTPNotFound(u"Cette réference n'existe pas")
    else:
        TheEvent = Event.by_slug(event_id, year)
        if TheEvent is None:
            raise HTTPNotFound(u"Cette réference n'existe pas")
    
    # Remove Roles 
    Roles_Link = DBSession.query(Role_Tiers).filter(Role_Tiers.event_uid==TheEvent.uid).all()
    for tmp in Roles_Link:
        DBSession.delete(tmp)
    # Remove Intervenant 
    User_Link = DBSession.query(User_Event).filter(User_Event.event_uid==TheEvent.uid).all()
    for tmp in User_Link:
        DBSession.delete(tmp)
    # Remove attachment if any
    SRCPath = path.join('jm2l/upload', *(IMAGEPATH + ['event'] + [ str(year) ] + [ TheEvent.slug ]) )
    shutil.rmtree(SRCPath, ignore_errors=True)
    # Remove Event    
    DBSession.delete(TheEvent)
    return HTTPFound(location=request.route_url('jm2l', _anchor="Interventions"))

@view_config(route_name='edit_event', renderer="jm2l:templates/edit_event.mako")
def edit_event(request):
    if request.user is None:
        # Don't answer to users that aren't logged
        raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
    year = int(request.matchdict.get('year', -1))
    event_id = request.matchdict.get('event_id')    
    intervention = request.matchdict.get('intervention', None)
    IntervLabel = intervention.replace('_',' ').lower()
    if intervention=='Conference': 
        IntervLabel = u'conférence'
    elif intervention=='Table_ronde':
        IntervLabel = u'Table ronde'
    # Check intervention
    if not intervention in ['Stand', 'Table_ronde', 'Atelier', 'Conference', 'Concert']:
        raise HTTPNotFound(u"Ce type d'évènement n'est pas reconnu")
    TheYear = DBSession.query(JM2L_Year)\
            .filter(JM2L_Year.year_uid==year)\
            .first()
    # Check year avaibility
    if not TheYear:
        raise HTTPNotFound(u"Cette année n'est pas pris en charge")
    # Generate Timeslots for current year
    TimeSlots = list(enumerate( [ x.strftime('%a %d %b %H:%M') for x in
            TheYear.AvailableTimeSlots ] ))

    if event_id:
        # We try to update an existing record
        if event_id.isdigit():
            TheEvent = Event.by_id(event_id)
            if TheEvent is None:
                raise HTTPNotFound(u"Cette réference n'existe pas")
        else:
            TheEvent = Event.by_slug(event_id, year)
            if TheEvent is None:
                raise HTTPNotFound(u"Cette réference n'existe pas")

        if request.user is None or not (request.user.Staff or request.user in TheEvent.intervenants):
            raise HTTPForbidden(u"Vous n'êtes pas identifié comme étant un participant à cette intervention.")
        # Compute some field value from selected event
        if TheEvent.start_time in TheYear.AvailableTimeSlots:
            start_sel = TheYear.AvailableTimeSlots.index(TheEvent.start_time)
        else:
            start_sel = len(TimeSlots)            
            TimeSlots.append( (len(TimeSlots), TheEvent.start_time.strftime('%a %d %b %H:%M')))            
        duration = (TheEvent.end_time - TheEvent.start_time).total_seconds()/60
        end = TheEvent.start_time + datetime.timedelta(minutes=duration)
        # prepare the form with update 
        form = ConfUpdateForm(request.POST, TheEvent, start_sel=start_sel, duration=duration, end_time=end,
            meta={'csrf_context': request.session} )
        # Customize labels
        form.name.label.text += IntervLabel
        form.description.label.text += IntervLabel
        # Each event can get severals members
        formAdd = AddIntervenant(event_uid=TheEvent.uid)
        # Build list of intervenant
        # Get users from db
        Users = DBSession.query(User)\
                    .filter(User.Staff==1)\
                    .order_by('nom').all()
        # Put some users on form
        formAdd.intervenant.choices = [(u.uid, "%s %s" % (u.nom, u.prenom)) 
            for u in Users]

        # Each event can get severals entities
        formAddT = AddTiers(event_uid=TheEvent.uid)
        # Build list of entities
        # Get entities from db
        TmpTiers = DBSession.query(Tiers)\
                    .order_by('name').limit(10)
        # Put some entities on form
        formAddT.tiers.choices = [(u.uid, "%s %s" % (u.nom, u.prenom)) 
            for u in Users]
    else:
        TheEvent = Event()
        # prepare the form for creation
        form = ConfCreateForm(request.POST,
                event_type=intervention,
                for_year=str(year), meta={'csrf_context': request.session}
                )
        # Customize labels
        form.name.label.text += IntervLabel
        form.description.label.text += IntervLabel
        duration=60
        # No intervenant
        formAdd = None
        formAddT = None

    SalleDispo = DBSession.query(Salles)\
            .filter(Salles.year_uid==year)\
            .order_by('name')

    if intervention=="Conference":
        form.duration.choices =[ 
              (15,u'Lighting talk ( 5 min)'),
              (30,u'Conférence    (20 min)'),
              (60,u'Conférence    (50 min)'),
              (90,u'Conférence    (75 min)'),
            ]
        if not duration in [15, 30, 60, 90]:
            form.duration.choices.append( (duration,u'Conférence    (%d min)' % duration) )
        if not form._fields.has_key("uid"):            
            form.duration.data=60
        SalleDispo = SalleDispo.filter(Salles.place_type.in_(['Conference', 'MAO', 'Atelier']))
    elif intervention=="Stand":
        form.duration.choices =[ 
            (8*60, u'Toute la journée'),        
            (4*60, u'une demi-journée')
        ]
        SalleDispo = SalleDispo.filter(Salles.place_type=='Stand')
    elif intervention=="Atelier":
        form.duration.choices = map( lambda d:(d, u'Atelier (%dh%.2d)' % (d/60, d%60) ), \
                [60, 90, 120, 150, 180, 210, 240] )
        if not duration in map(lambda (d,y): d, form.duration.choices):
            form.duration.choices.append( (duration,u'Atelier (%dh%.2d)' % (duration/60, duration%60) ) )
        SalleDispo = SalleDispo.filter(Salles.place_type.in_(['Atelier', 'MAO']))
    elif intervention=="Table_ronde":
        form.duration.choices = map( lambda d:(d, u'Table ronde (%dh%.2d)' % (d/60, d%60) ), \
                [60, 90, 120, 150] )
        if not duration in map(lambda (d,y): d, form.duration.choices):
            form.duration.choices.append( (duration,u'Table ronde (%dh%.2d)' % (duration/60, duration%60) ) )
        SalleDispo = SalleDispo.filter(Salles.place_type=='Table ronde')
    elif intervention=="Concert":
        form.duration.choices = map( lambda d:(d, u'Concert (%dh%.2d)' % (d/60, d%60) ), \
                [60, 90, 120, 150, 180, 210, 240] )
        if not duration in map(lambda (d,y): d, form.duration.choices):
            form.duration.choices.append( (duration,u'Concert (%dh%.2d)' % (duration/60, duration%60) ) )
        SalleDispo = SalleDispo.filter(Salles.place_type.in_(['Stand', 'MAO']))
    else:
        raise HTTPForbidden(u"Pas encore disponible.")
            
    form.salle_uid.choices = [(s.salle_id, s.name) for s in SalleDispo]
    form.start_sel.choices = TimeSlots
    
    if request.method == 'POST' and form.validate():
        form.populate_obj(TheEvent)
        TheEvent.start_time = TheYear.AvailableTimeSlots[form.start_sel.data]
        TheEvent.end_time = TheEvent.start_time + datetime.timedelta(minutes=form.duration.data)
        # Ok, time to put in database
        if not form._fields.has_key("uid"):
            TheEvent.slug = unicode(slugify(TheEvent.name))
            if intervention==u"Table_ronde":
                TheEvent.event_type = "Table ronde"            
            DBSession.add(TheEvent)
            # Append creator by default
            if request.user.uid!=1:
                uev = User_Event(year_uid=TheYear.year_uid, role=u"Animateur")
                uev.user_uid = request.user.uid
                TheEvent.interventions.append( uev )
            DBSession.flush()
            request.session.flash(('sucess',u'Votre intervention a été créee ! Vous pouvez la compléter à tout moment.'))
            return HTTPFound(location=request.route_url('edit_event', sep='/',
                year=str(year), intervention=intervention, event_id=str(TheEvent.slug)))
        else:
            if slugify(TheEvent.name)!=TheEvent.slug:
                # We should move some file as slug have been changed
                # First we ensure there is no related event that already exist with that slug
                CheckEvent = Event.by_slug( unicode(slugify(TheEvent.name)), year)
                if CheckEvent:
                    request.session.flash(('warning',u'Choisissez un autre titre pour votre évènement, il est en conflit avec un autre.'))
                    return {'event':TheEvent, 'form':form, 'formAdd':formAdd, 'formAddT':formAddT, 'Salles':Salles }
                else:
                    SRCPath = path.join('jm2l/upload', *(IMAGEPATH + ['event'] + [ str(year) ] + [ TheEvent.slug ]) )
                    TheEvent.slug=unicode(slugify(TheEvent.name))
                    DSTPath = path.join('jm2l/upload', *(IMAGEPATH + ['event'] + [ str(year) ] + [ TheEvent.slug ]) )
                    if not path.isdir(path.dirname(DSTPath)):
                        makedirs(path.dirname(DSTPath))
                    # Then we should move event attachments to the new slug (if any)
                    if path.exists(SRCPath):
                        shutil.move(SRCPath, DSTPath)
                    
            DBSession.merge(TheEvent)
            request.session.flash(('sucess',u'Votre intervention a été mis à jour !'))
            return HTTPFound(location=request.route_url('edit_event', sep='/',
                year=str(year), intervention=intervention, event_id=str(TheEvent.slug)))
            
    MainTab = {'programme':'','presse':'', 'plan':'', 'participer':'',
            'event':TheEvent, 'form':form, 'formAdd':formAdd, 'formAddT':formAddT,
            'Salles':Salles }
            
    return MainTab

@view_config(route_name='entities', renderer="jm2l:templates/list_tiers.mako")
def list_tiers(request):
    Entities = dict()
    EntityType = DBSession.query(TiersOpt.entity_type)\
            .group_by(TiersOpt.entity_type).all()
    for EType in EntityType:
        Entities[EType.entity_type] = DBSession.query(Tiers).join(TiersOpt)\
            .filter(TiersOpt.entity_type==EType.entity_type)\
            .order_by(TiersOpt.entity_subtype, Tiers.name)
    MainTab = {'programme':'','presse':'', 'plan':'', 'participer':'', 
        'entities':Entities, 'logged_in':request.authenticated_userid }
    return MainTab

@view_config(route_name='show_entity', renderer="jm2l:templates/view_tiers.mako")
def show_tiers(request):
    tiers_type = request.matchdict.get('tiers_type')
    entity_id = request.matchdict.get('entity_id')
    if entity_id.isdigit():
        TheTiers = Tiers.by_id(entity_id)
        if TheTiers is None:
            raise HTTPNotFound()
    else:
        TheTiers = Tiers.by_slug(entity_id)
        if TheTiers is None:
            raise HTTPNotFound()        
    MainTab = {'programme':'','presse':'', 'plan':'', 'participer':'', 
        'entity':TheTiers, 'logged_in':request.authenticated_userid }
    return MainTab


@view_config(route_name='delete_entity')
def delete_tiers(request):
    if request.user is None:
        # Don't answer to users that aren't logged
        raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
    entity_id = request.matchdict.get('entity_id', None)
    if entity_id:
        if entity_id.isdigit():
            TheTiers = Tiers.by_id(int(entity_id))
            if TheTiers is None:
                raise HTTPNotFound()
        else:
            TheTiers = Tiers.by_slug(entity_id)
            if TheTiers is None:
                raise HTTPNotFound()
        if len(TheTiers.membership)!=0:
            request.session.flash(('error', u"Vous devez supprimer tous les membres liés avant la suppression d'une entité."))
            return HTTPFound(location=request.route_url('show_entity', entity_id=TheTiers.slug, tiers_type=TheTiers.get_entity_type.slug_entity_type))
        if len(TheTiers.membership)!=0:
            request.session.flash(('error', u"Vous devez supprimer tous les roles liés avant la suppression d'une entité."))
            return HTTPFound(location=request.route_url('show_entity', entity_id=TheTiers.slug, tiers_type=TheTiers.get_entity_type.slug_entity_type))
        DBSession.delete(TheTiers)
        request.session.flash(('info', u"L'entité a bien été supprimée"))
        return HTTPFound(location=request.route_url('entities'))
    else:
        raise HTTPNotFound()


@view_config(route_name='add_entity', renderer="jm2l:templates/edit_tiers.mako")
@view_config(route_name='edit_entity', renderer="jm2l:templates/edit_tiers.mako")
def edit_tiers(request):
    entity_id = request.matchdict.get('entity_id', None)
    TargetList = list()
    if request.user is None:
        # Don't answer to users that aren't logged
        raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
    entity_types = DBSession.query(TiersOpt.entity_type).group_by(TiersOpt.entity_type).all()
    for entity_type in entity_types:
        entity_subtypes = DBSession.query(TiersOpt)\
            .filter(TiersOpt.entity_type==entity_type.entity_type)\
            .group_by(TiersOpt.entity_subtype).all()
        ListType = [(i.uid, i.entity_subtype) for i in entity_subtypes]
        TargetList.append( (entity_type.entity_type, ListType) )
    if entity_id:
        if entity_id.isdigit():
            TheTiers = Tiers.by_id(entity_id)
            if TheTiers is None:
                raise HTTPNotFound()
        else:
            TheTiers = Tiers.by_slug(entity_id)
            if TheTiers is None:
                raise HTTPNotFound()
        form = UpdateTiersForm(request.POST,  TheTiers, meta={'csrf_context': request.session})
        UserOptions = DBSession.query(TiersOpt)\
            .filter(TiersOpt.entity_type==TheTiers.tiers_type)\
            .all()
        form.tiers_type.choices = TargetList
    else:
        TheTiers = Tiers()
        # prepare the form for creation
        form = TiersForm(request.POST, TheTiers, meta={'csrf_context': request.session})
        form.tiers_type.choices = TargetList
        UserOptions = list()

    #test_form = TiersForm(request.POST, TheTiers, meta={'csrf_context': request.session})
    if request.method == 'POST' and form.validate():
        ToDelete = list()
        ToDeleteR = list()
        # First, we remove entries no more present
        for obj in form.membership.object_data:
            MatchEntry = filter( lambda x: x.object_data and x.object_data._sa_instance_state == obj._sa_instance_state, 
                    form.membership.entries )
            if not MatchEntry:
                ToDelete.append(obj)
        # For roles too
        for obj in form.roles.object_data:
            MatchEntry = filter( lambda x: x.object_data and x.object_data._sa_instance_state == obj._sa_instance_state, 
                    form.roles.entries )
            if not MatchEntry:
                ToDeleteR.append(obj)

        # We should remove it as it's not in original data
        for obj in ToDelete:
            TheTiers.membership.remove(obj)
            DBSession.delete(obj)
        # For roles too
        for obj in ToDeleteR:
            TheTiers.roles.remove(obj)
            DBSession.delete(obj)

        # Then, it's time to consider new entries
        for entry in form.membership.entries:
            if entry.object_data is None:
                TmpUser = User_Tiers()
                entry.object_data = TmpUser
                TheTiers.membership.append(TmpUser)
                form.membership.object_data = TheTiers.membership
        # For roles too
        for entry in form.roles.entries:
            if entry.object_data is None:
                TmpRole = Role_Tiers()
                entry.object_data = TmpRole
                TheTiers.roles.append(TmpRole)
                form.roles.object_data = TheTiers.roles

        form.populate_obj(TheTiers)
        # Handle Remove of accents
        OriginalSlug = TheTiers.slug
        if not form._fields.has_key('uid'):
            TheTiers.slug = slugify(form.name.data)
            TheTiers.creator_id = request.user.uid
            DBSession.add(TheTiers)
            DBSession.flush()
            return HTTPFound(location=request.route_url('edit_entity', sep='/', 
                entity_id=str(TheTiers.slug), tiers_type=TheTiers.get_entity_type.entity_type))
        else:
            if OriginalSlug!=slugify(form.name.data):
                # We should move some file as slug have been changed
                # First we ensure there is no related event that already exist with that slug
                CheckTiers = Tiers.by_slug( slugify(form.name.data) )
                if CheckTiers:
                    request.session.flash(('warning',u'Attention, Choisissez un autre titre pour votre entitée, elle est en conflit avec une autre.'))
                    DBSession.rollback()
                    return HTTPFound(location=request.route_url('edit_entity', sep='/', 
                        entity_id=str(OriginalSlug), tiers_type=TheTiers.get_entity_type.entity_type))                    
                else:
                    TheTiers.slug = slugify(form.name.data)
                    SRCPath = path.join('jm2l/upload', *(IMAGEPATH + ['tiers'] + [ OriginalSlug ]) )
                    DSTPath = path.join('jm2l/upload', *(IMAGEPATH + ['tiers'] + [ TheTiers.slug ]) )
                    if not path.isdir(path.dirname(DSTPath)):
                        makedirs(path.dirname(DSTPath))
                    # Then we should move event attachments to the new slug (if any)
                    if path.exists(SRCPath):
                        shutil.move(SRCPath, DSTPath)

        DBSession.merge(TheTiers)
        return HTTPFound(location=request.route_url('show_entity', entity_id=TheTiers.slug,
                tiers_type=TheTiers.get_entity_type.slug_entity_type))

    MainTab = {'programme':'','presse':'', 'plan':'', 'participer':'', 
    'form':form, 'DBUser':User, 'UserOptions':UserOptions, 
    'logged_in':request.authenticated_userid }
    return MainTab 

@view_config(route_name='edit_entity_cat', renderer="jm2l:templates/edit_tiers_categ.mako")
def edit_tiers_category(request):
    if request.user is None:
        # Don't answer to users that aren't logged
        raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
    DicResult = dict()
    ListChanges = list()
    if request.method == 'POST':
        # Reformat data
        RegExist = re.compile('collection\[(?P<slug>[\w-]+)\]\[(?P<num>\d+)\]\[(?P<id>\d+)\]')
        RegTitle = re.compile('collection\[(?P<slug>[\w-]+)\]\[title]')
        RegNew   = re.compile('collection\[(?P<slug>[\w-]+)\]\[(?P<num>\d+)\]\[id\]')        
        for key, value in request.POST.iteritems():
            regN= RegNew.match(key)
            regT= RegTitle.match(key)
            reg = RegExist.match(key)                                
            if reg:
                if not DicResult.has_key(reg.group('slug')):
                    DicResult[reg.group('slug')] = dict()
                
                if DicResult[reg.group('slug')].has_key('items'):
                    DicResult[reg.group('slug')]['items'].append( ( int(reg.group('id')), value ) )
                else:
                    DicResult[reg.group('slug')]['items'] = [ ( int(reg.group('id')), value ) ]
            elif regN:
                if not DicResult.has_key(regN.group('slug')):
                    DicResult[regN.group('slug')] = dict()
                    
                if DicResult[regN.group('slug')].has_key('items'):
                    DicResult[regN.group('slug')]['items'].append( ( 'id', value ) )
                else:
                    DicResult[regN.group('slug')]['items'] = [ ( 'id', value ) ]
                ListChanges.append(('add', 0, DicResult[regN.group('slug')]['title'], value))
            elif regT:
                if not DicResult.has_key(regT.group('slug')):
                    DicResult[regT.group('slug')] = dict()
                DicResult[regT.group('slug')]['title'] = value
            else:
                raise

        for opt in DBSession.query(TiersOpt).all():
            if DicResult.has_key(opt.slug_entity_type):
                found = filter( lambda (x,y): opt.uid==x, 
                    DicResult[opt.slug_entity_type].get('items', []))
                if not found:
                    ListChanges.append(('remove', opt.uid, opt.entity_type, opt.entity_subtype))
                else:
                    for tst in found:
                        # Check changes on Cat Name
                        if DicResult[opt.slug_entity_type]['title']!=opt.entity_type or \
                            tst[1]!=opt.entity_subtype:
                            ListChanges.append(('changed', opt.uid, 
                                DicResult[opt.slug_entity_type]['title'],
                                tst[1]))
            else:
                ListChanges.append(('remove', opt.uid, opt.entity_type, opt.entity_subtype))
                
        # Do The change
        for action, uid, entity, subentity in ListChanges:
            if action=="changed":
                opt = TiersOpt.by_id(uid)
                opt.entity_type = entity
                opt.entity_subtype = subentity
            elif action=="remove":
                opt = TiersOpt.by_id(uid)
                DBSession.delete(opt)
            elif action=="add":
                opt = TiersOpt()
                opt.entity_type = entity
                opt.entity_subtype = subentity
                DBSession.add(opt)
                
    MainTab = {'programme':'','presse':'', 'plan':'', 'participer':'', 
        'logged_in':request.authenticated_userid, 'TiersOpt':TiersOpt }
    return MainTab    

@view_config(route_name='show_user', renderer="jm2l:templates/view_user.mako")
def show_user(request):
    user_slug = request.matchdict.get('user_slug', None)
    if user_slug is None or len(user_slug)==0:
        raise HTTPNotFound(u"Cet utilisateur n'a pas été reconnu")
    # Query database
    DispUser = User.by_slug(user_slug)
    if DispUser is None:
        raise HTTPNotFound()
    MainTab = {'programme':'','presse':'', 'plan':'', 'participer':'', 
        'DispUser':DispUser, 'logged_in':request.authenticated_userid }    
    return MainTab

#@view_config(route_name='link_user_entity')
def link_user_entity(request):
    if request.user is None:
        # Don't answer to users that aren't logged
        raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
    uid = int(request.matchdict.get('uid', -1))
    year = int(request.matchdict.get('year', -1))
    user_id = int(request.matchdict.get('uid', -1))
    TheTiers = Tiers.by_id(uid)
    if TheTiers is None:
        raise HTTPNotFound()
    return HTTPFound(location=request.route_url('edit_entity', uid=uid) )
            
#@view_config(route_name='link_role_entity')
def link_role_entity(request):
    if request.user is None:
        # Don't answer to users that aren't logged
        raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
    uid = int(request.matchdict.get('uid', -1))
    year = int(request.matchdict.get('year', -1))   
    role_id = int(request.matchdict.get('role_id', -1))
    TheTiers = Tiers.by_id(uid)
    if TheTiers is None:
        raise HTTPNotFound()
    return HTTPFound(location=request.route_url('edit_entity', uid=uid) )    

@forbidden_view_config()
def forbidden(reason, request):
    if 'ident' in reason.detail:
        request.session.flash(('info', reason.detail))
        return HTTPFound(location='/sign/login?from='+request.environ['PATH_INFO']  )
    else:
        request.response.status = 403
        return render_to_response('jm2l:templates/Errors/403.mako', { "reason":reason },
            request=request)

@notfound_view_config()
def notfound(reason, request):
    request.response.status = 404
    return render_to_response('jm2l:templates/Errors/404.mako', { "reason":reason },
        request=request)
    
