/*
Copyright (C) 2001-2010, Parrot Foundation.
$Id: packfiledirectory.pmc 48494 2010-08-14 22:56:55Z petdance $

=head1 NAME

src/pmc/packfiledirectory.pmc - PackfileDirectory PMC

=head1 DESCRIPTION

This class implements a PackfileDirectory object, a segment of the .pbc data
file used for listing the rest of the file's contents.  Essentially this
segment is a container for all other segments within a Packfile.

See packfile.pmc for the toplevel Packfile interface, see packfilesegment.pmc
for the list of common methods every packfile segment pmc must implement; see
PDD13 for the design spec.


=head2 Methods

=over 4

=cut

*/

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

pmclass PackfileDirectory auto_attrs extends PackfileSegment {
    /* Directory is a hash of Segments */
    ATTR PMC *hash;

/*

=item C<void init()>

Initialize PackfileDirectory.

=cut

*/
    VTABLE void init() {
        Parrot_PackfileDirectory_attributes * const attrs =
                PMC_data_typed(SELF, Parrot_PackfileDirectory_attributes*);

        attrs->hash = Parrot_pmc_new(INTERP, enum_class_Hash);

        PObj_custom_mark_SET(SELF);
    }

/*

=item C<void mark()>

Marks the object as live.

=cut

*/

    VTABLE void mark() {
        Parrot_PackfileDirectory_attributes * const attrs =
                PARROT_PACKFILEDIRECTORY(SELF);

        Parrot_gc_mark_PMC_alive(INTERP, attrs->hash);

        SUPER();
    }

/*

=item C<void set_pointer(void *ptr)>

Initialize PackfileDirectory from PackFile_Directory.

=cut

*/

    VTABLE void set_pointer(void *ptr) {
        const PackFile_Directory * const pfd = (const PackFile_Directory *)ptr;
        size_t i;

        SUPER(ptr);

        /* Iterate over elements and create corresponded PMCs */
        for (i=0; i < pfd->num_segments; ++i) {
            PackFile_Segment * const pfseg = pfd->segments[i];
            int     pmc_type;
            PMC     *segment;
            STRING  *name;

            switch (pfseg->type) {
              case PF_DIR_SEG:
                pmc_type = enum_class_PackfileDirectory;
                break;
              case PF_FIXUP_SEG:
                pmc_type = enum_class_PackfileFixupTable;
                break;
              case PF_CONST_SEG:
                pmc_type = enum_class_PackfileConstantTable;
                break;
              case PF_ANNOTATIONS_SEG:
                pmc_type = enum_class_PackfileAnnotations;
                break;
              case PF_DEBUG_SEG:
                pmc_type = enum_class_PackfileDebug;
                break;
              case PF_BYTEC_SEG:
              case PF_UNKNOWN_SEG:
              default:
                pmc_type = enum_class_PackfileRawSegment;
                break;
            }

            segment = Parrot_pmc_new(INTERP, pmc_type);
            name    = pfseg->name;
            VTABLE_set_pmc_keyed_str(INTERP, SELF, name, segment);

            /* Initialize internal PMC structure */
            VTABLE_set_pointer(INTERP, segment, pfseg);

        }
    }

/*

=item C<void *get_pointer()>

Creates PackFile for given directory.

=cut

*/

    VTABLE void *get_pointer() {
        Parrot_PackfileDirectory_attributes * attrs =
                PARROT_PACKFILEDIRECTORY(SELF);
        PackFile           * const pf    = PackFile_new(INTERP, 0); /* dummy PackFile... */
        PackFile_Directory * const pfdir = &pf->directory;
        PMC                * const iter  = VTABLE_get_iter(INTERP, attrs->hash);

        /* Create Segments. Add to Directory with transfering ownership */
        while (VTABLE_get_bool(INTERP, iter)) {
            STRING           * const name  = VTABLE_shift_string(INTERP, iter);
            PMC              * const seg   = VTABLE_get_pmc_keyed_str(INTERP, attrs->hash, name);
            PackFile_Segment * const pfseg = (PackFile_Segment *)VTABLE_get_pointer(INTERP, seg);

            pfseg->pf   = pf;
            pfseg->name = name;
            PackFile_add_segment(INTERP, pfdir, pfseg);
        }

        return pf;
    }

/*

=item C<INTVAL elements()>

Get the number of elements in the array.

=cut

*/
    VTABLE INTVAL elements() {
        return VTABLE_elements(INTERP, PARROT_PACKFILEDIRECTORY(SELF)->hash);
    }


/*

=item C<PMC *get_iter()>

Return a new iterator for the directory.

=cut

*/

    VTABLE PMC *get_iter() {
        return VTABLE_get_iter(INTERP, PARROT_PACKFILEDIRECTORY(SELF)->hash);
    }

/*

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

Search the array for a segment with the given name, and return it if it exists.

=cut

*/
    VTABLE PMC *get_pmc_keyed_str(STRING *name)  {
        return VTABLE_get_pmc_keyed_str(INTERP,
                PARROT_PACKFILEDIRECTORY(SELF)->hash, name);
    }


/*

=item C<PMC *get_pmc_keyed(PMC *key)>

Fetch a keyed string value from the packfiledirectory object.

=cut

*/
    VTABLE PMC *get_pmc_keyed(PMC *key) {
        STRING * const s_key = VTABLE_get_string(INTERP, key);
        return VTABLE_get_pmc_keyed_str(INTERP,
                PARROT_PACKFILEDIRECTORY(SELF)->hash, s_key);
    }


/*

=item C<void set_pmc_keyed_str(STRING *name, PMC *segment)>

Add a segment with the given name to the directory.  If a segment with this
name already existed, it will be replaced with the new segment.

=cut

TODO: check type

*/
    VTABLE void set_pmc_keyed_str(STRING *name, PMC *segment)  {
        Parrot_pcc_invoke_method_from_c_args(INTERP, segment,
            Parrot_str_new_constant(INTERP, "set_directory"),
            "P->", SELF);
        VTABLE_set_pmc_keyed_str(INTERP,
            PARROT_PACKFILEDIRECTORY(SELF)->hash, name, segment);
    }

/*

=item C<PMC *set_pmc_keyed(PMC *key, PMC *segment)>

Add a segment with the given name to the directory.  Dispatches to
set_pmc_keyed_str.

=cut

*/

    VTABLE void set_pmc_keyed(PMC *key, PMC *segment)  {
        STRING * const s_key = VTABLE_get_string(INTERP, key);
        VTABLE_set_pmc_keyed_str(INTERP, SELF, s_key, segment);
    }

/*

=item C<PMC *delete_keyed(PMC *key)>

Delete the specified segment from the directory.

=cut

*/

    VTABLE void delete_keyed(PMC *key) {
        VTABLE_delete_keyed(INTERP,
            PARROT_PACKFILEDIRECTORY(SELF)->hash, key);
    }


}

/*

=back

=cut

*/

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