/*******************************************************************************
+
+  LEDA 3.5
+
+  _g_array.c
+
+  This file is part of the LEDA research version (LEDA-R) that can be 
+  used free of charge in academic research and teaching. Any commercial
+  use of this software requires a license which is distributed by the
+  LEDA Software GmbH, Postfach 151101, 66041 Saarbruecken, FRG
+  (fax +49 681 31104).
+
+  Copyright (c) 1991-1997  by  Max-Planck-Institut fuer Informatik
+  Im Stadtwald, 66123 Saarbruecken, Germany     
+  All rights reserved.
+ 
*******************************************************************************/
#include <LEDA/graph.h>


//------------------------------------------------------------------------------
// graph maps and arrays 
//
// graph_map: base of node/edge/face_map/array
//
// by S. Naeher  (1995,1996)
//------------------------------------------------------------------------------

graph_map::~graph_map()
{ if (g && g_index != 0) g->unregister_map(this);
  if (table) delete[] table; 
 } 


int graph_map::next_power(int s) const
{ if (s==0) return 0;
  int p = 1;
  while (p < s) p <<= 1;
  return p;
}


void  graph_map::re_init_entry(node v)
{ if (g_index > -1) 
    init_entry(v->data[g_index]);
  else 
   { int i = index(v);
     if (i < table_size) 
     { clear_entry(table[i]);
       init_entry(table[i]);
      }
    }
 }


void  graph_map::re_init_entry(edge e)
{ if (g_index > -1) 
    init_entry(e->data[g_index]);
  else 
   { int i = index(e);
     if (i < table_size)
     { clear_entry(table[i]);
       init_entry(table[i]);
      }
    }
 }


void  graph_map::re_init_entry(face f)
{ if (g_index > -1) 
    init_entry(f->data[g_index]);
  else 
   { int i = index(f);
     if (i < table_size)
     { clear_entry(table[i]);
       init_entry(table[i]);
      }
    }
 }




void graph_map::init_table(GenPtr* start, GenPtr* stop)
{  if (g_index == -1)
     for(GenPtr* q=start; q < stop; q++) init_entry(*q);
   else
     if (g && g_index > 0)
     { 
       switch (kind) {
       case 0 : { node v;
                  forall_nodes(v,*g) init_entry(v->data[g_index]);
                  break;
                 }
       case 1 : { edge e;
                  forall_edges(e,*g) init_entry(e->data[g_index]);
                  break;
                 }
       case 2 : { face f;
                  forall_faces(f,*g) init_entry(f->data[g_index]);
                  break;
                 }
       }
     }
}

void graph_map::clear_table()
{ if (g_index == -1)
    { GenPtr* stop = table + table_size;
      for(GenPtr* q=table; q < stop; q++) clear_entry(*q);
     }
  else
     if (g && g_index > 0)
     { switch (kind) {
       case 0 : { node v;
                  forall_nodes(v,*g) clear_entry(v->data[g_index]);
                  break;
                 }
       case 1 : { edge e;
                  forall_edges(e,*g) clear_entry(e->data[g_index]);
                  break;
                 }
       case 2 : { face f;
                  forall_faces(f,*g) clear_entry(f->data[g_index]);
                  break;
                 }
       }
     }

 }

void graph_map::resize_table(int sz)
{ 
  GenPtr* old_table = table;
  GenPtr* old_stop  = table + table_size;
  
  table_size = sz;
  table = new GenPtr[sz];
  if (table == 0) error_handler(1," graph_map: out of memory");

  GenPtr* p = old_table; 
  GenPtr* q = table;
  while (p < old_stop) *q++ = *p++;

  init_table(q,table+sz);

  if (old_table != old_stop) delete[] old_table;
}


void graph_map::init(const graph* G, int sz, int k) 
{ 
  if (g != G)
  { if (g && g_index != 0) g->unregister_map(this);
    kind = k;
    g = (graph*)G;
    if (g) g_index = g->register_map(this);
  }

  if (g_index > -1) 
  { table = 0;
    table_size = 0;
    return; 
   }

  clear_table();
  if (table_size > 0) delete[] table;

  table = 0;

  table_size = next_power(sz);
  if (table_size > 0) 
  { table = new GenPtr[table_size];
    if (table == 0) error_handler(1," graph_map: out of memory");
   }
}


graph_map::graph_map(const graph* G, int k) 
{ kind = k; 
  g = (graph*)G;
  g_index = 0;
  table = 0;
  table_size = 0;
}


graph_map::graph_map(const graph* G, int sz, int k) 
{ 
  kind = k; 
  g = (graph*)G;
  g_index = -1;

  if (g) g_index =  g->register_map(this);

  if (g_index > -1) 
  { table = 0;
    table_size = 0;
    return; 
   }

  def_entry = 0;
  table = 0;
  table_size = next_power(sz);
  if (table_size > 0) 
  { table = new GenPtr[table_size];
    if (table == 0) error_handler(1," graph_map: out of memory");
   }
}


graph_map::graph_map(const graph_map& M)
{ kind = M.kind;
  g = M.g;
  if (M.g_index == 0)
  { g_index = 0;
    return;
   }
  g_index = -1;
  if (g) g_index = g->register_map(this);
  def_entry = 0;
  table = 0;
  table_size = M.table_size;
  if (table_size > 0)
  { table = new GenPtr[table_size];
    if (table == 0) error_handler(1," graph_map: out of memory");
    GenPtr* p = table;
    GenPtr* stop = M.table+M.table_size;
    for(GenPtr* q=M.table; q < stop; q++) 
    { *p = *q;
      M.copy_entry(*p); 
      p++;
     }
   }
}


graph_map& graph_map::operator=(const graph_map& M)
{ if (&M == this) return *this;
  clear_table();
  if (table_size > 0) delete[] table;
  if (g && g_index != 0) g->unregister_map(this);
  table = 0;
  kind = M.kind;
  g = M.g;
  if (M.g_index == 0)
  { g_index = 0;
    return *this;
   }
  g_index = -1;
  if (g) g_index = g->register_map(this);
  table_size = M.table_size;
  if (table_size > 0)
  { table = new GenPtr[table_size];
    if (table == 0) error_handler(1," graph_map: out of memory");
    GenPtr* p = table;
    GenPtr* stop = M.table+M.table_size;
    for(GenPtr* q=M.table; q < stop; q++) 
    { *p = *q;
      copy_entry(*p); 
      p++;
     }
   }
  return *this;
}

