#pragma implementation
#include <iostream.h>
#include <stdlib.h>
#include "mapping.h"
#include "genfiles.h"
#include "gvars.h"
#include "gkinds.h"
#include "gennum.h"
#include "gfiles.h"
#include "gfunc.h"
//#include "hashtab.h"
#include "exceptions.h"
#include "ifthenelse.h"

#define UnknownElement ((Root*)(0))
#define NewElement ((Root*)(1))

extern const Class * (__GenSeqTypeList[2]);
extern void DefaultCoerceTo(void *dst, const void *src,
	const Type * dstClass, const Type *srcClass);
#define COERCE_FUNCTION DefaultCoerceTo
DEFINE_CLASS(MemoSeq,__GenSeqTypeList)

SplayMap::SplayMap() : map((Root*)0)
{
    len = 0;
}

SplayMap::SplayMap(Root *key1, Root *arg1) : map((Root*)0)
{
    len = 1;
    map[key1] = arg1;
}

SplayMap::SplayMap(int n, Root **keys, Root **args) : map((Root*)0)
{
    len = n;
    while ( --n >= 0 )
	map[*keys++] = *args++;
}

#if 0
GenFile * SplayMap::open(long flags=0) const
{
    return new SplayMapFile(this, flags);
}
#endif

Root *SplayMap::prefix(Root *key)
{
    if (FunctionLike(key)) return NULL;
    Pix p = ((SplayMap*)this)->map.seek(key);
    if (p == NULL) return Missing;
    return ((SplayMap*)this)->map.contents(p);
}

Root * MemoSubSeq::index(index_t i)
{
    if ((size_t)i >= len) return Missing;
    return this_memo.index(i + first);
}

GenSeq* MemoSubSeq::subseq(index_t start, index_t end)
{
    if (start < 0) start += leng() + 1;
    size_t new_len = len;
    if (end < 0) end += leng() + 1;
    int frst = start; int lngth = end-start;
    if (new_len != InfiniteLength && new_len != UnknownLength)
	new_len -= start;
    if (new_len >= lngth) new_len = lngth;
    return new MemoSubSeq(this_memo, first + start, new_len);
}

/* Used by AllocGenVar */
MemoSeq::MemoSeq(Functional *f, int seqs_count)
: MemoSubSeq(*this, 0, UnknownLength)
{
    first = 0;
    rule = f;
    link = this;
    cur_len = 0;
    allocated = 0;
    buf = NULL;
    _indexed_seqs_count = seqs_count;
}

MemoSeq::MemoSeq(Function *f, int seqs_count)
: MemoSubSeq(*this, 0, UnknownLength)
{
    first = 0;
    func = f;
    rule = GC_NEW GFunction(f, this);
    link = this;
    cur_len = 0;
    allocated = 0;
    buf = NULL;
    _indexed_seqs_count = seqs_count;
}

Root * MemoSeq::index(index_t i)
{
    int j;
    Root** p;
//  if (i >= fullLength) return Missing;
    if (i >= allocated) {
	size_t newLength = 2 * allocated;
	while (newLength <= i)
	    if (newLength == 0) newLength = 16;
	    else newLength += newLength;
	if (buf == NULL)
	    ((MemoSeq*)this)->buf = (Root**)GC_malloc(sizeof(Root*) * newLength);
	else
	    ((MemoSeq*)this)->buf = (Root**)GC_realloc(buf, sizeof(Root*) * newLength);
	p = buf + allocated;
	for (j = newLength - allocated; --j >= 0; p++)
	    *p = UnknownElement;
	((MemoSeq*)this)->allocated = newLength;
    }
    if (i >= cur_len) ((MemoSeq*)this)->cur_len = i+1;
    p = buf + i;
    if (*p == NewElement) { /* in case of recursive dependencies */
	*p = new CVariable();
    }
    if (*p == UnknownElement) {
	*p = NewElement;
	Root* val;
	Root* (params[func->clauses->nParams]);
#if 0
	if (func->clauses->nParams != indexed_seqs_count() + 1)
	  abort();
#endif
	params[0] = (Root*)MakeFixInt(i);
	int n_seqs = func->clauses->nParams - 1;
	GenSeq **iseqs = indexed_seqs();
	for (int j = 0; j < n_seqs; j++)
	  if ((params[1+j] = iseqs[j]->index(i)) == Missing)
	    {
	      val = Missing;
	      goto have_it;
	    }
	CATCH_MISSING(MemoSeqIndexHandler) {
	    ArgDesc args(NULL, params, NULL, NULL, 0, n_seqs + 1, 0);
//	    Function *func = ??;
	    ApplyClause(&val, &RefRoot, func->clauses, func, this, args);
	} HANDLE_MISSING(MemoSeqIndexHandler) {
	    val = Missing;
	} END_MISSING;
      have_it:
	if (*p != NewElement)
	    val->unify(**p);
	*p = val;
    }
    return *p;
}

#if 0
struct MemoSeqIter : public SeqIterator
{
  MemoSeq * memoSeq() { return (MemoSeq*)cltn; }
  GenFile **indexed_iters() { return (GenFile**)(this+1); }
  ~MemoSeqIter();
  virtual Root *next();
};

MemoSeqIter::~MemoSeqIter()
{
    GenFile **ind_iters = indexed_iters();
    int ind_iters_count = memoSeq()->indexde_seqs_count();
    for (i = 0; i < ind_iters_count; i++)
	delete ind_iters[i];
}

Root* MemoSeqIter::next()
{
    cur_i = ???;
    Root params[func->clauses->nParams];
    if (func->clauses->nParams != indexed_seqs_count() + 1)
	abort();
    int n_seqs = indexed_seq_count();
    GenSeq **iseqs = indexed_seqs();
    for (int j = 0; j < n_seqs; j++) {
	Root *el = indexed_iters[cur_i]->next();
	if (el == Missing)
	    ....;
	params[1+j] = el;
    }
    if (already_calculated)
	....;
    else {
	params[0] = (Root*)MakeFixInt(cur_i);
	ArgDesc args(NULL, params, NULL, NULL, 0, 1, 0);
	ApplyClause(&val, &RefRoot, func->clauses, func, this, args);
	memoize;
    }
}

int  MemoSeq::sizeof_file() const
{
    return sizeof(MemoSeqIter) + indexed_seqs_count() * sizeof(GenSeq**);
}

void MemoSeq::open(GenFile* file, OpenFlags flags=0)
{
    register MemoSeqIter *iter = (MemoSeqIter*)file;
    GenFile **ind_iters = iter->indexed_iters();
    int ind_iters_count = indexed_seqs_count();
    GenSeq **ind_seqs = indexed_seqs();
    for (i = 0; i < ind_iters_count; i++)
	ind_iters[i] = ind_seq[i]->open(flags);
}
#endif

size_t MemoSubSeq::length() { return len; }

void MemoSubSeq::printBare(ostream& outs) const
{
    if (!print_readable) {
	GenSeq::printBare(outs);
	return;
    }
    int prevWasSymbol = 0;
    for (size_t i = 0; ; i++) {
	if ((unsigned)i >= (unsigned)len)
	    return;
	if (i+first >= this_memo.cur_len)
	    break;
	Root *v = this_memo.buf[i+first];
	int curIsSymbol = v != UnknownElement &&
	    (v->magic() & BasicKindMask) == SymbolKind;
	if (i)
	    if (v != UnknownElement && v->mapping())
		outs << (char)print_list_separator;
	    else if (print_readable || !prevWasSymbol)
		outs << ' ';
	prevWasSymbol = curIsSymbol;
	if (v == UnknownElement)
	    outs << '_';
	else
	    v->printon(outs);
    }
    outs << " ...";
}

MemoMap::MemoMap(Functional *f) : map((Root*)0)
{
    rule = f;
    link = this;
    aux_map = NULL;
}

Root * MemoMap::prefix(Root *arg)
{
    int n = 0;
    int i;
    Root *v = NULL;
    MemoMap *m;

    // Count number of linked MemoMaps
    m = (MemoMap*)this;
    do {
	n++;
	m = m->link;
    } while (m != this);

    MemoMap **list = (MemoMap**)alloca(n * sizeof(MemoMap*));
    Root **vals = (Root**)alloca(n * sizeof(Root *));
    for (m = (MemoMap*)this, i = 0; i < n; i++, m = m->link) {
	list[i] = m;
	RootPtr *ref = &m->map[arg];
	if (*ref == NULL && m->aux_map != NULL) {
	    ref = &(*m->aux_map)[arg];
	}
	vals[i] = *ref;
	if (v == NULL) {
	    v = vals[i];
	    if (v == NULL) v = new CVariable();
	}
	// NOTE: should set up trail to delete on backtracking
	if (vals[i] == NULL) *ref = v;
    }
    for (i = 0; i < n; i++) {
	m = list[i];
	Root *val = vals[i];
	if (val == NULL) val = m->rule->prefix(arg);
	v->unify(*val);
    }
    return v;
#if 0
    RootPtr& ref = map[arg];
    if (ref != NULL) return ref;
    CVariable *v = new CVariable();
    if (aux_map) {
	RootPtr& ref2 = (*aux_map)[arg];
	ref2 = v;
    }
    else {
	ref = v;
    }
    return v;
#endif
}

void MemoMap::printon(ostream& outs) const
{
    outs << '[';
    PtrPtrSplayMap *smap = (PtrPtrSplayMap*)&map;
    Pix pix = smap->first();
    int i = -1;
    for (; pix != NULL; smap->next(pix)) {
	if (++i > 0) outs << ' ';
	smap->key(pix)->printon(outs);
	outs << "->";
	smap->contents(pix)->printon(outs);
    }
	  if (aux_map) {
	pix = aux_map->first();
	i = -1;
	for (; pix != NULL; aux_map->next(pix)) {
	    if (++i > 0) outs << ' ';
	    aux_map->key(pix)->printon(outs);
	    outs << "->";
	    aux_map->contents(pix)->printon(outs);
	}
    }
    outs << " ...]";
}


#if 0
UnifyMemoMaps(MemoMap *map1, MemoMap *map2)
{
    link together;
    map1->aux_map = new PtrPtrSplayMap((Root*0);
    map2->aux_map = new PtrPtrSplayMap((Root*0);
    ...;
    
    
}
#endif

SplayMapFile::SplayMapFile(const SplayMap *m, int flags = 0) : map(m)
{
    curIndex = ((PtrPtrSplayMap*)&map->map)->first();
}

Root * SplayMapFile::key()
{
    if (curIndex == NULL) return Missing;
    return ((PtrPtrSplayMap*)&map->map)->key(curIndex);
}

Root * SplayMapFile::next()
{
    if (curIndex == NULL) return Missing;
    Root *v = ((PtrPtrSplayMap*)&map->map)->contents(curIndex);
    ((PtrPtrSplayMap*)&map->map)->next(curIndex);
    return v;
}

int SplayMapFile::seek(Root *arg)
{
    Pix p = ((PtrPtrSplayMap*)&map->map)->seek(arg);
    if (p == NULL) return -1;
    curIndex = p;
    return 0;
}

AssignableSplayMap::AssignableSplayMap() : map((Root*)0)
{
}

Root *AssignableSplayMap::get(Root* key)
{
    if (FunctionLike(key)) return NULL;
    Pix p = ((PtrPtrSplayMap*)&map)->seek(key);
    if (p == NULL) return Missing;
    return ((PtrPtrSplayMap*)&map)->contents(p);
}

void AssignableSplayMap::printon(ostream& outs) const
{
    PtrPtrSplayMap& smap = *(PtrPtrSplayMap*)&map;
    Pix p = smap.first();
    for (; p != NULL; smap.next(p))
	outs << *smap.key(p) << ':' << *smap.contents(p) << '\n';
}

void AssignableSplayMap::put(Root* key, Root *val)
{
    if (val == Missing)
	map.del(key);
    else
	map[key] = val;
}

Root* AssignableSplayMap::value()
{
    abort();
}

size_t AssignableSplayMap::length()
{
    return ((PtrPtrSplayMap*)&map)->length();
}

Root * DoMemo(Root *arg)
{
  Functional *func = arg->functional();
  if (func == 0) RaiseDomainError(NULL);
  return new MemoMap(func);
}

#if 0
MapFile * AMap::mapopen(long flags=0) const
{
    return new MapFile(this, flags);
}
#endif
