#include "otalk.h"
#include "scanner.h"
#include <string.h>
#include <assert.h>


void decorate                (t_node );
void decorate_parameter_list (t_node );
void decorate_var_list       (t_node ,int);
void decorate_name           (t_node );

static t_node method;
static t_node stack = NULL;
static T_OBJECT g_class;

void top_decorate(t_node m_node)
{
  /*fprintf(stderr,"Decoriere\n");*/
  method = m_node;

  if (stack == NULL) {
    stack = new_stack(100);
  }
  clear_stack(stack);
  
  g_class = class_for(NODE_NAME(METHOD_CLASS(m_node)));
  decorate(m_node);
  /*fprintf(stderr,"Decoriere ... ok\n");*/
}


void decorate(t_node node)
{
  int i;

  if (node == NULL) {
    fprintf(stderr,"*** Warning: NULL in decorate()\n");
    return;
  }

  switch(NODE_TAG(node)) {
  case tag_method_vector:
    decorate_parameter_list(METHOD_PARAMETERS(node));
    decorate_var_list(METHOD_VARS(node),NODE_FILL(METHOD_PARAMETERS(node)));
    push_liste(stack,METHOD_VARS(node));
    push_liste(stack,METHOD_PARAMETERS(node));

    decorate(METHOD_STATEMENTS(node));

    pop_n(stack,NODE_FILL(METHOD_PARAMETERS(node)));
    pop_n(stack,NODE_FILL(METHOD_VARS(node)));
    break;
  case tag_closure_vector:
    /* decorate_var_list(CLOSURE_VARS(node)); */
    break;
  case tag_if:
    decorate(IF_TEST(node));
    decorate(IF_THEN(node));
    decorate(IF_ELSE(node));
    break;
  case tag_while:
    decorate(WHILE_TEST(node));
    decorate(WHILE_BODY(node));
    break;
  case tag_plus: case tag_minus:
  case tag_mul:  case tag_div:
  case tag_and:  case tag_or:
  case tag_dot:  case tag_assign:
  case tag_less:  case tag_less_eq:
  case tag_greater:  case tag_greater_eq:
  case tag_equal:
    decorate(NODE_LEFT(node));
    decorate(NODE_RIGHT(node));
    break;
  case tag_return:
    decorate(NODE_LEFT(node));
    break;
  case tag_vector:
    for (i=0; i<NODE_FILL(node); ++i) {
      decorate(NODE_ENTRY(node,i));
    }
    break;
  case tag_name:
    decorate_name(node);
    break;
  case tag_call:
    decorate(CALL_ARGS(node));
    break;
  default:
    break;
  }
}


int find_slot_index(T_OBJECT class, char* slotname)
{
  int i,max,all=0,found=0;
  T_OBJECT meths;
  
  while ((class != g_top_object_class) &&
	 (class != VALUE_NIL)) {
    meths = CLASS_SLOTS(class);
    max = VECTOR_LENGTH(meths);
    
    for (i=0; i<max; ++i) {
      /*printf("Vergleiche %s und %s\n",slotname,STRING_CHARS(VECTOR_ENTRY(meths,i)));*/
      if (!strcmp(slotname,STRING_CHARS(VECTOR_ENTRY(meths,i)))) {
	found = all+max-i;	
      }
    }
    
    all += max;
    class = CLASS_SUPER(class);
  }

  if (found)
    return all-found;
  else
    return -1;
}

void decorate_name(t_node node)
{
  int i,index;
  t_node entry;

  if ((!strcmp(TOKEN_NAME(NODE_TOKEN(node)),"self"))  ||
      (!strcmp(TOKEN_NAME(NODE_TOKEN(node)),"super")) ||
      (!strcmp(TOKEN_NAME(NODE_TOKEN(node)),"true"))  ||
      (!strcmp(TOKEN_NAME(NODE_TOKEN(node)),"nil"))   ||
      (!strcmp(TOKEN_NAME(NODE_TOKEN(node)),"false"))   ) {
    NODE_TYPE(node) = TYPE_SPECIAL;
    return;
  }

  if (isupper(*TOKEN_NAME(NODE_TOKEN(node)))) {
    NODE_TYPE(node) = TYPE_GLOBAL;
    return;
  }

  for (i=0; i<stack_elements(stack); ++i) {
    entry = stack_element_n(stack,i);

    /*
    printf("i: %d von %d ",i,stack_elements(stack));
    print_token(NODE_TOKEN(node));
    printf("  ");
    print_token(NODE_TOKEN(entry));
    puts("");
    */
    if (!strcmp(TOKEN_NAME(NODE_TOKEN(node)),
		TOKEN_NAME(NODE_TOKEN(entry)))) {
      NODE_INDEX(node) = NODE_INDEX(entry);
      NODE_TYPE(node)  = NODE_TYPE(entry);
      /*
      fprintf(stderr,"Decoriere %s mit %d Typ %d\n",
	      TOKEN_NAME(NODE_TOKEN(node)),
	      NODE_INDEX(entry),
	      NODE_TYPE(entry));
      */
      return;
    }
  }
  index = find_slot_index(g_class,TOKEN_NAME(NODE_TOKEN(node)));
  
  if (index < 0) {
    fprintf(stderr,"\n--------------------------------------------------\n"
	    "Kann Variable %s in Methode %s nicht decorieren\n",
	    TOKEN_NAME(NODE_TOKEN(node)),
	    NODE_NAME(METHOD_NAME(method))
	    );
    print_class(g_class);
    assert(1==2);
  }
  else {
    /*printf("Index for %s is %d\n",TOKEN_NAME(NODE_TOKEN(node)),index);*/
    NODE_INDEX(node) = index;
    NODE_TYPE(node)  = TYPE_SLOT;
  }

}


void decorate_parameter_list(t_node liste)
{
  int i;
  int max=NODE_FILL(liste);

  for (i=0; i<max; ++i) {
    NODE_INDEX(NODE_ENTRY(liste,i)) = -max+i+1;
    NODE_TYPE(NODE_ENTRY(liste,i))  = TYPE_PARAMETER;
  }
}

void decorate_var_list(t_node liste, int offset)
{
  int i;

  for (i=0; i<NODE_FILL(liste); ++i) {
    NODE_INDEX(NODE_ENTRY(liste,i)) = i+1; /* +1, denn 0 ist ja der letzte Parameter */
    NODE_TYPE(NODE_ENTRY(liste,i))  = TYPE_VAR;
  }
}

/*eof*/
