/*
Copyright (C) 2007-2010, Parrot Foundation.
$Id: eventhandler.pmc 46700 2010-05-16 12:30:35Z bacek $

=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

*/

/* HEADERIZER HFILE: none */
/* HEADERIZER BEGIN: static */
/* HEADERIZER END: static */


pmclass EventHandler extends Sub provides invokable auto_attrs {

    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() {
        PObj_custom_mark_SET(SELF);
        PObj_custom_destroy_SET(SELF);
    }

/*

=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 =
                (Parrot_EventHandler_attributes *) PMC_data(SELF);

        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);

        PObj_custom_mark_SET(SELF);
        PObj_custom_destroy_SET(SELF);

        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 * const e = PARROT_EVENTHANDLER(SELF);

        if (e) {
            Parrot_gc_mark_STRING_alive(INTERP, e->type);
            Parrot_gc_mark_PMC_alive(INTERP, e->interp);
            Parrot_gc_mark_PMC_alive(INTERP, e->code);

            SUPER();
        }
    }

/*

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

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

=cut

*/

    VTABLE void set_string(STRING *type) {
        Parrot_EventHandler_attributes * const e = PARROT_EVENTHANDLER(SELF);

        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 * const e = PARROT_EVENTHANDLER(SELF);

        if (e)
            return e->type;

        return CONST_STRING(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 * const e = PARROT_EVENTHANDLER(SELF);

        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 * const e = PARROT_EVENTHANDLER(SELF);

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

/*

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

=cut

*/

    VTABLE PMC *get_attr_str(STRING *name) {
        Parrot_EventHandler_attributes * const e = PARROT_EVENTHANDLER(SELF);
        PMC *value = PMCNULL;

        if (Parrot_str_equal(INTERP, name, CONST_STRING(INTERP, "code"))) {
            value = e->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 * const e = PARROT_EVENTHANDLER(SELF);

        /* can't invoke on INTERP and can't return its result; this may not be
         * the right interpreter */
        if (e) {
            void *unused;

            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) {

        if (event->vtable->base_type == enum_class_Task) {
            PMC    * const type     = VTABLE_get_attr_str(INTERP, event, CONST_STRING(INTERP, "type"));
            STRING * const type_str = VTABLE_get_string(INTERP, type);

            if (Parrot_str_equal(INTERP, type_str, CONST_STRING(INTERP, "event"))) {
                Parrot_EventHandler_attributes * const handler_struct = PARROT_EVENTHANDLER(SELF);
                PMC    * const subtype     = VTABLE_get_attr_str(INTERP, event, CONST_STRING(INTERP, "subtype"));
                STRING * const subtype_str = VTABLE_get_string(INTERP, subtype);

                if (Parrot_str_equal(INTERP, subtype_str, handler_struct->type)) {
                    RETURN(INTVAL 1);
                }
            }
        }

        RETURN(INTVAL 0);
    }

}

/*

=back

=cut

*/

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