/* object.h: Declarations for objects. */

/* The header ordering conventions break down here; we need to make sure data.h
 * has finished, not just that the typedefs have been done. */

#ifndef DID_DBREF_TYPEDEF
typedef long Dbref;
#define DID_DBREF_TYPEDEF
#endif

#include "data.h"

#ifdef DATA_H_DONE

#ifndef OBJECT_H
#define OBJECT_H

typedef struct object		Object;
typedef struct string_entry	String_entry;
typedef struct ident_entry	Ident_entry;
typedef struct var		Var;
typedef struct method		Method;
typedef struct error_list	Error_list;
typedef int			Object_string;
typedef int			Object_ident;

#include <stdio.h>
#include "data.h"

struct object {
    List *parents;
    List *children;

    /* Variables are stored in a table, with index threads starting at the
     * hash table entries.  There is also an index thread for blanks.  This
     * way we can write the hash table to disk easily. */
    struct {
	Var *tab;
	int *hashtab;
	int blanks;
	int size;
    } vars;

    /* Methods are also stored in a table.  Since methods are fairly big, we
     * store a table of pointers to methods so that we don't waste lots of
     * space. */
    struct {
	struct mptr {
	    Method *m;
	    int next;
	} *tab;
	int *hashtab;
	int blanks;
	int size;
    } methods;

    /* Table for string references in methods. */
    String_entry *strings;
    int num_strings;
    int strings_size;

    /* Table for identifier references in methods. */
    Ident_entry	*idents;
    int num_idents;
    int idents_size;

    /* Information for the cache. */
    Dbref dbref;
    int refs;
    char dirty;			/* Flag: Object has been modified. */
    char dead;			/* Flag: Object has been destroyed. */

    long search;		/* Last search to visit object. */

    /* Pointers to next and previous objects in cache chain. */
    Object *next;
    Object *prev;
};

/* The object string and identifier tables simplify storage of strings and
 * identifiers for methods.  When we want to free an object without destroying
 * it, we don't need to scan the method code to determine what strings and
 * identifiers to free, and we don't need to do any modification of method
 * code to reflect a new identifier table when we reload the object. */

/* We keep a ref count on object string entries because we have to know when
 * to delete it from the object.  As far as the string is concerned, all these
 * references are really just one reference, since we only duplicate or discard
 * when we're adding or removing a string from an object. */
struct string_entry {
    String *str;
    int refs;
};

/* Similar logic for identifier references. */
struct ident_entry {
    Ident id;
    int refs;
};

struct var {
    Ident name;
    Dbref cclass;
    Data val;
    int next;
};

struct method {
    Ident name;
    Object *object;
    int num_args;
    Object_ident *argnames;
    Object_ident rest;
    int num_vars;
    Object_ident *varnames;
    int num_opcodes;
    long *opcodes;
    int num_error_lists;
    Error_list *error_lists;
    int overridable;
    int refs;
};

struct error_list {
    int num_errors;
    int *error_ids;
};

Object *object_new(long dbref, List *parents);
void object_free(Object *object);
void object_destroy(Object *object);

void object_construct_ancprec(Object *object);

int object_change_parents(Object *object, List *parents);
List *object_ancestors(long dbref);
int object_has_ancestor(long dbref, long ancestor);
void object_reconstruct_descendent_ancprec(long dbref);

int object_add_string(Object *object, String *string);
void object_discard_string(Object *object, int ind);
String *object_get_string(Object *object, int ind);

int object_add_ident(Object *object, char *ident);
void object_discard_ident(Object *object, int ind);
long object_get_ident(Object *object, int ind);

long object_add_param(Object *object, long name);
long object_del_param(Object *object, long name);
long object_assign_var(Object *object, Object *cclass, long name, Data *val);
long object_retrieve_var(Object *object, Object *cclass, long name, Data *ret);
void object_put_var(Object *object, long cclass, long name, Data *val);

Method *object_find_method(long dbref, long name);
Method *object_find_next_method(long dbref, long name, long after);
void object_add_method(Object *object, long name, Method *method);
int object_del_method(Object *object, long name);
List *object_list_method(Object *object, long name, int indent, int parens);
void method_free(Method *method);
Method *method_grab(Method *method);
void method_discard(Method *method);

void object_text_dump(long dbref, FILE *fp);

#endif

#endif