#!/usr/bin/python
# -*- coding:utf8 -*-

# Codé par 20-100 le 25/05/12

# Un bot IRC qui pose des questions d'histoire

import irclib
import ircbot
import threading
import random
import time
import pickle
import re
from cast_as_date import *

config_password="EtTaMère,ElleEstNéeQuand?"
config_pseudo="historien"
config_chanlist=["#bot","#flood"]
config_play_channels=["#flood"]
config_stay_channels=["#flood","#bot"]
config_overops=["[20-100]","[20-100]_"]
config_ops=["PEB","Petite-Peste"]

config_source_file="dates.txt"
config_played_file_template="played.%s.txt" #il faut rajouter le nom du serveur
def get_config_played_file(serveur):
    serveurs={"acoeur.crans.org":"acoeur","irc.crans.org":"crans"}
    return config_played_file_template%(serveurs[serveur])
ttrig=120 #time trigger (normalement 120, mais diminué pour les tests)
Ttrig=600 #between two enigms
config_time_incompressible=15 #on peut pas retrigger en dessous de ce temps (60)
config_time_incompressible_clue=60 #on peut pas forcer la demande d'indice en dessous

config_score_file="scores.pickle"

config_tag_triggers=[u"t(|a)g",u"ta gueule",u"la ferme",u"ferme( |-)la",u"tais-toi",u"chut"]
config_tag_actions=[u"se tait",u"ferme sa gueule",u"se la ferme",u"la ferme"]
config_tag_answers=[u"J'me tais si j'veux !",
u"Je t'entends pas :°",
u"Héhé, try again",
u"Non, j'ai pas envie",
u"Peut-être quand toi tu la fermeras, et encore…"]

config_level2=[]
config_level3=[]

config_debug_stdout = True
config_logfile_template="historien.%s.log"
def get_config_logfile(serveur):
    serveurs={"acoeur.crans.org":"acoeur","irc.crans.org":"crans"}
    return config_logfile_template%(serveurs[serveur])

config_quit_messages=[u"%s : %s quitte le serveur IRC"]

config_leave_messages=[u"%s : %s quitte le channel"]

# Quand personne ne cause, on finit par se taire
# temps au bout duquel, si personne n'a parlé, on se tait
config_idle_time=20*60
# liste des bots, qui ne sont pas considérés comme de l'activité
config_idle_bots=["deconnaisseur","Basile","historien","hung","salesman","Shadobot","Wen","___","Sanctuary"]

class UnicodeBotError(Exception):
    pass
def bot_unicode(chain):
    try:
        unicode(chain,"utf8")
    except UnicodeDecodeError:
        raise UnicodeBotError

def log(serveur,channel,auteur=None,message=None):
    f=open(get_config_logfile(serveur),"a")
    if auteur==message==None:
        # alors c'est que c'est pas un channel mais juste une ligne de log
        chain="%s %s"%(time.strftime("%F %T"),channel)
    else:
        chain="%s [%s:%s] %s"%(time.strftime("%F %T"),channel,auteur,message)
    f.write(chain+"\n")
    if config_debug_stdout:
        print chain
    f.close()


config_score_annee=1
config_score_mois=3
config_score_jour=4

config_noscore=["[20-100]","[20-100]_"] # parce que 20-100 est nul en histoire

class GoodCentury(Exception):
    pass

class GoodDeceny(Exception):
    pass

def reussi(message,answer,auteur):
    if auteur in config_level3:
        return answer in message
    if auteur in config_level2:
        return answer in message
    else:
        try:
            date=cast_as_date(message.lower().strip())
        except ThisIsNotADate:
            return False
        realdate=map(lambda x:int(x), answer.split('/'))
        realdate.reverse()
        score=0
        if date[0]==realdate[0]:
            score=config_score_annee
            if date[1]==realdate[1]:
                score+=config_score_mois
                if date[2]==realdate[2]:
                    score+=config_score_jour
        elif date[0]/10 == realdate[0]/10:
            raise GoodDeceny
        elif date[0]/100 == realdate[0]/100:
            raise GoodCentury
        return score

def is_something(chain,matches,avant=u".*(?:^| )",apres=u"(?:$|\.| |,|;).*",case_sensitive=False,debug=False):
    if case_sensitive:
        chain=unicode(chain,"utf8")
    else:
        chain=unicode(chain,"utf8").lower()
    allmatches="("+"|".join(matches)+")"
    reg=(avant+allmatches+apres).lower()
    o=re.match(reg,chain)
    return o

def is_tag(chain):
    return is_something(chain,config_tag_triggers)

class RefuseError(Exception):
    pass

class Historien(ircbot.SingleServerIRCBot):
    def __init__(self,serveur,debug=False):
        temporary_pseudo=config_pseudo+str(random.randrange(10000,100000))
        ircbot.SingleServerIRCBot.__init__(self, [(serveur, 6667)],
                                      temporary_pseudo,"Un bot irc qui a au moins l'agreg d'histoire", 10)
        self.debug=debug
        self.serveur=serveur
        self.overops=config_overops
        self.ops=self.overops+config_ops
        self.chanlist=config_chanlist
        self.stay_channels=config_stay_channels
        self.play_channels=config_play_channels
        self.play_status={i:[0] for i in self.play_channels}
        self.last_activity={}
        self.quiet_channels=[]

    def give_me_my_pseudo(self,serv):
        serv.privmsg("NickServ","RECOVER %s %s"%(config_pseudo,config_password))
        serv.privmsg("NickServ","RELEASE %s %s"%(config_pseudo,config_password))
        time.sleep(0.3)
        serv.nick(config_pseudo)
    
    def on_welcome(self, serv, ev):
        self.serv=serv # ça serv ira :)
        self.give_me_my_pseudo(serv)
        serv.privmsg("NickServ","identify %s"%(config_password))
        log(self.serveur,"Connected")
        if self.debug:
            self.chanlist=["#bot"]
            self.play_channels=["#bot"]
        for c in self.chanlist:
            log(self.serveur,"JOIN %s"%(c))
            serv.join(c)
            self.update_activity(c,"") # la chaîne vide ne sera jamais un nom de bot et donc marchera toujours
        for c in self.play_channels:
            token=time.time()-3600
            self.play_status[c]=[0,token]
            serv.execute_delayed(random.randrange(ttrig),self.start_enigme,(serv,c,token))

    def start_enigme(self,serv,channel,token=None):
        # On reste silencieux si lechan n'est pas actif
        if not self.is_active(channel):
            serv.execute_delayed(ttrig*5,self.start_enigme,(serv,channel,token))
            return
        if self.play_status[channel][0]==0 and channel in self.play_channels:
            ok="skip"
            if token==self.play_status[channel][-1]:
                ok="do_it"
            if token==None:
                if time.time() > self.play_status[channel][-1]+config_time_incompressible:
                    ok="do_it"
                else:
                    ok="refuse"
            if ok=="do_it":
                date,evenement=self.get_enigme()
                log(self.serveur,channel,u"$Date$".encode("utf8"),("%s : %s"%(date, evenement)).encode("utf8"))
                serv.privmsg(channel,evenement.encode("utf8"))
                token=time.time()
                # le 0 est le flag "bon siècle" n'a pas encore été dit
                self.play_status[channel]=[1,date,evenement,0,token]
                serv.execute_delayed(random.randrange(ttrig*3,ttrig*5),self.give_indice,(serv,channel,token))
            elif ok=="refuse":
                raise RefuseError
    def give_indice(self,serv,channel,token):
        if self.play_status[channel][0]==1:
            if token==None:
                # c'est donc que l'indice a été demandé
                if self.play_status[channel][-1]+config_time_incompressible_clue<time.time():
                    token=self.play_status[channel][-1]
            if self.play_status[channel][-1]==token:
                date=self.play_status[channel][1]
                indice=date[:5]
                serv.privmsg(channel,"indice : %s"%(indice).encode("utf8"))
                self.play_status[channel][0]=2
                serv.execute_delayed(random.randrange(ttrig*1,ttrig*3),self.give_answer,(serv,channel,token))
    def give_answer(self,serv,channel,token):
        if self.play_status[channel][0]==2 and self.play_status[channel][-1]==token:
            date=self.play_status[channel][1]
            serv.privmsg(channel,"C'était le %s"%(date).encode("utf8"))
            token=time.time()
            self.play_status[channel]=[0,token]
            serv.execute_delayed(random.randrange(Ttrig*5,Ttrig*10),self.start_enigme,(serv,channel,token))

    def get_enigme(self):
        # on récupère les dates
        f=open(config_source_file)
        l=f.readlines()
        f.close()
        l=[i.split(" : ",2) for i in l]
        dates={int(i[0]):i[1:] for i in l}
        # on va chercher combien de fois elles ont été jouées
        played_file=get_config_played_file(self.serveur)
        f=open(played_file)
        t=f.read()
        f.close()
        l=re.findall("(.*):(.*)",t)
        played={int(i[0]):int(i[1]) for i in l}
        # on récupère le nombre d'occurrences le plus faible
        mini=min(played.values())
        # on choisit un id dans ceux qui ont ce nombre d'occurences
        id_choisi=random.choice([k for k,v in played.items() if v==mini])
        date,evenement=dates[id_choisi]
        evenement=evenement.replace("\n","")
        # on incrémente la choisie
        played[id_choisi]+=1
        # on enregistre le played_file
        f=open(played_file,"w")
        f.write("\n".join(["%-4s : %s"%(k,v) for k,v in played.items()]))
        f.close()
        return map(lambda x:x.decode("utf8"), [date,evenement])

    def pourmoi(self, serv, message):
        pseudo=self.nick
        size=len(pseudo)
        if message[:size]==pseudo and len(message)>size and message[size]==":":
            return (True,message[size+1:].strip(" "))
        else:
            return (False,message)

    def on_privmsg(self, serv, ev):
        message=ev.arguments()[0]
        auteur = irclib.nm_to_n(ev.source())
        try:
            test=bot_unicode(message)
        except UnicodeBotError:
            serv.privmsg(auteur,
              "Euh, tu fais de la merde avec ton encodage là, j'ai failli crasher…")
            return
        message=message.split()
        cmd=message[0].lower()
        notunderstood=False
        if cmd=="help":
            helpmsg_default="""Liste des commandes :
 HELP       Affiche ce message d'aide
 SCORE      Affiche ton score (SCORE TRANSFERT <pseudo> [<n>] pour transférer des points)
 SCORES     Affiche les scores"""
            helpmsg_ops="""
 JOIN       Faire rejoindre un channel (sans paramètres, donne la liste des chans actuels)
 LEAVE      Faire quitter un channel
 PLAY       Passe un channel en mode "jouer"
 NOPLAY     Passe un channel en mode "ne pas jouer"
 QUIET      Se taire sur un channel
 NOQUIET    Opposé de QUIET"""
            helpmsg_overops="""
 SCORES {DEL|ADD|SUB}   Tu veux un dessin ?
 SAY        Fais envoyer un message sur un chan ou à une personne
 STAY       Ignorera les prochains LEAVE pour un chan
 NOSTAY     Opposé de STAY
 STATUS     Montre l'état courant
 DIE        Mourir"""
            helpmsg=helpmsg_default
            if auteur in self.ops:
                helpmsg+=helpmsg_ops
            if auteur in self.overops:
                helpmsg+=helpmsg_overops
            for ligne in helpmsg.split("\n"):
                serv.privmsg(auteur,ligne)
        elif cmd=="join":
            if auteur in self.ops:
                if len(message)>1:
                    if message[1] in self.chanlist:
                        serv.privmsg(auteur,"Je suis déjà sur %s"%(message[1]))
                    else:
                        serv.join(message[1])
                        self.chanlist.append(message[1])
                        serv.privmsg(auteur,"Channels : "+" ".join(self.chanlist))
                        log(self.serveur,"priv",auteur," ".join(message))
                else:
                    serv.privmsg(auteur,"Channels : "+" ".join(self.chanlist))
            else:
                notunderstood=True
        elif cmd=="leave":
            if auteur in self.ops and len(message)>1:
                if message[1] in self.chanlist:
                    if not (message[1] in self.stay_channels) or auteur in self.overops:
                        self.quitter(message[1]," ".join(message[2:]))
                        self.chanlist.remove(message[1])
                        log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
                    else:
                        serv.privmsg(auteur,"Non, je reste !")
                        log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
                else:
                    serv.privmsg(auteur,"Je ne suis pas sur %s"%(message[1]))
            else:
                notunderstood=True
        elif cmd=="stay":
            if auteur in self.overops:
                if len(message)>1:
                    if message[1] in self.stay_channels:
                        serv.privmsg(auteur,"Je stay déjà sur %s."%(message[1]))
                        log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
                    else:
                        self.stay_channels.append(message[1])
                        serv.privmsg(auteur,"Stay channels : "+" ".join(self.stay_channels))
                        log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
                else:
                    serv.privmsg(auteur,"Stay channels : "+" ".join(self.stay_channels))
            else:
                notunderstood=True
        elif cmd=="nostay":
            if auteur in self.overops:
                if len(message)>1:
                    if message[1] in self.stay_channels:
                        self.stay_channels.remove(message[1])
                        serv.privmsg(auteur,"Stay channels : "+" ".join(self.stay_channels))
                        log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
                    else:
                        serv.privmsg(auteur,"Je ne stay pas sur %s."%(message[1]))
                        log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
            else:
                notunderstood=True
        elif cmd=="play":
            if auteur in self.ops:
                if len(message)>1:
                    if message[1] in self.play_channels:
                        serv.privmsg(auteur,"Je play déjà sur %s."%(message[1]))
                        log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
                    else:
                        self.play_channels.append(message[1])
                        self.play_status[message[1]]=[0,time.time()-3600]
                        serv.privmsg(auteur,"Play channels : "+" ".join(self.play_channels))
                        log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
                else:
                    serv.privmsg(auteur,"Play channels : "+" ".join(self.play_channels))
            else:
                notunderstood=True
        elif cmd=="noplay":
            if auteur in self.ops:
                if len(message)>1:
                    if message[1] in self.play_channels:
                        self.play_channels.remove(message[1])
                        serv.privmsg(auteur,"Play channels : "+" ".join(self.play_channels))
                        log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
                    else:
                        serv.privmsg(auteur,"Je ne play pas sur %s."%(message[1]))
                        log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
            else:
                notunderstood=True
        elif cmd=="quiet":
            if auteur in self.ops:
                if len(message)>1:
                    if message[1] in self.quiet_channels:
                        serv.privmsg(auteur,"Je me la ferme déjà sur %s"%(message[1]))
                        log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
                    else:
                        self.quiet_channels.append(message[1])
                        serv.privmsg(auteur,"Quiet channels : "+" ".join(self.quiet_channels))
                        log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
                else:
                    serv.privmsg(auteur,"Quiet channels : "+" ".join(self.quiet_channels))
            else:
                notunderstood=True
        elif cmd=="noquiet":
            if auteur in self.ops:
                if len(message)>1:
                    if message[1] in self.quiet_channels:
                        self.quiet_channels.remove(message[1])
                        serv.privmsg(auteur,"Quiet channels : "+" ".join(self.quiet_channels))
                        log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
                    else:
                        serv.privmsg(auteur,"Je ne me la ferme pas sur %s."%(message[1]))
                        log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
            else:
                notunderstood=True
        elif cmd in ["states","status"]:
            if auteur in self.overops:
                for k in self.play_status.keys():
                    serv.privmsg(auteur,(u"%s : %s"%(k," | ".join([unicode(i) for i in self.play_status[k]]))).encode("utf8") )
        elif cmd=="say":
            if auteur in self.overops and len(message)>2:
                serv.privmsg(message[1]," ".join(message[2:]))
                log(self.serveur,"priv",auteur," ".join(message))
            elif len(message)<=2:
                serv.privmsg(auteur,"Syntaxe : SAY <channel> <message>")
            else:
                notunderstood=True
        elif cmd=="die":
            if auteur in self.overops:
                log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
                self.mourir()
        elif cmd=="score":
            if len(message)>1:
                if len(message) in [3,4] and message[1].lower()=="transfert":
                    scores=self.get_scores()
                    de,to=auteur,message[2]
                    value=scores.get(de,0)
                    if len(message)==4:
                        try:
                            asked=int(message[3])
                        except ValueError:
                            serv.privmsg(auteur,"Syntaxe : SCORE TRANSFERT <pseudo> [<n>]")
                            return
                    else:
                        asked=value
                    if value==0:
                        serv.privmsg(auteur,"Vous n'avez pas de points")
                        return
                    elif asked<=0:
                        serv.privmsg(auteur,"Bien tenté…")
                        return
                    elif asked>value:
                        serv.privmsg(auteur,"Vous n'avez que %s points"%(value))
                        return
                    else:
                        self.add_score(de,-asked)
                        self.add_score(to,asked)
                        serv.privmsg(auteur,"Transfert de %s points de %s à %s"%(asked,de,to))
                else:
                    serv.privmsg(auteur,"Syntaxe : SCORE TRANSFERT <pseudo> [<n>]")
            else:
                serv.privmsg(auteur,"Votre score : %s"%(self.get_scores().get(auteur,0)) )
        elif cmd=="scores":
            if len(message)==1:
                scores=self.get_scores().items()
                # trie par score
                scores.sort(lambda x,y:cmp(x[1],y[1]))
                scores.reverse()
                serv.privmsg(auteur,"Scores by score : "+" ; ".join(["%s %s"%(i[0],i[1]) for i in scores]))
                # trie par pseudo
                scores.sort(lambda x,y:cmp(x[0].lower(),y[0].lower()))
                serv.privmsg(auteur,"Scores by pseudo : "+" ; ".join(["%s %s"%(i[0],i[1]) for i in scores]))
            elif auteur in self.overops:
                souscmd=message[1].lower()
                if souscmd=="del":
                    if len(message)==3:
                        todelete=message[2]
                        scores=self.get_scores()
                        if scores.has_key(todelete):
                            del scores[todelete]
                            self.save_scores(scores)
                            serv.privmsg(auteur,"Score de %s supprimé"%(todelete))
                        else:
                            serv.privmsg(auteur,"Ce score n'existe pas : %s"%(todelete))
                    else:
                        serv.privmsg(auteur,"Syntaxe : SCORES DEL <pseudo>")
                elif souscmd in ["add","sub"]:
                    if len(message)==4:
                        toadd,val=message[2],message[3]
                        try:
                            val=int(val)
                        except ValueError:
                            serv.privmsg(auteur,"Syntaxe : SCORES {ADD|SUB} <pseudo> <n>")
                            return
                        if souscmd=="sub":
                            val=-val
                        self.add_score(toadd,val)
                        serv.privmsg(auteur,"Done")
                    else:
                        serv.privmsg(auteur,"Syntaxe : SCORES {ADD|SUB} <pseudo> <n>")
                else:
                    serv.privmsg(auteur,"Syntaxe : SCORES {DEL|ADD|SUB} <pseudo> [<n>]")
            else:
                notunderstood=True
        else:
            notunderstood=True
        if notunderstood:
            serv.privmsg(auteur,"Je n'ai pas compris. Essaye HELP…")
    
    def on_pubmsg(self, serv, ev):
        auteur = irclib.nm_to_n(ev.source())
        canal = ev.target()
        message = ev.arguments()[0]
        self.update_activity(canal,auteur)
        try:
            test=bot_unicode(message)
        except UnicodeBotError:
            if not canal in self.quiet_channels:
                serv.privmsg(canal,
                   "%s: Euh, tu fais de la merde avec ton encodage là, j'ai failli crasher…"%(auteur))
            return
        tryother=False
        pour_moi,message=self.pourmoi(serv,message)
        if pour_moi and message.split()!=[]:
            cmd=message.split()[0].lower()
            try:
                args=" ".join(message.split()[1:])
            except:
                args=""
            if cmd in ["meurs","die","crève"]:
                if auteur in self.overops:
                    self.mourir()
                    log(self.serveur,canal,auteur,message+"[successful]")
                else:
                    serv.privmsg(canal,"%s: crève !"%(auteur))
                    log(self.serveur,canal,auteur,message+"[failed]")
            if cmd in ["meur", "meurt","meurre","meurres"] and not canal in self.quiet_channels:
                serv.privmsg(canal,'%s: Mourir, impératif, 2ème personne du singulier : "meurs" (de rien)'%(auteur))
            if cmd in ["part","leave","dégage"]:
                if auteur in self.ops and (not (canal in self.stay_channels)
                                           or auteur in self.overops):
                    self.quitter(canal)
                    log(self.serveur,canal,auteur,message+"[successful]")
                    self.chanlist.remove(canal)
                else:
                    serv.privmsg(canal,"%s: Non, je reste !"%(auteur))
                    log(self.serveur,canal,auteur,message+"[failed]")
    
            if cmd in ["deviens","pseudo"]:
                if auteur in self.ops:
                    become=args
                    serv.nick(become)
                    log(self.serveur,canal,auteur,message+"[successful]")
            if cmd in ["coucou"] and not canal in self.quiet_channels:
                serv.privmsg(canal,"%s: coucou"%(auteur))
            if cmd in ["ping"] and not canal in self.quiet_channels:
                serv.privmsg(canal,"%s: pong"%(auteur))
            if cmd in ["date","dates","histoire","énigme","enigme","encore"]:
                if canal in self.play_channels:
                    if self.play_status.get(canal,[-1])[0]==0:
                        try:
                            self.start_enigme(serv,canal)
                        except RefuseError:
                            serv.privmsg(canal,"%s: Je peux souffler une minute ?"%(auteur))
                    else:
                        serv.privmsg(canal,("%s: Rappel : %s"%(auteur,self.play_status[canal][2])).encode("utf8") )
                else:
                    serv.privmsg(canal,"%s: pas ici…"%(auteur))
            if cmd in ["score","!score"]:
                serv.privmsg(auteur,"Votre score : %s"%(self.get_scores().get(auteur,0)) )
            if cmd in ["scores","!scores"]:
                scores=self.get_scores().items()
                # trie par score
                scores.sort(lambda x,y:cmp(x[1],y[1]))
                scores.reverse()
                serv.privmsg(auteur,"Scores by score : "+" ; ".join(["%s %s"%(i[0],i[1]) for i in scores]))
                # trie par pseudo
                scores.sort(lambda x,y:cmp(x[0].lower(),y[0].lower()))
                serv.privmsg(auteur,"Scores by pseudo : "+" ; ".join(["%s %s"%(i[0],i[1]) for i in scores]))
            if cmd=="indice" and canal in self.play_channels:
                self.give_indice(serv,canal,None)
            if is_tag(message) and not canal in self.quiet_channels:
                if auteur in self.ops:
                    action=random.choice(config_tag_actions)
                    serv.action(canal,action.encode("utf8"))
                    self.quiet_channels.append(canal)
                else:
                    answer=random.choice(config_tag_answers)
                    for ligne in answer.split("\n"):
                        serv.privmsg(canal,"%s: %s"%(auteur,ligne.encode("utf8")))
            else:
                tryother=True
        else:
            tryother=True
        if tryother:
            if self.play_status.get(canal,[-1])[0] in [1,2]:
                answer=self.play_status[canal][1]
                flag_century=self.play_status[canal][3]
                try:
                    score_obtenu=reussi(message.decode("utf8"),answer,auteur)
                except GoodCentury:
                    if not flag_century:
                        serv.privmsg(canal,"%s: C'est le bon siècle, mais pas la bonne année, cherche encore ;)"%(auteur))
                        self.play_status[canal][3]=1
                    return
                except GoodDeceny:
                    if flag_century in [0,1]:
                        serv.privmsg(canal,"%s: C'est la bonne décennie, mais pas la bonne année, encore un effort ;)"%(auteur))
                        self.play_status[canal][3]=2
                    return
                if score_obtenu:
                    if self.play_status[canal][0]==1:
                        bonusmsg=u" [+bonus_mois"*(score_obtenu>config_score_annee)+u"+bonus_jour"*(score_obtenu>config_score_annee+config_score_mois)
                    else:
                        bonusmsg=""
                        score_obtenu=1
                    if bonusmsg:
                        bonusmsg+=u"]"
                    serv.privmsg(canal,(u"%s: bravo ! (C'était le %s)%s"%(auteur,answer,bonusmsg)).encode("utf8"))
                    log(self.serveur,canal,auteur+"$win",message)
                    if auteur in config_noscore:
                        score_obtenu=0
                    self.add_score(auteur,score_obtenu)
                    token=time.time()
                    self.play_status[canal]=[0,token]
                    serv.execute_delayed(random.randrange(Ttrig*5,Ttrig*10),self.start_enigme,(serv,canal,token))
    
    def on_kick(self,serv,ev):
        auteur = irclib.nm_to_n(ev.source())
        channel = ev.target()
        victime = ev.arguments()[0]
        raison = ev.arguments()[1]
        if victime==self.nick:
            log(self.serveur,"%s kické de %s par %s (raison : %s)" %(victime,channel,auteur,raison))
            time.sleep(5)
            serv.join(channel)
            self.update_activity(channel,"")
            # on ne dit rien au rejoin
            #l1,l2=config_kick_answers,config_kick_actions
            #n1,n2=len(l1),len(l2)
            #i=random.randrange(n1+n2)
            #if i>=n1:
            #    serv.action(channel,l2[i-n1].format(auteur).encode("utf8"))
            #else:
            #    serv.privmsg(channel,l1[i].format(auteur).encode("utf8"))
    
    def quitter(self,chan,leave_message=None):
        if leave_message==None:
            leave_message=random.choice(config_leave_messages)
        try:
            leave_message=leave_message%(time.strftime("le %d/%m/%Y à %T").decode("utf8"),self.nick)
        except:
            pass
        self.serv.part(chan,message=leave_message.encode("utf8"))
    
    def mourir(self):
        quit_message=random.choice(config_quit_messages)
        try:
            quit_message=quit_message%(time.strftime("le %d/%m/%Y à %T").decode("utf8"),self.nick)
        except:
            pass
        self.die(msg=quit_message.encode("utf8"))
    
    def get_scores(self):
        f=open(config_score_file)
        scores=pickle.load(f)
        f.close()
        return scores

    def add_score(self,pseudo,value):
        scores=self.get_scores()
        if scores.has_key(pseudo):
            scores[pseudo]+=value
        else:
            scores[pseudo]=value
        self.save_scores(scores)

    def save_scores(self,scores):
        f=open(config_score_file,"w")
        pickle.dump(scores,f)
        f.close()
    
    def _getnick(self):
        return self.serv.get_nickname()
    nick = property(_getnick)
    
    def update_activity(self,canal,pseudo):
        if not pseudo in config_idle_bots:
            self.last_activity[canal]=time.time()
    def is_active(self,canal):
        return time.time()-self.last_activity[canal]<config_idle_time

if __name__=="__main__":
    import sys
    if len(sys.argv)==1:
        print "Usage : historien.py <serveur> [--debug]"
        exit(1)
    serveur=sys.argv[1]
    if "debug" in sys.argv or "--debug" in sys.argv:
        debug=True
    else:
        debug=False
    serveurs={"a♡":"acoeur.crans.org","acoeur":"acoeur.crans.org","acoeur.crans.org":"acoeur.crans.org",
              "irc":"irc.crans.org","crans":"irc.crans.org","irc.crans.org":"irc.crans.org"}
    try:
        serveur=serveurs[serveur]
    except KeyError:
        print "Server Unknown : %s"%(serveur)
        exit(404)
    historien=Historien(serveur,debug)
    historien.start()
