# mvc from



##Some points to mention...
##
##The model knows nothing about the view or the controller.
##The view knows nothing about the controller or the model.
##The controller understands both the model and the view.
##
##The model uses observables, essentially when important data is changed,
##any interested listener gets notified through a callback mechanism.
##
##The following opens up two windows, one that reports how much money you
##have, and one that has two buttons, one to add money and one to remove
##money.
##
##The important thing is that the controller is set up to monitor changes
##in the model.  In this case the controller notices that you clicked a
##button and modifies the money in the model which then sends out a
##message that it has changed.  The controller notices this and updates
##the widgets.
##
##The cool thing is that anything modifying the model will notify the
##controller.  In this case it is the controller modifying the model, but it
##could be anything else, even another controller off in the distance
##looking at something else.
##
##The main idea is that you give a controller the model and view that it
##needs, but the model's can be shared between controllers so that when
##the model is updated, all associated views are updated. -Brian Kelley
##
## following is a Tkinter approximation of the original example.

# BM a ajouté quelques explications

import tkinter as tk


class Observable:
    def __init__(self, initialValue=None):
        self.data = initialValue
        self.callbacks = {}

    def addCallback(self, func):
        print("passage par addCallback")
        self.callbacks[func] = 1

    def delCallback(self, func):
        del self.callback[func]

    # fonction appelée après un set.
    # lance les notifications aux observateurs.
    def _docallbacks(self):

        for func in self.callbacks:             
             print("passage par _docallbacks")
             print(self.callbacks)
             func(self.data)
    # La fonction set appelle les callbacks.
    def set(self, data):
        print("passage par set")          
        self.data = data
        self._docallbacks()

    def get(self):
        print("passage par get") 
        return self.data

    def unset(self):
        print("passage par unset") 
        self.data = None


class Model:
    def __init__(self):
        self.myMoney = Observable(0)

    def addMoney(self, value):
        self.myMoney.set(self.myMoney.get() + value)

    def removeMoney(self, value):
        self.myMoney.set(self.myMoney.get() - value)


class View(tk.Toplevel):
    def __init__(self, master):
        tk.Toplevel.__init__(self, master)
        self.protocol('WM_DELETE_WINDOW', self.master.destroy)
        tk.Label(self, text='My Money').pack(side='left')
        self.moneyCtrl = tk.Entry(self, width=8)
        self.moneyCtrl.pack(side='left')
        
    def SetMoney(self, money):
        self.moneyCtrl.delete(0,'end')
        self.moneyCtrl.insert('end', str(money))        


class ChangerWidget(tk.Toplevel):
    def __init__(self, master):
        tk.Toplevel.__init__(self, master)
        self.addButton = tk.Button(self, text='Add', width=8)
        self.addButton.pack(side='left')
        self.removeButton = tk.Button(self, text='Remove', width=8)
        self.removeButton.pack(side='left')        


class Controller:
    def __init__(self, root):
        self.model = Model()

       # Sur l'oject myMoney du model, on ajoute un callback : cette
        # fonction du controlleur sera appellée après une mise à jour du modèle
        # On passe la référence de cette fonction, qui est ici une
        # fonction du controlleur. Cette fonction est stockée (dans un dico)
        # par un objet qui n'est pas de la classe du controleur, mais
        # qui est de la classe du modèle.

        # Autrement dit : on dit à un des objets du modèle de prévenir le
        # controlleur quand il a été mis à jour.
        
        self.model.myMoney.addCallback(self.MoneyChanged)

        self.view1 = View(root)
        self.view2 = ChangerWidget(self.view1)
        self.view2.addButton.config(command=self.AddMoney)
        self.view2.removeButton.config(command=self.RemoveMoney)
        
        self.MoneyChanged(self.model.myMoney.get())
        
    def AddMoney(self):
        self.model.addMoney(10)

    def RemoveMoney(self):
        self.model.removeMoney(10)

    def MoneyChanged(self, money):
        self.view1.SetMoney(money)


if __name__ == '__main__':
    root = tk.Tk()
    root.withdraw()
    app = Controller(root)
    root.mainloop()
