/*
**  This file is part of Zterp, and is
**  Copyright 1992, 1993 Charles Hannum
*/

#include <sys/types.h>
#include "main.h"
#include "object.h"
#include "variable.h"
#include "jump.h"

zpointer
object_ptr (uword n)
{
  if (zil_version <= 3)
    return (object + 9 * n);
  else
    return (object + 14 * n);
}

static uword
get_parent (zpointer o)
{
  if (zil_version <= 3)
    return (get_byte (o + 4));
  else
    return (get_word (o + 6));
}

static uword
get_sibling (zpointer o)
{
  if (zil_version <= 3)
    return (get_byte (o + 5));
  else
    return (get_word (o + 8));
}

static uword
get_child (zpointer o)
{
  if (zil_version <= 3)
    return (get_byte (o + 6));
  else
    return (get_word (o + 10));
}

uword
get_data (zpointer o)
{
  if (zil_version <= 3)
    return (get_word (o + 7));
  else
    return (get_word (o + 12));
}

static void
set_parent (zpointer o, uword n)
{
  if (zil_version <= 3)
    set_byte (o + 4, (zbyte) n);
  else
    set_word (o + 6, n);
}

static void
set_sibling (zpointer o, uword n)
{
  if (zil_version <= 3)
    set_byte (o + 5, (zbyte) n);
  else
    set_word (o + 8, n);
}

static void
set_child (zpointer o, uword n)
{
  if (zil_version <= 3)
    set_byte (o + 6, (zbyte) n);
  else
    set_word (o + 10, n);
}

void
set_data (zpointer o, uword n)
{
  if (zil_version <= 3)
    set_byte (o + 7, n);
  else
    set_word (o + 12, n);
}

void
store_sibling (n)
  uword n;
{
  uword a = get_sibling (object_ptr (n));
  store_variable_push (a);
  return_or_jump (a != 0);
}

void
store_child (n)
  uword n;
{
  uword a = get_child (object_ptr (n));
  store_variable_push (a);
  return_or_jump (a != 0);
}

void
store_parent (n)
  uword n;
{
  uword a = get_parent (object_ptr (n));
  store_variable_push (a);
}

void
insert_object (n1, n2)
  uword n1, n2;
{
  zpointer o1 = object_ptr (n1),
	   o2 = object_ptr (n2);
  remove_object (n1);
  set_parent (o1, n2);
  set_sibling (o1, get_child (o2));
  set_child (o2, n1);
}

void
remove_object (n1)
  uword n1;
{
  zpointer o1 = object_ptr (n1);
  uword n2 = get_parent (o1);

  if (n2)
  {
    zpointer o2 = object_ptr (n2);
    uword n3 = get_child (o2);
    if (n3 == n1)
      set_child (o2, get_sibling (o1));
    else
    {
      zpointer o3 = object_ptr (n3);
      uword n4;
      while ((n4 = get_sibling (o3)) != n1)
	o3 = object_ptr (n4);
      set_sibling (o3, get_sibling (o1));
    }
  }

  set_parent (o1, 0);
  set_sibling (o1, 0);
}

void
test_attribute (n, b)
  /* jump if attribute not set */
  uword n, b;
{
  zpointer p = (zpointer) object_ptr (n);
  p += (b >> 3);
  return_or_jump ((get_byte (p) >> ((~ b) & 7)) & 1);
}

void
set_attribute (n, b)
  uword n, b;
{
  zpointer p = (zpointer) object_ptr (n);
  p += (b >> 3);
  set_byte (p, get_byte (p) | (1 << ((~ b) & 7)));
}

void
clear_attribute (n, b)
  uword n, b;
{
  zpointer p = (zpointer) object_ptr (n);
  p += (b >> 3);
  set_byte (p, get_byte (p) & ~ (1 << ((~ b) & 7)));
}

void
inside_object (a, b)
  uword a, b;
{
  return_or_jump (get_parent (object_ptr (a)) == b);
}
