/**********************************************************************
This file is part of Crack dot Com's free source code release of Golgotha.
for information about compiling & licensing issues visit this URL
 If that doesn't help, contact Jonathan Clark at 
  golgotha_source@usa.net (Subject should have "GOLG" in it) 
***********************************************************************/

#include "saver.hh"
#include "checksum/checksum.hh"
#include "memory/malloc.hh"
#include "g1_object.hh"

// Saver methods

g1_saver_class::g1_saver_class(i4_file_class *out, i4_bool close_on_delete)
  : i4_saver_class(out, close_on_delete), remap(0)
{
  t_refs=0;
  state=DIRECTORY_CREATE;
  current_offset=out->tell();
}

g1_saver_class::~g1_saver_class()
{
  g1_global_id.free_remapping(remap);
}

void g1_saver_class::set_helpers(g1_object_class **reference_list, w32 total_references)
{ 
  ref_list=reference_list;
  t_refs=total_references;

  remap = g1_global_id.alloc_remapping();
  for (w32 i=0; iglobal_id] = i;
}

i4_bool g1_saver_class::write_global_id(w32 id)
{
  if (state==DIRECTORY_CREATE)
  {
    current_offset+=2;
    return i4_T;
  }
  else
  {
    w16 found=0xffff;
    if (g1_global_id.check_id(id))
      found = (*remap)[id];

    out->write_16(found);

    if (found==0xffff)
      return i4_F;
  }

  return i4_T;
}

i4_bool g1_saver_class::write_reference(const g1_reference_class &ref)
{
  if (state==DIRECTORY_CREATE)
  {
    current_offset+=4;
    return i4_T;
  }
  else
  {
    w16 found=0;

    if (ref.ref)
    {
      for (w32 i=0; !found && iwrite_16(found);
    } 
    else 
      out->write_16(0);

    // blank for notifee
    out->write_16(0);
  }

  return i4_T;
}


// Loader methods

g1_loader_class::g1_loader_class(i4_file_class *in, i4_bool close_on_delete)
  : i4_loader_class(in, close_on_delete), id_remap(0)
{
  ref_list=0;
  first_ref=0;
  li_remap=0;
}

g1_loader_class::~g1_loader_class()
{
  if (id_remap)
  {
    g1_global_id.claim_freespace();
    i4_free(id_remap);
  }
}

void g1_loader_class::set_remap(w32 total_references)
{ 
  t_refs=total_references;
  id_remap = (w32 *)i4_malloc(total_references*sizeof(*id_remap), "loader_remapping");
  for (int i=0; iread_16();
  if (i==0xffff || !id_remap)
    return g1_global_id.invalid_id();
  else
    return id_remap[i];
}

void g1_loader_class::read_reference(g1_reference_class &ref)
{
  w16 index=in->read_16();
  ref.ref=0;                            // clear out hi bits
  ref.ref=(g1_object_class *)index;

  // read blank for notifee
  in->read_16();

  if (ref.ref)    // if non-0 reference we need to modify it later, so add to list
  {
    ref.next=first_ref;
    first_ref=&ref;
  }
  else
    ref.next=0;
}


void g1_loader_class::convert_references()
{
  g1_reference_class *f,*next;

  for (f=first_ref; f;)
  {
    next=f->next;
    g1_object_class *r;

    w16 ref=*((w16 *)&f->ref);
    if (ref==0)
      r=0;
    else   
    {
      ref--;
      if (refref=0;
    
    f->reference_object(r);
    
    f=next;
  }
  first_ref=0;
}



g1_loader_class *g1_open_save_file(i4_file_class *in, i4_bool close_on_delete_or_fail)
{
  g1_loader_class *l=new g1_loader_class(in, close_on_delete_or_fail);
 
  if (l->error())
  {
    delete l;
    return 0;
  }

  return l;
}