# POPFILE LOADABLE MODULE
package POPFile::MQ;

use POPFile::Module;
@ISA = ( "POPFile::Module" );

#----------------------------------------------------------------------------
#
# This module handles POPFile's message queue.  Every POPFile::Module is
# able to register with the MQ for specific message types and can also
# send messages without having to know which modules need to receive
# its messages.
#
# Message delivery is asynchronous and guaranteed.
#
# The following public functions are defined:
#
# register() - register for a specific message type and pass an object
#              reference.  will call that object's deliver() method to
#              deliver messages
#
# post()     - send a message of a specific type
#
# The current list of types is
#
#     UIREG    Register a UI component, message is the component type
#              and the parameter is a the element and reference to the
#              object registering (comes from any component)
#
#     TICKD    Occurs when an hour has passed since the last TICKD (this
#              is generated by the POPFile::Logger module)
#
#     LOGIN    Occurs when a proxy logs into a remote server, the message
#              is the username sent
#
#     NEWFL    Occurs when a new file has been written to the history
#              cache on disk.  The message is the filename
#
# Copyright (c) 2001-2003 John Graham-Cumming
#
#   This file is part of POPFile
#
#   POPFile is free software; you can redistribute it and/or modify
#   it under the terms of the GNU General Public License as published by
#   the Free Software Foundation; either version 2 of the License, or
#   (at your option) any later version.
#
#   POPFile is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU General Public License for more details.
#
#   You should have received a copy of the GNU General Public License
#   along with POPFile; if not, write to the Free Software
#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
#----------------------------------------------------------------------------

use strict;
use warnings;
use locale;

#----------------------------------------------------------------------------
# new
#
#   Class new() function
#----------------------------------------------------------------------------
sub new
{
    my $type = shift;
    my $self = POPFile::Module->new();

    # These are the individual queues of message, indexed by type
    # and written to by post().

    $self->{queue__} = {};

    # These are the registered objects for each type

    $self->{waiters__} = {};

    bless $self, $type;

    $self->name( 'mq' );

    return $self;
}

# ---------------------------------------------------------------------------------------------
#
# service
#
# Called to handle pending tasks for the module.  Here we flush all queues
#
# ---------------------------------------------------------------------------------------------
sub service
{
    my ( $self ) = @_;

    # Iterate through all the messages in all the queues

    for my $type (sort keys %{$self->{queue__}}) {
         while ( my $ref = shift @{$self->{queue__}{$type}} ) {
             for my $waiter (@{$self->{waiters__}{$type}}) {
                my $message   = @$ref[0];
                my $parameter = @$ref[1];

                $waiter->deliver( $type, $message, $parameter );
            }
        }
    }

    return 1;
}

#----------------------------------------------------------------------------
#
# register
#
#   When a module wants to receive specific message types it calls this
#   method with the type of message is wants to receive and the address
#   of a callback function that will receive the messages
#
#   $type        A string identifying the message type
#   $callback    Reference to a function that takes three parameters
#
#----------------------------------------------------------------------------
sub register
{
    my ( $self, $type, $callback ) = @_;

    push @{$self->{waiters__}{$type}}, ( $callback );
}

#----------------------------------------------------------------------------
#
# post
#
#   Called to send a message through the message queue
#
#   $type        A string identifying the message type
#   $message     The message
#   $parameter   Parameters to the message
#
#----------------------------------------------------------------------------
sub post
{
    my ( $self, $type, $message, $parameter ) = @_;

    push @{$self->{queue__}{$type}}, [ $message, $parameter ];
}

1;
