PUBLISHER
=========

PUBLISHER is a tclOO-class providing  a general facility for implementing 
the publisher-subscribers pattern.

A publisher is an object usually attached to a master-object (e.g. a complex data structure such a list, a graph, a table, a database ...) that can raise events of public interest. 
These events usually occur when something in the master-object changes.
The master-object knows nothing about its potentials subscribers; it simply tells  the publisher to notify some events to all the (dynamically) registered subscribers.

Subscribers (also referred as observers) are clients interested about changes occurring on that particular master-object. They inform the publisher they are interested on some events and give it a callback, i.e. a command  that publisher should call every time events are generated.
Events may have parameters that will be passed to subscribers' callbacks.


RECOMMENDED NAMING CONVENTIONS
------------------------------
These naming conventions are not mandatory. You are encouraged to follow them - or any other coherent set of conventions - just because they help to write a more readable code (without the need of extra "comments").

* Each *event-name* has a leading "!" (e.g  !ev1 !alert ...)
* Each event may carry details (*event's data*) as a list of key-values; Keys have a leading "-"  (e.g.  -color blue -temperature 100.0 .... )  
* Each different *subscriber* must be identified by a different "id".
    If subscriber is a widget, "id" could be the widget-name
    If subscriber is a (snit) object, "id" could be its name
    Otherwise, you should choose an "id", provided it is unique among all possible subscribers (of the same publisher)
* Each *callback* name should be "On!event" (e.g.  On!alert )


How to interact with a publisher (subscribers-side)
--------------------------------------------------
Let's suppose we have a publisher ($pub) attached to a master-object and some observers wishing to be informed whenever a change in the master-object occur.
The folllowing command lists all the possible events 
    $pub events   ;# -->  { !configure  !alert  !full  !evXYZ !destroyed }
Then an observer (whose "id" is "$obsA") interested on event "!evXYZ" should 
1) setup a callback
    proc On!evXYZ {args} {
        array set param $args
        .. do something with param(-color),  param(-x)  param(-y) ....
    }
2) tell the publisher to call its callback for all the next notifications.
    $pub register !evXYZ $obsA On!evXYZ

Of course each different event may provide different details (event-data), and it is the subscriber's responsibility to setup a conformant callback.


When an observer ($obsA) is no more interested in publisher's notifications it must revoke the subscription
    $pub unregister !evXYZ $obsA  ;# revoke subscription for event !evXYZ
    or
    $pub unregister * $obsA       ;# revoke ALL its-own subscriptions

Note that an observer MUST revoke ALL its subscriptions before being destroyed, or the publisher will send all next events to a no-more-existing client.

** Universal callback **
For testing purpose with just few lines of code, you can setup an universal callback, able to print every detail, catching all possible events:
    # Universal-callback; note the first two "fixed" parameters ...
    proc On!EveryEvent {ev pub args} {
        puts "event ($ev) from ($pub)"
        foreach {key val} $args {
            puts "\tkey: ($key) -- ($val)"
        }
    }
    # register for all events
    foreach ev [$pub events] {
        $pub register $ev $obsA [list On!EveryEvent $ev $pub]
    }
Note that the first two parameters of the callback are fixed at "register-time"; the publisher only "appends" events-data (as the usual key-value list) to a command with two "pre-fixed" parameters.



How to interact with subscribers (publisher--side)
--------------------------------------------------
When a master-object needs to interact with several observers, it must create its own publisher for handling such interactions.

First, master-object creates a publisher:
  set pub [publisher new]
  or
  set pub [publisher create _name_]
Then it declares the names of events it will provide
 $pub declare !evA !evB !evC
 or
 $pub declare !evA ; $pub declare !evB !evC
 
Other than the explicitelly declared event-names, all publishers always provide a standard event named "!destroyed" informing the subscribers that it has been .. destroyed (usually by the master-object).
    This standard event doesn't need to be declared.
    The !destroyed event carries no event-data.

Note that (currently) when declaring events there is no way to declare the parameters (event-data).
It's just a matter of good documentation practice: each publishers should document all its events, their meanings, and their parameters.

*** It is strongly recommended that parameters always be transmitted as an unordered list of key-value pairs.
This key-value convention allows to upgrade the publisher-part ( e.g. adding a parameter "-speed" for a given event), without the need to rewrite the previous subscribers callbacks. (Of course non-upgraded subscribers will simply ignore the new parameter). ***



When a change in the master-object occur, the master-object must tell to its publisher to notify the event.
    $pub notify !itemRemoved -id 42342
    $pub notify !itemAdded -id 12312 -parent 1239866
    $pub notify !itemConfigured -id 23452 -color blue -rank "A"

Note that master-object knows nothing about its currently registered subscribers; that's the publisher's job!

When a master-object deletes its publisher, the publisher implicitely trasmits a last event
    $pub notify !destroyed
Subscribers should simply 'forget' the publisher, without the need to unregister their callback (in fact, they can't unregister, because there is no publisher to contact!)


=== Publisher-Subscribers vs. Tk-events =======================================

The main difference to the event system built into the Tcl/Tk core is that the latter can generate only virtual events, and only for Tk-widgets. 
It is not possible to use the builtin facilities to bind to events on arbitrary (non-Tk-)objects, nor is it able to generate events for such.

Moreover, even for widgets, the bind-event system is rather clumsy when multiple callbacks should be independently attached (bind) to an event, and indipendently detached.
The publisher-subscribers system can be used in a coherent way both for Tk-widgets and for arbitrary objects.
