/* ************************************* */
/*   repack2.c                           */
/*   Copyright 2001 Martin L"auter       */
/*     used old Graham Toal code         */
/*   laeuter@mathematik.uni-leipzig.de   */
/* ************************************* */

#include <stdio.h>
#include <stdlib.h>
#include "dawg.h"
#include "aoften.c"

#define EMPTY 0xaaaaaaa0
#define M_OCCUPIED (1L<<V_END_OF_NODE)
#define MAX_DIFF 32

unsigned int this_node[MAX_CHARS];
NODE *idawg;
NODE *odawg;
int iptr,osize,optr;

int first_possible;

int get_node(int ptr)
{ int i;long mask;
  unsigned int w;
  if(ptr!=1) {
    memset(this_node,0,sizeof(long)*MAX_CHARS);//for(i=0;i<MAX_CHARS;i++) this_node[i]=0;
    w=idawg[--ptr]&(~M_END_OF_NODE);
    mask=0;
    do {
      this_node[i=LTR(w)]=w;
      mask|=(1<<i);
    } while(((w=idawg[--ptr]) & M_END_OF_NODE)==0);
    this_node[0]=mask;
    return(++ptr);
  } else return(0);
}

int compatible(int node)
{ int i;
  if(odawg[node]&M_OCCUPIED) return(FALSE);
  for(i=0;i<MAX_CHARS;i++) {
    if(this_node[i] && (odawg[node+i]&(~M_OCCUPIED))!=EMPTY) return(FALSE);
  }
  return(TRUE);
}

int pack_node()
{ int i,j;
  j=first_possible;
  while(!compatible(j)) j++;
  for(i=0;i<MAX_CHARS;i++) {
    if(this_node[i]) odawg[j+i]=this_node[i];
  }
  odawg[j]|=M_OCCUPIED;
  if(j>first_possible+MAX_DIFF) { int found;
    while((odawg[first_possible]&(~M_OCCUPIED))!=EMPTY) first_possible++;
    found=FALSE;
    for(i=first_possible;i<first_possible+MAX_CHARS;i++) {
      if((odawg[i]&(~M_OCCUPIED))==EMPTY) {found=TRUE;break;}
    }
    if(!found)
      while((odawg[first_possible+MAX_CHARS]&(~M_OCCUPIED))!=EMPTY) first_possible++;
    if(j>first_possible+20*MAX_DIFF) first_possible+=1;
  }
  return(j);
}

void relocate()
{ int i;
  unsigned int w;
  i=osize>>2;
  while(odawg[--i]==EMPTY);
  optr=i+1;
//  printf("%x,%x\n",odawg[i],idawg[0]);
  idawg[0]=0;
  for(i=0;i<optr;i++) {
    if((w=(odawg[i]&(~M_OCCUPIED)))==EMPTY) {
      odawg[i]=0x5eebade5;
    } else {
      if((odawg[i]&M_OCCUPIED)==0)
        odawg[i]=((w&(~M_NODE_POINTER))|(idawg[IDX(w)]<<V_POINTER))&(~M_OCCUPIED);
      else odawg[i]=w;
    }
  }
}

main(int argc,char **argv)
{ int i,j;
  FILE *h;
  long dwginfo[4];
  char inname[40],outname[40];

  if(argc!=2) {
    fprintf(stderr,"usage: repack2 file\n");
  } else {
    sprintf(inname,"%s.dwg",argv[1]);
    sprintf(outname,"%s.pck2",argv[1]);
    if((idawg=load_dwg(inname,dwginfo))!=NULL) {
      if((odawg=(NODE *)malloc(osize=(dwginfo[1]*50)/15))!=NULL) {
        for(j=(osize>>2)-1;j>=0;j--) odawg[j]=EMPTY;
        i=dwginfo[1]>>2;
        first_possible=1;
        idawg[0]|=M_END_OF_NODE;
        while(i=get_node(i)) {
          idawg[i]=pack_node();
        }
        relocate();
        if((h=fopen(outname,"wb"))==NULL) { fprintf(stderr,"Failed to create file"); } else {
          long pckinfo[4];
          pckinfo[0]=0xff000001;
          pckinfo[1]=optr*sizeof(NODE);
          pckinfo[2]=idawg[dwginfo[2]>>2]*sizeof(NODE);
          fwrite(pckinfo,4,4,h);
          fwrite(odawg,4,optr,h);
          fclose(h);
        }
        free(odawg);
      } else fprintf(stderr,"Failed to get %d bytes of memory\n",osize);
      free(idawg);
    } else fprintf(stderr,"Failed to open file %s\n",inname);
  }
  return(0);
}

