/*
   NAME:     Chain
   AUTHOR:   Ole Gunnar Westgaard
   DATE:     Jul 28 1995
             
*/

#include "otools.h"

//=============================================================================
// Chain handling routines
//=============================================================================

Chain::Chain()                                      // Construct as empty chain
{
  fig  = NULL;
  next = NULL;
}

Chain::Chain(Figlet *f)                         // Construct with first element
{
  fig = f;
  next = NULL;
}

Chain::Chain(Chain *c)                   // Create new chain as copy of a chain
{                                     // Will not copy the actual figlets (NB!)
  Chain *n = this;
  while (c && c->fig) {
    n->fig = c->fig;
    if (c->next) {
      n->next = new Chain();
      n = n->next;
    }
    c = c->next;
  }
}

int Chain::Size()                                    // Calculate size of chain
{
  Chain *c = this;
  int    t = 0;
  while (c && c->fig) { t++; c=c->next; }
  return t;
}

void Chain::Add(Figlet *f)                       // Add a figlet last in chain
{
  if (! fig) fig = f;                      // No figlet in this element, add it
  else {
    Chain *c = this;
    while (c->fig && c->next) c = c->next;
    if (! c->fig) c->fig = f;
    else c->next = new Chain(f);
  }
}

void Chain::Add(Chain *c)               // Add a chain to the end of this chain
{
  Chain *n = this;
  if (!c || !c->fig) return;     // Don't do anything if chain to copy is empty
  while (n->next) n = n->next;                        // Find end of this chain
  if (!n->fig) {     // Add first of copychain to this chain if figlet is empty
    n->fig = c->fig;
    c = c->next;
  }
  while (c && c->fig) {           // Copy the rest of the chain onto this chain
    n->next = new Chain(c->fig);
    n=n->next;
    c=c->next;
  }
}

void Chain::Draw(void)
{
  Chain *c = this;
  while (c && c->fig) {
    c->fig->DrawFrame();
    c->fig->Draw();
    c = c->next;
  }
}

void Chain::IntelligentDraw(int x,int y,int w,int h)      // Draw exposed areas
{
  Chain *c = this;

  while (c && c->fig) {

  if (  x    <= (c->fig->xb+3) &&
        y    <= (c->fig->yb+3) &&
       (x+w) >= (c->fig->xa-3) &&
       (y+h) >= (c->fig->ya-3) )
    {
      c->fig->DrawFrame();
      c->fig->Draw();
    }
    c = c->next;
  }
}

//-----------------------------------------------------------------------------
// Arrange a chain inside a specified block, specifying space between (dx,dy)
// and number of columns/rows (one should be set to zero), and blocksize
void Chain::Stack(int xa,int ya,int xb,int yb,int colx,int coly,int dx,int dy)
{
  Chain *chain = this;
  int   nr = Size();
  float w,
        h;
  int   a=0,
        b=0;
  if(!colx && !coly && !dx && !dy) {            // Default if unused parameters
    dx = 5; dy = 5; colx=1; coly=0;
  }
  if (!colx && !coly) { colx = 1; coly = 0; }       // someone gotta be nonzero
  if (colx && coly) { coly = 0; }                   // someone gotta be    zero
  if (colx)
    colx = (nr<colx) ? nr : colx ;
  else
    coly = (nr<coly) ? nr : coly ;
  dx++; dy++;
  if (!coly) coly = (int) ceil( (double) nr / (double) colx ) ;
  if (!colx) colx = (int) ceil( (double) nr / (double) coly ) ;
  w = ((float)(xb-xa) - (float)((colx-1)*dx)) / (float)colx;
  h = ((float)(yb-ya) - (float)((coly-1)*dy)) / (float)coly;
  while ( (a+b*colx)< nr )                    // Stack all figlets inside block
  {
    chain->fig->xa= xa+(int) ((float)  a   *( w + (float) dx));
    chain->fig->ya= ya+(int) ((float)  b   *( h + (float) dy));
    chain->fig->xb= xa+(int) ((float) (a+1)*( w + (float) dx) - (float) dx);
    chain->fig->yb= ya+(int) ((float) (b+1)*( h + (float) dy) - (float) dy);
    chain = chain->next;
    a++;
    if (a>=colx) {
      a=0;
      b++;
    }
  }
}

void Chain::Show(char *name)
{
  Chain *n = this;
  printf("\n\nChain '%s' information:\n",name);
  while (n) {
    printf("  (%4lX->%4lX) Fig: %4lX",n,n->next,n->fig);
    if (n->fig) printf(" %s\n",n->fig->ShowShort()); else printf("\n");
    n=n->next;
  }
  //getchar();
}

void Chain::Remove(char *name)
{
  Chain *n = this,*t;
  while (n && n->fig) {
    if (strcmp(n->fig->message,name)==0) {
      if (!n->next || !n->next->fig) {     // If match and last figlet in chain
	n->fig = NULL;
	if (n->next) delete n->next;
      }
      else {               // Remove this instance by copying the next instance
	n->fig = n->next->fig;
	t = n->next;
	n->next = n->next->next;
	delete t;
      }
    }
    n = n->next;
  }

}
