/*
Copyright (C) 2007-2008, The Perl Foundation.
$Id: /mirror/trunk/src/pmc/eventhandler.pmc 34125 2008-12-19T01:57:06.072455Z chromatic  $

=head1 NAME

src/pmc/eventhandler.pmc - a handler for events

=head1 DESCRIPTION

A PMC that captures the state of the interpreter to invoke when handling an
Event.

=head2 Vtable Functions

=over 4

=cut

*/

#include "parrot/parrot.h"

pmclass EventHandler extends Sub need_ext {

    ATTR STRING *type;          /* the type of the event to handle */
    ATTR PMC    *code;          /* the code object to execute */
    ATTR PMC    *interp;        /* the registered interpreter */
    ATTR INTVAL  priority;      /* the minimum priority threshhold of events */

/*

=item C<void init()>

Initializes an empty C<EventHandler>.  Add attributes to it if you want it to
do anything.

=cut

*/

    VTABLE void init() {
        Parrot_EventHandler_attributes *e =
            mem_allocate_zeroed_typed(Parrot_EventHandler_attributes);

        PObj_custom_mark_SET(SELF);
        PObj_active_destroy_SET(SELF);

        PMC_data(SELF) = e;
    }

/*

=item C<void init_pmc(PMC *data)>

Initializes a new EventHandler with either a C<Sub> PMC (or descendant) or a
C<Hash> PMC.  With the latter, the keys should be any or all of:

=over 4

=item C<code>

a C<Sub> (or descendant) PMC containing code to invoke when handling the event

=item C<interp>

a C<ParrotInterpreter> PMC in which to invoke the code PMC

=item C<type>

a STRING recording the type of event to handle

=item C<priority>

the minimum threshhold of priority which the event must meet or exceed for the
handler to care

=back

=cut

*/

    VTABLE void init_pmc(PMC *data) {
        PMC                 *code        = NULL;
        PMC                 *interpreter = PMCNULL;
        STRING              *type        = NULL;
        INTVAL               priority    = 0;
        Parrot_EventHandler_attributes *e           = NULL;

        if (VTABLE_isa(INTERP, data, CONST_STRING(INTERP, "Sub"))) {
            code = data;
        }
        else if (VTABLE_isa(INTERP, data, CONST_STRING(INTERP, "Hash"))) {
            code = VTABLE_get_pmc_keyed_str(INTERP, data, CONST_STRING(INTERP, "code"));
            interpreter = VTABLE_get_pmc_keyed_str(INTERP, data, CONST_STRING(INTERP, "interp"));
            type = VTABLE_get_string_keyed_str(INTERP, data, CONST_STRING(INTERP, "type"));
            priority = VTABLE_get_integer_keyed_str(INTERP, data, CONST_STRING(INTERP, "priority"));
        }
        else {
            Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_INVALID_OPERATION,
                "EventHandler initializer must be Sub or Hash");
        }

        if (PMC_IS_NULL(interpreter))
            interpreter = VTABLE_get_pmc_keyed_int(INTERP,
                    INTERP->iglobals, IGLOBALS_INTERPRETER);

        e = mem_allocate_zeroed_typed(Parrot_EventHandler_attributes);

        PObj_custom_mark_SET(SELF);
        PObj_active_destroy_SET(SELF);

        PMC_data(SELF) = e;
        e->type        = type;
        e->code        = code;
        e->interp      = interpreter;
        e->priority    = priority;
    }

/*

=item C<void mark()>

Marks this PMC and any of its contents as live.

=cut

*/

    VTABLE void mark() {
        Parrot_EventHandler_attributes *e = PMC_data_typed(SELF, Parrot_EventHandler_attributes *);

        if (e) {
            if (e->type)
                pobject_lives(INTERP, (PObj *)e->type);

            if (! PMC_IS_NULL(e->interp))
                pobject_lives(INTERP, (PObj *)e->interp);

            if (! PMC_IS_NULL(e->code))
                pobject_lives(INTERP, (PObj *)e->code);
        }
    }

/*

=item C<void destroy()>

Frees any memory held by this PMC.

=cut

*/

    VTABLE void destroy() {
        Parrot_EventHandler_attributes *e = PMC_data_typed(SELF, Parrot_EventHandler_attributes *);

        if (e) {
            mem_sys_free(e);
            PMC_data(SELF) = NULL;
        }
    }

/*

=item C<void set_string(STRING *type)>

Sets the C<type> attribute of this event handler to the passed-in string.

=cut

*/

    void set_string(STRING *type) {
        Parrot_EventHandler_attributes *e = PMC_data_typed(SELF, Parrot_EventHandler_attributes *);

        if (e)
            e->type = type;
    }

/*

=item C<STRING *get_string()>

Retrieves the C<type> attribute of this event handler.

=cut

*/

    VTABLE STRING *get_string() {
        Parrot_EventHandler_attributes *e =
            PMC_data_typed(SELF, Parrot_EventHandler_attributes *);

        if (e)
            return string_copy(INTERP, e->type);

        return string_from_literal(INTERP, "");
    }

/*

=item C<void set_integer_native(INTVAL priority)>

Sets the minimum interesting priority for this event handler.

=cut

*/
    VTABLE void set_integer_native(INTVAL priority) {
        Parrot_EventHandler_attributes *e = PMC_data_typed(SELF, Parrot_EventHandler_attributes *);

        if (e)
            e->priority = priority;
    }

/*

=item C<void set_pmc(PMC *interpreter)>

Sets the passed-in C<ParrotInterpreter> as the active interpreter in which to
handle the registered events.

=cut

*/
    VTABLE void set_pmc(PMC *interpreter) {
        Parrot_EventHandler_attributes *e =
            PMC_data_typed(SELF, Parrot_EventHandler_attributes *);

        if (e)
            e->interp = interpreter;
    }

/*

=item C<PMC *get_attr_str(STRING *name)>

=cut

*/

    VTABLE PMC *get_attr_str(STRING *name) {
        Parrot_EventHandler_attributes *core_struct
            = PMC_data_typed(SELF, Parrot_EventHandler_attributes *);
        PMC *value = PMCNULL;

        if (string_equal(interp, name, CONST_STRING(interp, "code")) == 0) {
            value = core_struct->code;
        }

        return value;
    }

/*

=item C<opcode_t *invoke(void *next)>

Runs the contained code, if any; this is what handles the event.

=cut

*/
    VTABLE opcode_t *invoke(void *next) {
        Parrot_EventHandler_attributes *e = PMC_data_typed(SELF, Parrot_EventHandler_attributes *);
        void                *unused;

        /* can't invoke on INTERP and can't return its result; this may not be
         * the right interpreter */
        if (e) {
            unused = VTABLE_invoke(PMC_data_typed(e->interp, Parrot_Interp),
                    e->code, next);
            UNUSED(unused);
        }

        return (opcode_t *)next;
    }

/*

=back

=head2 Methods

=over 4

=cut

*/

/*

=item C<METHOD can_handle(PMC *event)>

Report whether the event handler can handle a particular type of event.

=cut

*/

    METHOD can_handle(PMC *event) {
        Parrot_EventHandler_attributes *handler_struct =
            PMC_data_typed(SELF, Parrot_EventHandler_attributes *);
        if (event->vtable->base_type == enum_class_Task) {
            PMC *type = VTABLE_get_attr_str(interp, event, CONST_STRING(interp, "type"));
            STRING *type_str = VTABLE_get_string(interp, type);

            if (string_equal(interp, type_str, CONST_STRING(interp, "event")) == 0) {
                PMC *subtype = VTABLE_get_attr_str(interp, event, CONST_STRING(interp, "subtype"));
                STRING *subtype_str = VTABLE_get_string(interp, subtype);

                if (string_equal(interp, subtype_str, handler_struct->type) == 0) {
                    RETURN(INTVAL 1);
                }
            }
        }

        RETURN(INTVAL 0);
    }

}

/*

=back

=cut

*/

/*
 * Local variables:
 *   c-file-style: "parrot"
 * End:
 * vim: expandtab shiftwidth=4:
 */
