#!/usr/bin/env python
# -*- coding: iso-8859-1 -*-

import msnp
import random
import string
import time




##########################################
#                                        #
#  Classe de base de tous les listeners  #
#                                        #
##########################################

class MsnChatListener(msnp.ChatCallbacks):
    """Cette classe est la classe de base des gestionnaires de jeux
    qui répondent au chat."""

    welcomeMessage = "Bonjour!  Je ne suis pas Martin, mais plutôt "       + \
                     "un petit programme qu'il a fait pour te divertir.  " + \
                     "Si tu veux jouer avec moi, tape quelque chose et "   + \
                     "on va s'amuser!"
    stopWord = "stop"
    listeners = []
    listenerIterator = 0


    def stopWordInMessage(self, message):
        """Cette fonction vérifie que le mot d'arrêt a été reçu."""
        for word in self.convert(message).split():
            if word == self.stopWord:
                return True
        return False


    def convert(self, message, charset='utf-8'):
        """Cette fonction convertit la chaîne reçu en une chaîne
        utilisable par le programme."""
        return message.decode(charset).encode('iso-8859-1')


    def end(self, firstTime=False):
        callbacks = self.listeners[self.listenerIterator]()
        callbacks.listenerIterator = (self.listenerIterator + 1) % len(self.listeners)

        self.chat.callbacks = callbacks
        callbacks.chat = self.chat
        self.chat = None
        if firstTime:
            callbacks.sendWelcomeMessage()
        else:
            callbacks.sendMessage("Je viens de changer de comportement...  Amuse-toi!")


    def sendMessage(self, message, charset='utf-8'):
        """Cette fonction envoie un message en s'assurent que
        l'encodage est correct."""
        self.chat.send_message(message.decode('iso-8859-1').encode(charset))


    def sendWelcomeMessage(self):
        """Cette fonction envoie le message de bienvenue."""
        self.sendMessage(self.welcomeMessage)




#############################################################
#                                                           #
#  Classe qui ignore les entrées et change de gestionnaire  #
#                                                           #
#############################################################

class IgnoreMsnChatListener(MsnChatListener):
    """Cette classe est utilisée pour ignorer la première entrée qui
    cause la conversation."""

    def message_received(self, passport_id, display_name, text, charset):
        self.end(True)




##################################
#                                #
#  Classe du jeu des anagrammes  #
#                                #
##################################

class AnagramMsnChatListener(MsnChatListener):
    """Cette classe implante le jeu des anagrammes."""


    def __init__(self):
        self.anagram = None
        self.answer  = None


    def scramble(self, message):
        message = list(message)
        random.shuffle(message)
        return ''.join(message)


    def message_received(self, passport_id, display_name, text, charset):
        if self.anagram == None:
            # On prend un mot dans le texte qu'il a écrit: le plus long
            words = self.convert(text).split()
            words.sort(cmp=lambda x,y : len(y) - len(x))
            if len(words) > 0:
                self.answer  = words[0]
                self.anagram = self.scramble(words[0])
            self.sendMessage('Voici un anagramme: "' + self.anagram + \
                             '".  Bonne chance!')
        else:
            # Est-ce que le mot a été deviné?
            words = self.convert(text).split()

            answerFound   = False
            stopWordFound = False
            for word in words:
                if word == self.answer:
                    answerFound = True
                if word == MsnChatListener.stopWord:
                    stopWordFound = True

            if answerFound:
                self.sendMessage('Bravo!  Tu as trouvé!')
                self.anagram = None
                self.answer  = None
            else:
                if not stopWordFound:
                    self.sendMessage("Désolé, ce n'est pas le mot...  " + \
                                     'Tu peux réessayer ou taper "'     + \
                                     MsnChatListener.stopWord + '" '    + \
                                     'si tu es tanné!')
                    self.sendMessage('(Le mot est "' + self.anagram + '")')
                else:
                    self.sendMessage("Merci d'avoir joué!")
                    self.sendMessage('(La réponse était "' + self.answer + '")')
                    self.anagram = None
                    self.answer  = None
                    self.end()

# On enregistre la classe comme listener valide
MsnChatListener.listeners.append(AnagramMsnChatListener)




###############################################################
#                                                             #
#  Classe qui change la présentation du message et le répète  #
#                                                             #
###############################################################

class PrettyMsnChatListener(MsnChatListener):
    """Cette classe implante une répétition du message embelli."""


    def __init__(self):
        self.answererIterator = 0


    def same(self, text, charset):
        return self.convert(text)


    def upperLower(self, text, charset):
        message = self.convert(text)
        returnValue = []
        i = 0
        while i < len(message):
            if (i % 2 == 0):
                function = string.lower
            else:
                function = string.upper
            returnValue.append(function(message[i]))
            i = i + 1
        return ''.join(returnValue)


    def star(self, text, charset):
        message = self.convert(text)
        returnValue = []
        i = 0
        while i < len(message):
            returnValue.append(message[i])
            returnValue.append('*')
            i = i + 1
        return '*' + ''.join(returnValue)


    def colored(self, text, charset):
        # Ce code est copié/collé de chat.py
        import email
        import email.Message
        mime_message = email.Message.Message()
        mime_message['MIME-Version'] = '1.0'
        mime_message['Content-Type'] = 'text/plain; charset=' + charset
        # On change le style du message
        mime_message['X-MMS-IM-Format'] = 'EF=BI CO=0000ff'
        mime_message.set_payload(text)
        self.chat._Chat__send_mime_message(mime_message, 'N')
        # Retourner none spécifie que le message est déjà envoyé
        return None


    converters = [
        same ,
        upperLower ,
        star ,
        colored
        ]


    def message_received(self, passport_id, display_name, text, charset):
        if (self.stopWordInMessage(text)):
            self.sendMessage("Merci de t'être amusé!")
            self.end()
        else:
            function = self.converters[self.answererIterator]
            self.answererIterator = (self.answererIterator + 1) % len(self.converters)
            response = function(self, text, charset)
            if response != None:
                self.sendMessage(response)
            self.sendMessage('(Tu peux taper "' + self.stopWord + \
                             '" si tu es tanné!)')

# On enregistre la classe comme listener valide
MsnChatListener.listeners.append(PrettyMsnChatListener)




########################################
#                                      #
#  Classe du jeu de deviner un numéro  #
#                                      #
########################################

class GuessMsnChatListener(MsnChatListener):
    """Cette classe implante le jeu de deviner un numéro."""


    maxValue = 100
    minValue = 0


    def __init__(self):
        self.number   = None


    def message_received(self, passport_id, display_name, text, charset):
        if self.number == None:
            # On choisit un nombre à faire deviner
            self.minGuess = self.minValue
            self.maxGuess = self.maxValue
            self.number   = random.randint(self.minValue, self.maxValue)

            self.sendMessage("J'ai choisi un nombre entre " + \
                             str(self.minValue) + " et " + \
                             str(self.maxValue) + ".  Devine-le!")
        else:
            if (self.stopWordInMessage(text)):
                self.sendMessage("Merci d'avoir joué!")
                self.sendMessage("(La réponse était " + str(self.number) + ")")
                self.end()
            else:
                # On essaie de trouver un nombre dans le message
                number = None
                for word in self.convert(text).split():
                    try:
                        number = int(word)
                    except ValueError:
                        pass

                needToExplainStop = True
                if number == None:
                    self.sendMessage("Tu dois entrer un nombre!")
                elif not number > self.minGuess:
                    self.sendMessage("Ce n'est pas super intelligent de " + \
                                     "choisir un nombre plus petit ou égal à " + \
                                     str(self.minGuess) + "...")
                elif not number < self.maxGuess:
                    self.sendMessage("Ce n'est pas super intelligent de " + \
                                     "choisir un nombre plus grand ou égal à que " + \
                                     str(self.maxGuess) + "...")
                elif number < self.number:
                    self.sendMessage("Bel essai, mais trop bas!")
                    self.minGuess = number
                elif number > self.number:
                    self.sendMessage("Bel essai, mais trop haut!")
                    self.maxGuess = number
                else:
                    self.sendMessage("Bravo!  Tu as trouvé le numéro!  " + \
                                     "On recommence!")
                    needToExplainStop = False
                    self.number = None
                    # On rappelle la fonction
                    self.message_received(passport_id, display_name, None, None)

                if (needToExplainStop):
                    self.sendMessage('(Tu peux taper "' + self.stopWord + \
                                     '" si tu es tanné!)')

# On enregistre la classe comme listener valide
MsnChatListener.listeners.append(GuessMsnChatListener)




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




#####################################################
#                                                   #
#  Classe de réception générale des énévements MSN  #
#                                                   #
#####################################################

class MsnListener(msnp.SessionCallbacks):
    def state_changed(self, state):
        if state == msnp.States.ONLINE:
            print 'MSNBot est maintenant en ligne'
    def friend_list_updated(self, friend_list):
        print 'Réception de la liste de contacts:'
        for friend in friend_list.get_friends():
            print 'passport_id: ' + friend.get_passport_id() + \
                  ' , display_name: ' + friend.get_display_name()
    def chat_started(self, chat):
        callbacks = IgnoreMsnChatListener()
        callbacks.chat = chat
        chat.callbacks = callbacks


msn = msnp.Session(MsnListener())
msn.login('martin_s_bot@hotmail.com', 'patate')
msn.sync_friend_list()

while True:
    msn.process(chats = True)
    time.sleep(1)



# Notes:
# - J'ai modifié session.py pour tenir compte des messsages "NOT" qui
#   m'empêchait de me connecter avec mon compte
