#include <stdio.h>
#include "../lint.h"
#include "../interface.h"
#include "../object.h"
/* Define variables */
extern struct object *previous_ob;


/* Define functions */

extern char *malloc(unsigned);
static var obj_prev = { "obj_previous", 0 };
static var obj_props = { "obj_props", 0 };
static var obj_no_change = { "obj_no_change", 0 };

/*
fp[0]: string to be expanded
fp[1]: target object
*/
static void 
object_check_call(struct svalue *fp)
{
    extern struct svalue const0;
    extern struct svalue *process_value (char *, int);
    extern char *process_string(char *, int);
    extern void INLINE push_malloced_string(char *p);
    extern struct object *query_simul_efun_ob();
    extern struct object *current_object;

    struct svalue *ret = 0;
    char *p, *p2, *str, *retstr;
    int more;

    if (fp[0].type != T_STRING)
    {
	push_svalue(&fp[0]);
	return;
    }

    assign_svalue(&VAR(obj_prev), &fp[1]);

    str = fp[0].u.string;
    if (str[0] == '@' && str[1] == '@')
    {
	p = &str[2];
	p2 = &p[-1];
	while ((p2 = (char *) strchr(&p2[1], '@')) &&
	       (p2[1] != '@'))
	    ;
	if (!p2)
	{
	    ret = process_value(p, 1);
	}
	else if (p2[2] == '\0')
	{
	    int len = strlen(p);
	    p2 = (char *) alloca(len - 1);
	    strncpy(p2, p, len - 2);
	    p2[len - 2] = '\0';
	    ret = process_value(p2, 1);
	}
	else
	    retstr = process_string(str, 1);
    }
    else
        retstr = process_string(str, 1);

    if (ret)
    {
	push_svalue(ret);
    }
    else
    {
	push_string(retstr, STRING_MALLOC);
	if (str != retstr)
	    free(retstr);
    }

    assign_svalue(&VAR(obj_prev), &const0);
}

static func func_check_call = 
{
    "check_call",
    object_check_call,
};

static void
object_query_prop(struct svalue *fp)
{
    extern struct object *previous_ob;
    extern struct svalue const0;
    extern struct svalue *process_value (char *, int);
    extern char *process_string(char *, int);
    extern void INLINE push_malloced_string(char *p);
    extern struct object *query_simul_efun_ob();
    extern struct object *current_object;

    struct svalue *ret = 0;
    struct svalue *val;
    static struct svalue tmp;

    char *p, *p2, *str, *retstr;
    int more;

    extern struct svalue *get_map_lvalue(struct mapping *,
					 struct svalue *, int );
    if (VAR(obj_props).type != T_MAPPING)
    {
	push_number(0);
	return;
    }

    val = get_map_lvalue(VAR(obj_props).u.map, fp, 0);
    if (val->type != T_STRING)
    {
	push_svalue(val);
	return;
    }

    tmp.type = T_OBJECT;
    tmp.u.ob = previous_ob;
    assign_svalue(&VAR(obj_prev), &tmp);

    str = val->u.string;
    if (str[0] == '@' && str[1] == '@')
    {
	p = &str[2];
	p2 = &p[-1];
	while ((p2 = (char *) strchr(&p2[1], '@')) &&
	       (p2[1] != '@'))
	    ;
	if (!p2)
	{
	    ret = process_value(p, 1);
	}
	else if (p2[2] == '\0')
	{
	    int len = strlen(p);
	    p2 = (char *) alloca(len - 1);
	    strncpy(p2, p, len - 2);
	    p2[len - 2] = '\0';
	    ret = process_value(p2, 1);
	}
	else
	    retstr = process_string(str, 1);
    }
    else
        retstr = process_string(str, 1);

    if (ret)
    {
	push_svalue(ret);
    }
    else
    {
	push_string(retstr, STRING_MALLOC);
	if (str != retstr)
	    free(retstr);
    }

    assign_svalue(&VAR(obj_prev), &const0);
}


static func func_query_prop = 
{
    "query_prop",
    object_query_prop,
};

static void
object_add_prop(struct svalue *fp)
{
   extern struct svalue *get_map_lvalue(struct mapping *,
					 struct svalue *, int );
   struct svalue *oval;

   if (VAR(obj_no_change).u.number || VAR(obj_props).type != T_MAPPING)
   {
      push_number(0);
      return;
   }

   assign_svalue((oval=get_map_lvalue(VAR(obj_props).u.map,fp,1)),&fp[1]);

   if (current_object->super)
   {
      push_svalue(&fp[0]);
      push_svalue(get_map_lvalue(VAR(obj_props).u.map,fp,0));
      push_svalue(oval);
      apply("notify_change_prop",current_object->super,3,0);
   }

   push_number(0);
   return;
}

static func func_add_prop = 
{
    "add_prop",
    object_add_prop,
};

static func func_change_prop = 
{
    "change_prop",
    object_add_prop,
};

/* Define the interface */
static var *(vars[]) =
{
    &obj_prev,
    &obj_props,
    &obj_no_change,
    0,
};

static func *(funcs[]) =
{
    &func_check_call,
    &func_query_prop,
    &func_add_prop,
    &func_change_prop,
    0,
};


struct interface stdobject = 
{
    "std/object.c",
    vars,
    funcs,
};