/* -*- Mode: c++ -*-
 *  $Id: s.xotclReference.c 1.1 00/09/13 20:19:53-00:00 neumann $
 *  
 *  Extended Object Tcl (XOTcl)
 *
 *  Copyright (C) 1999-2000 Gustaf Neumann, Uwe Zdun
 *
 *
 *  xotclReference.c --
 *  
 *  XOTcl Object References
 *  
 */

#include "xotclInt.h"

#ifdef OBJ_REFERENCES
void
ReferenceDeleteList(Tcl_Interp* in, XOTclObject* obj) {
  Tcl_HashSearch hSrch;
  Tcl_HashEntry *refByHPtr, *refHPtr = &obj->references ?
    Tcl_FirstHashEntry(&obj->references, &hSrch) : 0;
  /*
   * discard all existing references
   */
  /*fprintf(stderr, "  +++ Removing all references from: %s \n",
    ObjStr(obj->cmdName));*/
  while (refHPtr) {
    XOTclObject* ref = (XOTclObject*)Tcl_GetHashKey(&obj->references, refHPtr);
    if (ref) {
      refByHPtr = Tcl_FindHashEntry (&ref->referencedBy, (char*) obj);
      if (refByHPtr) Tcl_DeleteHashEntry(refByHPtr);
    }
    Tcl_DeleteHashEntry(refHPtr);
    refHPtr = Tcl_FirstHashEntry(&obj->references, &hSrch);
  }
}

void
ReferenceDiscardReferencesToObj(Tcl_Interp* in, XOTclObject* obj) {
  Tcl_HashSearch hSrch;
  Tcl_HashEntry *refHPtr, *refByHPtr = &obj->referencedBy ?
    Tcl_FirstHashEntry(&obj->referencedBy, &hSrch) : 0;
  /*
   * visit all objects that reference obj and discard these refs
   */
  /*fprintf(stderr, "  +++ Removing all references to: %s \n",
    ObjStr(obj->cmdName));*/
  while (refByHPtr) {
    XOTclObject* refBy = (XOTclObject*)Tcl_GetHashKey(&obj->referencedBy, refByHPtr);
    if (refBy) {
      refHPtr = Tcl_FindHashEntry (&refBy->references, (char*) obj);
      if (refHPtr) Tcl_DeleteHashEntry(refHPtr);
    }
    Tcl_DeleteHashEntry(refByHPtr);
    refByHPtr = Tcl_FirstHashEntry(&obj->referencedBy, &hSrch);
  }
}

void
XOTclReferenceAddRef(Tcl_Interp* in, XOTclObject* obj, XOTclObject *referenced) {
  int nw;
  /*
   * create ref and don't care whether the ref is already existing
   */
  /*fprintf(stderr, "  +++ Adding reference: %s -> %s \n",
    ObjStr(obj->cmdName), ObjStr(referenced->cmdName));*/
  (void) Tcl_CreateHashEntry(&referenced->referencedBy, (char*)obj, &nw);
  (void) Tcl_CreateHashEntry(&obj->references, (char*)referenced, &nw);
}

int
XOTclIsReferencedBy(XOTclObject* obj, XOTclObject* refObj) {
  Tcl_HashEntry *hPtr =
    Tcl_FindHashEntry (&obj->referencedBy, (char*) refObj);
  if (hPtr)
    return 1;
  return 0;
}

void
XOTclReferenceDestroy(Tcl_Interp* in, XOTclObject* obj) {
  ReferenceDeleteList(in, obj);
  ReferenceDiscardReferencesToObj(in, obj);
  Tcl_DeleteHashTable(&obj->references);
  Tcl_DeleteHashTable(&obj->referencedBy);
}

void
XOTclReferenceInit(XOTclObject* obj) {
  Tcl_InitHashTable(&obj->references, TCL_ONE_WORD_KEYS);
  Tcl_InitHashTable(&obj->referencedBy, TCL_ONE_WORD_KEYS);
}

#endif
