/*
$Id: /mirror/trunk/languages/perl6/src/pmc/objectref_pmc.template 35419 2009-01-11T06:15:27.719485Z pmichaud  $
Copyright (C) 2008, The Perl Foundation.

=head1 NAME

src/pmc/objectref_pmc.template - Template for the ObjectRef PMC

=head1 DESCRIPTION

Forwards all but some methods to the held PMC.

=head2 Methods

=cut

*/

#include "parrot/parrot.h"

pmclass ObjectRef need_ext dynpmc group perl6_group {
    ATTR PMC *value;
    ATTR PMC *cached_type;

    VTABLE void init() {
        PMC * const hll_ns    = Parrot_get_ctx_HLL_namespace(INTERP);
        STRING * const s_obj  = string_from_literal(INTERP, "$!OBJECTREF");
        PMC * const objectpmc = Parrot_find_global_n(INTERP, hll_ns, s_obj);
        STATICSELF.init_pmc(objectpmc);
    }

    VTABLE void init_pmc(PMC *value) {
        PMC *type_obj = PMCNULL;

        /* Need custom mark and destroy. */
        PObj_custom_mark_SET(SELF);
        PObj_active_destroy_SET(SELF);

        /* Create underlying structure. */
        PMC_data(SELF) = mem_allocate_zeroed_typed(Parrot_ObjectRef_attributes);
        SET_ATTR_cached_type(INTERP, SELF, type_obj);

        /* Initialize with an undef PMC if no value. */
        if (PMC_IS_NULL(value))
            value = pmc_new(INTERP, enum_class_Undef);
        SET_ATTR_value(INTERP, SELF, value);
    }

    VTABLE void mark() {
        PMC *value;
        GET_ATTR_value(INTERP, SELF, value);
        if (value)
            pobject_lives(INTERP, (PObj*)value);
    }

    VTABLE void destroy() {
        mem_sys_free(PMC_data(SELF));
        PMC_data(SELF) = NULL;
    }

    VTABLE PMC * get_pmc() {
        PMC * value;
        GET_ATTR_value(INTERP, SELF, value);
        return value;
    }

    VTABLE void set_pmc(PMC *value) {
        SET_ATTR_value(INTERP, SELF, value);
    }

    VTABLE INTVAL isa_pmc(PMC *lookup) {
        PMC * value;
        if (SUPER(lookup)) return 1;
        /* PMCProxy_does sends us a proxied ObjectRef with no value */
        if (!PMC_data(SELF)) return 0;
        GET_ATTR_value(INTERP, SELF, value);
        return VTABLE_isa_pmc(INTERP, value, lookup);
    }

    VTABLE INTVAL isa(STRING *classname) {
        PMC * value;
        if (SUPER(classname)) return 1;
        /* PMCProxy_does sends us a proxied ObjectRef with no value */
        if (!PMC_data(SELF)) return 0;
        GET_ATTR_value(INTERP, SELF, value);
        return VTABLE_isa(INTERP, value, classname);
    }

    VTABLE INTVAL does_pmc(PMC *role) {
        PMC * value;
        /* PMCProxy_does sends us a proxied ObjectRef with no value */
        if (!PMC_data(SELF)) return 0;
        GET_ATTR_value(INTERP, SELF, value);
        return VTABLE_does_pmc(INTERP, value, role);
    }

    VTABLE INTVAL does(STRING *role) {
        PMC * value;
        /* PMCProxy_does sends us a proxied ObjectRef with no value */
        if (!PMC_data(SELF)) return 0;
        GET_ATTR_value(INTERP, SELF, value);
        return VTABLE_does(INTERP, value, role);
    }

    VTABLE void morph(INTVAL type) {
        /* XXX For now silently do nothing - so copy op on us works. */
    }

    VTABLE PMC * clone() {
        PMC * value;
        PMC * copy;
        GET_ATTR_value(INTERP, SELF, value);
        copy = pmc_new_init(INTERP, SELF->vtable->base_type, value);
        return copy;
    }

    /* We don't want any of these to be touched */
    /* VTABLE PMC * getprop() */
    /* VTABLE PMC * setprop() */
    /* VTABLE PMC * delprop() */
    /* VTABLE PMC * getprops() */

    METHOD INTVAL readonly() {
        STRING *s_ro = string_from_literal(INTERP, "readonly");
        PMC *ro = VTABLE_getprop(INTERP, SELF, s_ro);
        INTVAL res =  PMC_IS_NULL(ro) ? 0 : VTABLE_get_bool(INTERP, ro);
        RETURN(INTVAL res);
    }

    METHOD INTVAL rw() {
        INTVAL ro, rw;
        (INTVAL ro) = PCCINVOKE(INTERP, SELF, "readonly");
        rw = ro ? 0 : 1;
        RETURN (INTVAL rw);
    }
}
