/* -*- c -*- 
 * File: proscope.c
 * Author: Igor Vlasenko <vlasenko@imath.kiev.ua>
 * Created: Thu May 26 15:25:57 2005
 *
 * $Id$
 */

#include <stdlib.h>
#include "proscope.h"
#include "tmpllog.h"

#define START_NUMBER_OF_NESTED_LOOPS 64

static
void 
Scope_init(struct scope_stack* scopestack) {
  scopestack->max=START_NUMBER_OF_NESTED_LOOPS;
  scopestack->root=(struct ProScopeEntry*) malloc ((scopestack->max) * sizeof(struct ProScopeEntry));
  if (NULL==scopestack->root) tmpl_log(TMPL_LOG_ERROR, "DIE:_Scope_init:internal error:not enough memory\n");
  scopestack->level=-1;
}

static
void 
Scope_free(struct scope_stack* scopestack) {
  free(scopestack->root);
  scopestack->max=-1;
  scopestack->level=-1;
}

INLINE
static
int curScopeLevel(const struct scope_stack* scopestack) {
  return scopestack->level;
}

INLINE
static
struct ProScopeEntry* getCurrentScope(const struct scope_stack* scopestack) {
  return scopestack->root+scopestack->level;
}

INLINE
static
struct ProScopeEntry* 
getScope(const struct scope_stack* scopestack, int depth) {
  return &(scopestack->root)[depth];
}

static
void 
popScope(struct scope_stack* scopestack) {
  if (scopestack->level>0) scopestack->level--;
  else tmpl_log(TMPL_LOG_ERROR, "WARN:PopScope:internal error:scope is exhausted\n");
}

static
void 
_pushScope(struct scope_stack* scopestack) {
  if (scopestack->max<0) {
    tmpl_log(TMPL_LOG_ERROR, "WARN:PushScope:internal warning:why scope is empty?\n");
    Scope_init(scopestack);
  }
  ++scopestack->level;
  if (scopestack->level>scopestack->max) 
    {
      if (scopestack->max<START_NUMBER_OF_NESTED_LOOPS) scopestack->max=START_NUMBER_OF_NESTED_LOOPS;
      scopestack->max*=2;
      scopestack->root=(struct ProScopeEntry*) realloc (scopestack->root, (scopestack->max) * sizeof(struct ProScopeEntry));
    }
}

static
void 
pushScopeLoop(struct scope_stack* scopestack, int loop_count, void *loops_AV) {
  struct ProScopeEntry* CurrentScope;
  _pushScope(scopestack);
  CurrentScope=scopestack->root+scopestack->level;
  CurrentScope->loop=-1;
  CurrentScope->loop_count = loop_count;
  CurrentScope->flags=0;
  CurrentScope->loops_AV=loops_AV;
  CurrentScope->param_HV=NULL;
}

static
void 
pushScopeMap(struct scope_stack* scopestack, void *param_HV, int flags) {
  struct ProScopeEntry* CurrentScope;
  _pushScope(scopestack);
  CurrentScope=scopestack->root+scopestack->level;
  CurrentScope->flags=flags;
  CurrentScope->loops_AV=NULL;
  CurrentScope->param_HV=param_HV;
}

static
void 
Scope_reset(struct scope_stack* scopestack, int keep_count) {
  int init_level=-1;
  // TODO; find out scope level
  if (scopestack->max<0) {
    tmpl_log(TMPL_LOG_ERROR, "ERROR:Scope_reset:internal error:scope is empty.\n");
    Scope_init(scopestack);
    scopestack->level=init_level;
  } else {
    scopestack->level=keep_count+init_level;
  }
}