#include "Object.h"
#include "value.h"
#include "List.h"
#include "parser.h"
#include <iostream.h>
#include <fstream.h>
#pragma implementation

/***********************************************************************
** on disk, an object will look like this:
** <parent1><parent2>...<parentn> -1  ... each is an integer (sizeof(long))
** <symboltable>\0<commandlist>\0
************************************************************************/

char* Object::pack_object (char* buffer){ 
  buffer = parents->dump(buffer);
  buffer = symbols.pack_syms (buffer);
  return commands.pack_cmds (buffer);
}

long nos=0;

Object::Object (char* buffer, int object_num){
  char* temp_buf;
  int pval;
  String* tempstring;
  Value* tempval;

  id = object_num;
  temp_buf = buffer;
  parents = new intlist (&temp_buf);
  while (*temp_buf)
    {tempstring = new String (temp_buf);
     temp_buf += tempstring->length() + 1;
     tempval = unpack_value (&temp_buf);
     symbols.add (tempval , tempstring);
     tempval->release();}
  temp_buf++;
  temp_buf = commands.unpack(temp_buf);
}

Object::Object (int oid, int iparent){
  parents = new intlist (iparent);
  id = oid;
}

#define MAX_LINE_LEN 40000

Object::Object (ifstream* input, int onum){
  int i, ilist [30], temptype;
  char templine [MAX_LINE_LEN];
  Value* tempval;
  String *sym, *key;

  id = onum;
  for (i=0 ; input->peek() != '\n' ; i++)  /** get parents **/
    *input >> ilist [i];
  ilist [i] = -1;
  parents = new intlist (ilist);
  input->get();
  while (input->peek() != '/')            /** get variables **/
    {key = new String;
     *input >> *key;
     sym = new String;
     while (input->peek() != '/')
       {input->getline (templine, MAX_LINE_LEN);
	*sym += templine;
	*sym += "\n";}
     input->getline (templine, MAX_LINE_LEN);
     tempval = parse_string (sym);
     if (!tempval)
       {cout << parse_fail_msg << "\n";
	cout << "In symbol: " << *key << "\n";
	exit (1);}
     temptype = (int) tempval->type;
     *sym += "  ";  /** horrible kludge **/
     delete sym;
     if ((int) tempval->type != temptype)
       {cout << "tempval was changed.\n";
	exit (1);}
     symbols.add (tempval, key);
     tempval->release();}
  input->getline (templine, MAX_LINE_LEN);
  while (input->peek() != '/')            /** get commands **/
    {input->getline (templine, MAX_LINE_LEN);
     tempval = parse_string (key = new String (templine));
     if (! (tempval->get_type() == LIST))
       {cerr << "invalid command: " << *key << "\nnot a list.\n";
	exit (1);}
     input->getline (templine, MAX_LINE_LEN);
     sym = new String (templine);
     if (! commands.add (tempval->list->copy(), sym))
       {cerr << "invalid command: " << *key
	  << "\nnot a valid command list format.\n";
	exit (1);}
     tempval->release();
     delete key;}
  input->getline (templine, MAX_LINE_LEN);
}

Object::~Object(){
  delete parents;
}

void Object::dump_to_stdout (){
  parents->dump_to_stdout();
  symbols.dump_to_stdout();
  cout << "/\n";
  commands.dump_to_stdout();
  cout << "/+++++++++++++ end of object #" << id << " +++++++++++++\n";  
};

Value* Object::get_parent_list(){
  return parents->toval();
}

Value* Object::tostr(){
  Value* retval, *temp;
  retval = new Value (id, OBJ);
  retval->tostr();
  temp = get_parent_list();
  temp->tostr();
  retval->add(temp);
  temp->release();
  temp = symbols.list_vars();
  temp->tostr();
  retval->add(temp);
  temp->release();
  temp = commands.list_cmds();
  temp->tostr();
  retval->add(temp);
  temp->release();
  return retval;
}

int Object::set_sym (Value* v, String* s){
  return symbols.add (v, s);
}
int Object::rm_sym (String* s){
  return symbols.remove (s);
}


int Object::add_cmd (Val_List* key, String* data){
  return (commands.add (key, data)) ? 1 : 0;
}

int Object::rm_cmd (String* key){
  return commands.remove (key);
}

void Object::purge_cmds (){
  commands.purge ();
}

int Object::change_parents (int* ilist){
  delete parents;
  parents = new intlist (ilist);
  return 1;
}


/***************************************************
** methods for the intlist class *******************
****************************************************/


intlist::intlist(int iparent, int max){
  list = new int [max];
  allocated = max;
  size = 0;
  if (iparent >= 0)
    list [size++] = iparent;
}

intlist::intlist(char** inbuff_ptr, int max){
  char* buf;
  int i;
  buf = *inbuff_ptr;
  size = (int) *buf++;
  allocated = (max > size ? max : size);
  list = new int [allocated];
  memcpy (list , buf , (size * (sizeof (long))));
  *inbuff_ptr = buf + (size * (sizeof (long)));
}

intlist::intlist(int* inlist, int max){
  list = new int [max];
  for (size=0 ; inlist[size] >= 0 ; size++)
    {list[size] = inlist[size];
     if (size >= max)
       {grow(max);
	max += 2;}}
  allocated = max;
}

intlist::intlist(){
  list = new int [allocated = MAXPARENTS];
  size = 0;
}

intlist::~intlist(){
  delete list;
}

intlist::check_is_inlist (int i){
  int j;
  for (j=0 ; j<size ; j++)
    if (list[j] == i)
      return 1;
  return 0;
}

void intlist::grow(int by){
  int i, *templist;
  templist = new int [allocated + by];
  for (i=0 ; i<allocated ; i++)
    templist[i] = list[i];
  allocated += by;
  delete list;
  list = templist;
}

void intlist::set_contents (intlist source){
  int i;
  if (source.size >= allocated)
    grow (source.size - allocated + 1);
  for (i = 0 ; i<source.size ; i++)
    list[i] = source.list[i];
  size = source.size;
}

void intlist::pop(){
  if (size > 0)
    size--;
}

void intlist::dump_to_stdout(){
  int j;
  for (j=0 ; j<size ; j++)
    {cout << list[j];
     if (j+1 != size)
       cout << " ";}
  cout << "\n";
}

int intlist::peek(){
  return ((size > 0) ? list[size-1] : -1);
}

void intlist::push(int inval){
  list[size++] = inval;
  if (size >= allocated)
    grow ();
}

char* intlist::dump (char* buf){
  *buf++ = (char) size;
  memcpy (buf , list , (size * (sizeof (long))));
  return buf + (size * (sizeof (long)));  
}

Value* intlist::toval (){
  int j;
  Val_List* i;
  for (j=0 , i=NULL ; j<size ; j++)
    i = new Val_List (new Value (list[j], OBJ), i);
  return new Value (i);
}