/* container-lump.m,
 *
 * Lumps are files in which all of the children are of the same class.
 * This allows us to safely grab a random thing from it.
 */

#include <assert.h>
#include <stdlib.h>
#include "alrand/alrand.h"
#include "container-lump.h"
#include "seborrhea-debug.h"


@implementation SebLump
- init
{
    [super init];
    process_directories = YES;
    lump_child_class = nil;
    return self;
}

- (BOOL) addToList:(Sebum *)child
{
    assert(child);

    /* Check all contents are of the same type. */
    if ((lump_child_class) && (not [child isKindOf:lump_child_class])) {
	fprintf(stderr, "[%s:%s] Attempted to add %s (%s) into lump of %s!\n",
		[[self class] name], [self name], [child name], [[child class] name], [lump_child_class name]);
	return NO;
    }
    else
	lump_child_class = [child class];

    return [super addToList:child];
}

	/* This is needed for metafile properties. */
- (Sebum *) getSebumByName:(const char *)name_
{
    unsigned int i;
    assert(name_);

    /* Basic routine. */
    for (i = 0; i < nelements; i++) {
	if (streq([element[i] name], name_))
	    return element[i];
    }

    fprintf(stderr, "[SebLump] Could not find %s.\n", name_);
    return nil;
}

- (BOOL) readMetafilePropertiesWithDirList:(DirectoryList *)dirlist
{
    if (not metafp || not [self seekInFile:metafp For:"properties" WithDirList:dirlist])
	return YES;

    SEBORRHEA_MESSAGE(stdout, "[%s] Reading metafile (properties)\n", [[self class] name]);

    while (expect_char(metafp, '(')) {
	Token *command = nil;
	int i;

        if (not (command = read_symbol(metafp)))
	    continue;

	while (expect_char(metafp, '(')) { /* Begin arguments. */
	    Token *argv[8] = {nil};
	    int argc = [self readTokensNonParenthesisFrom:metafp :argv :sizeof(argv)/sizeof(*argv)];
	    if (argc <= 0)
		goto abort;

	    {				/* Process command. */
		const char *cmd = [command getSymbol];

		for (i = 0; metafile_property_handlers[i].proc; i++) {
		    if (streq(cmd, metafile_property_handlers[i].prop)) {
			metafile_property_handlers[i].proc([self getSebumByName:[argv[0] getString]], argc, argv);
			break;
		    }
		}

		if (not metafile_property_handlers[i].proc) {
		    fprintf(stderr, "[%s] %s is not a recognised metafile property!\n",
			    [[self class] name], cmd);
		}
	    }

	    while (argc > 0) {		/* Free arguments. */
		argc--;
		argv[argc] = [argv[argc] free];
	    }
	}

	/* End of command. */
	if (not expect_char(metafp, ')'))
	    goto abort;

	command = [command free];
	continue;

    abort:
	command = [command free];
	return NO;
    }

    if (not expect_char(metafp, ')'))	/* ) to close properties list */
	return NO;

    return YES;
}

- (BOOL) startLoadingSebumDirectory:(const char *)top_dir :(const char *)sub_dir WithDirList:(DirectoryList *)dirlist
{
    [super startLoadingSebumDirectory:top_dir :sub_dir WithDirList:dirlist];

    if (not [self loadContentsOfDirectory:top_dir :sub_dir WithDirList:dirlist])
	return NO;

    /* Open the metafile, and process the properties section. */
    [self openMetafile:top_dir :sub_dir WithDirList:dirlist];
    if (not [self readMetafilePropertiesWithDirList:dirlist])
	goto buggy_metafile;

    [self closeMetafile:dirlist];
    return YES;

 buggy_metafile:
    fprintf(stderr, "[%s] Buggy metafile in %s%s.\n", [[self class] name], top_dir, sub_dir);
    [self closeMetafile:dirlist];
    return NO;

}

- (unsigned int) numElements { return nelements; }

- (Sebum *) getRandomSebum
{
    if (nelements == 0)
	return nil;
    else {
	alrand_uint32_t r = alrand_rand();
	return element[r % nelements];
    }
}
@end
