#!/usr/bin/python
# -*- coding: utf-8 -*-

#            DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
#                  Version 2, December 2004
#
# Copyright (C) 2010 François Poulain <fpoulain@metrodore.fr>
#
# Everyone is permitted to copy and distribute verbatim or modified
# copies of this license document, and changing it is allowed as long
# as the name is changed.
#
#            DO WHAT THE FUCK YOU WANT TO PUBLIC LICENCE
#   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
#
#  0. You just DO WHAT THE FUCK YOU WANT TO.




# Ce script traite les logs IRC des revues hebdo ; pour faciliter la
# digestion. Voir https://redmine.april.org/issues/135
#
# Le programme est conçu pour parser les logs de madix selon leur format
# particulier. Il prends le log sur l'entrée standard et sort sur la sortie
# standard. Si tu veux mettre un chemin de fichier en entrée, ça se passe au
# début du code, il y a un exemple commenté.
#
# Il y a trois modalités de contrôle en ligne :
# * commentaire : si quelqu'un veut écrire un truc qui ne soit pas
#   passé en revue, il commence par un %.
#   Exemple : <madix> % quand vous avez fini vous le dites
#             <liot_> % fini
#
# * directive de revue individuelle : avec un #, tu annonces un
#   changement d'état dans la revue. Les messages qui suivent
#   sont traités/triés individuellement. Les états sont créés
#   individuellement lorsqu'il y a un contenu associé à stocker.
#   Exemple : <madix> # 2/ Action passées
#
# * directive de revue globale : avec un ##, tu annonces un
#   changement d'état dans la revue. Les messages qui suivent
#   sont traités/triés collectivement. Les états sont créés
#   uniquement lorsqu'il y a un contenu associé à stocker.
#   Exemple : <madix> ## 3/ Point bloquants existants ou levés 
#                     récemment
# 
# Les directives ne sont interprétées que pour le conducteur de la
# réunion, défini dans le code. Pour des raisons de fainéantise, elles
# sont triées alphanumériquement ; donc il vaut mieux les numéroter.
#
# L'affichage est factorisé dans 3 méthodes title(), subTitle() et
# subSubTitle() ; pour modifier facilement aux gouts de chacun.
#
# Le code intègre un dictionnaire pseudo -> nom.



import re, sys, textwrap

######### Conducteur de la revue : celui qui envoit les directives ########
conducteur = 'madix'

####################### Dictionnaire peudo / nom ##########################

def pseudo2nom(pseudo):
	noms = {
		'liot_'			: 'Lionel Allorge',
		'liot'			: 'Lionel Allorge',
		'Armony'		: 'Armony Altinier',
		'kult' 			: 'Tony Bassette',
		'raceme'		: 'Christophe Boyanique',
		'PetiPandaRou'		: 'Julia Buchner',
		'PetiPandaRou1'		: 'Julia Buchner',
		'echarp'		: 'Emmanuel Charpentier',
		'aurelia'		: 'Aurélia Gilardi',
		'Luk_'		: 'Luc Fievet',
		'Remaille'		: 'Rémi Boulle',
		'teymour'		: 'Tangui Morlier',
		'coin_p'		: 'Marc Chauvet',
		'coin_pan'		: 'Marc Chauvet',
		'coin_pan_'		: 'Marc Chauvet',
		'lcosty'		: 'Laurent Costy',
		'Flache-Gore-Donn'		: 'Laurent Costy',
                'theocrite'             : 'theocrite',
		'cnestel'		: 'Charlie Nestel',
		'madix'			: 'Frédéric Couchet',
		'madix`'		: 'Frédéric Couchet',
		'dachary'		: 'Loïc Dachary',
		'mmu_man'		: 'François Revol',
		'benj'			: 'Benjamin Drieu',
		'bookynette'		: 'Magali Garnero',
		'Bookynette'		: 'Magali Garnero',
		'BookyPaNette'		: 'Magali Garnero',
		'Siltaar'		: 'Simon Descarpentries',
		'ave'			: 'Eva Mathieu',
		'ave1'			: 'Eva Mathieu',
		'_PoluX_'		: 'François Poulain',
		'_PoLuX_'		: 'François Poulain',
		'gibus'			: 'Gérald Sédrati-Dinet',
		'gibus_at_office'	: 'Gérald Sédrati-Dinet',
		'leobaillard'	: 'Léopold Baillard',
		'janchou'		: 'Jeanne Tadeusz',
	}
	if pseudo in set(noms): return noms[pseudo] + ' <' + pseudo + '>'
	else: return '<' + pseudo + '>'

###########################################################################

# log_brut = open('/tmp/20100806-log-irc-revueIndividuelle-hebdomadaire.txt').read()
log_brut = sys.stdin.read()

################## Filtrage du log, sortie dans une liste #################

# Nettoyage syntaxe + horodatage + notification
aSupprimer = re.compile(
	r'\*\*\*.*?(#april|has quit.*?|is now known as.*?)$'
	r'|'
	r' {2,}'
	r'|'
	r'\[\d\d:\d\d\]'
	r'|'
	r'\[\d\d/\d\d/\d\d \d\d:\d\d\]'
	r'|'
	r'^\s?\*\s?'
	,re.MULTILINE|re.DOTALL)
log = aSupprimer.sub('',log_brut)

aSubstituer = re.compile(r'\n+|\s+')
log = aSubstituer.sub(' ',log)

# Concatenation/découpe des pseudo/propos 
pseudo = re.compile(r'(<[^ >]*?>)')

log = pseudo.split(log)

# Supression des éventuelles puces et espaces de début et fin de ligne
puce = re.compile(r'^\s?\*?\s?|\s?$')
for phrase in log:
	log[log.index(phrase)] = re.sub(puce, '', phrase)

# Retrait des éventuelles lignes vides
while log.count(''): log.remove('')

################ Parsage du log, stockage en dictionnaire #################

# Regexps pour la reconnaissance des motifs
pseudo = re.compile(r'<([^ >]*?)>')
directive = re.compile(r'^\s?\#\#?\s?')
directiveIndividuelle = re.compile(r'^\s?\#[^#]\s?')
commentaire = re.compile(r'^\s?\%\s?')

# Drapeaux pour le traitement individuel/collectif
individuel = False

# Instantiation des revues
revueIndividuelle = {}
revueCollective = {}

directiveCourante = 'Indéfini'
parleur = 'John Doe' # normalement inutile

# Nombre de colonnes pour l'affichage
text_width = 72

print '\n', '  Commentaires (pour vérification)  '.center(text_width, '='), '\n'

for line in log:
	# Si on a affaire à un pseudo
 	if re.match(pseudo,line): 
 		parleur = re.match(pseudo,line).group(1)

	# Si on a affaire à une directive proposée par le dictateur
	elif re.match(directive, line) and parleur == conducteur:
		# Collective ?
		individuel = True
		if not re.match(directiveIndividuelle, line):
			individuel = False

		# Individuelle ?
		directiveCourante = re.sub(directive, '', line)

	# Si on a affaire à un commentaire
	elif re.match(commentaire, line):
		print parleur, ' : ', line # Affiché pour contrôle visuel

	# Sinon il s'agit d'une entrée à stocker
	else:
		# Traitement individuel ?
		if individuel:
			# Les nouveaux intervenants sont instanciés
			if parleur not in set(revueIndividuelle):
				revueIndividuelle[parleur] = {}
			
			# Les nouveaux états sont instanciés
			if directiveCourante not in set(revueIndividuelle[parleur]):
				revueIndividuelle[parleur][directiveCourante] = []

			# Stockage de la ligne dans la revueIndividuelle
			revueIndividuelle[parleur][directiveCourante].append(line)

		# Sinon : traitement collectif
		else:
			# Les nouveaux états sont instanciés
			if directiveCourante not in set(revueCollective):
				revueCollective[directiveCourante] = []

			# Stockage de la ligne dans la revueCollective
			revueCollective[directiveCourante].append(parleur + ' : ' + line)

##############################  Affichage  ##############################

# Regexp pour les énumérations
enumeration = re.compile(r'^\s?\d?\/?\s?')

# Procedures d'affichage

def separateur():
	print '\n', ''.center(text_width, '=')

def title(texte):
	separateur()
	print texte.center(text_width)
	print ''.center(text_width, '=')
	print ''

def subTitle(texte):
	separateur()
	print ''
	print (' ' + texte + ' ').center(text_width,'-')

def subSubTitle(texte):
	print '\n=== ', texte, ' ==='
	print ''

# Si le conducteur est mal déclaré
if directiveCourante == 'Indéfini':
	separateur()
	print ''
	print textwrap.fill('La réunion n\'a visiblement pas été conduite. Cela peut venir '+
			'd\'un problème de formatage de log IRC, ou bien simplement parce '+
			'que le conducteur déclaré dans le code est erroné. Êtes vous sur '+
			'que le conducteur de la réunion est ' + conducteur + ' ? Vous '+
			'pouvez changer ça dans le code revue.py, en éditant la ligne 62.', text_width)
	separateur()
	exit()

# Affichage des puces

wrapper = textwrap.TextWrapper()
wrapper.initial_indent = "* "
wrapper.subsequent_indent = "  "
wrapper.width = text_width

def printPuce(texte):
	print wrapper.fill(texte)

title('  Revue de la semaine en cours ')

# Liste des participants
subTitle('Participants')
people = ''
participants = sorted(revueIndividuelle.keys(), reverse = True)
if len(participants) > 0:
	while len(participants) > 1: 
		people += '* ' + pseudo2nom(participants.pop()) + ',\n'
	people += '* ' + pseudo2nom(participants.pop()) + '.'
	print people

# Revue individuelle
for participant in revueIndividuelle:
	subTitle(pseudo2nom(participant))
	for directive in sorted(revueIndividuelle[participant]):
		subSubTitle(re.sub(enumeration, '', directive))
		for puce in revueIndividuelle[participant][directive]:
			printPuce(puce)

# Revue collective : passe les états sauf celui indéfini
for directive in sorted(set(revueCollective) - set(['Indéfini'])):
	title(re.sub(enumeration, '', directive))
	for puce in revueCollective[directive]:
		printPuce(puce)

# Passe l'état indéfini
if 'Indéfini' in set(revueCollective):
	print '\n', '  Indéfini  '.center(text_width, '='), '\n'
	for puce in set(revueCollective['Indéfini']):
		printPuce(puce)

title('Log IRC brut')

print log_brut
