#define bitmask unsigned int
#define MAXMASKS 4
#define maskwidth (8*sizeof(bitmask))
#define STACKMAX 32

typedef bitmask bitsig[MAXMASKS+1];
int     freqs[27];
bitsig  uflosig;
bitsig  bagsig;
bitsig  bagsigcopy;
int     letmask[27];
int     letbit[27];
int     letwidth[27];
int     lastmask;

void die (char *ermsg);

int fieldwidth(int num)
{
  int tot = 0;
  while (num != 0) {
    tot += 1;
    num = num >> 1;
  }
  return(tot+1);
}

void choosefields(int *freqs)
{
  int letter;
  int curmask = 0, curbit = 0;
  int width;

  for (letter = 0; letter < 27; letter++)
    if (freqs[letter] != 0) {
      width = fieldwidth(freqs[letter]);
      if (curbit+width > maskwidth) {
        if (++curmask >= MAXMASKS) die("Sorry: Phrase too long to handle.\n");
        curbit = 0;
      }
      letmask[letter] = curmask;
      letbit[letter] = curbit;
      letwidth[letter] = width;
      curbit += width;
/*fprintf(errfile,"Field %c: w=%d\n", letter+'a',width);*/
    }
  if (curmask > lastmask) lastmask = curmask;
/*  fprintf(errfile,"1:lastmask=%d\n",lastmask);*/
}

void makefreqs(char *str, int *freq)  /* NEEDS WORK FOR I18N */
{
  char c;
  int i;
  for (i = 0; i < 27 /* 26 english letters + blank */; i++) freq[i] = 0;
  while ((c = *str++) != '\0') {
    assert((c == '?') || isalpha(c));
    if (c == '?') { // the wild card comes after Z
      freq[26] += 1;
    } else {
      if (('A' <= c) && (c <= 'Z')) c += 32;
      c -= 'a';
      if ((c >= 0) && (c < 26)) freq[c] += 1;
    }
  }
}

void printone(bitmask b) {
  int i;
  for (i = 31; i >= 0; --i) {
    fprintf(errfile, "%c", ((b>>i)&1) + '0');
  }
}

void printmask(char c, bitmask *sig) {
   fprintf(errfile,"%c", c);
   printone(sig[0]);
   if (lastmask > 0) printone(sig[1]);
   if (lastmask == 2) printone(sig[2]);
   fprintf(errfile," (%d)\n", lastmask);
}

void makeonesig(register char *str, bitmask sig[])
{
  char c;

  sig[0] = sig[1] = sig[2] = 0;
  while ((c = *str++) != '\0') {
    if (c == '?') c = 'z'+1; // the wild card comes after Z
    else c |= 32; // English set only.  Make lower
    c -= 'a'; // 0..26 (a-z, blank)
    sig[letmask[c]] += 1<<letbit[c];
  }
}

void makeuf(int freqs[], int letmask[], int letbit[], int letwidth[])
{
  int l;
  int bnum, bwidth;

  for (l = 0; l <= MAXMASKS; l++) uflosig[l] = 0;

  for (l = 0; l < 27; l++)
    if (freqs[l] != 0) {
      bnum = letbit[l];
      bwidth = letwidth[l];
      uflosig[letmask[l]] += (1L << (bnum+bwidth-1));
    }
}

void die (char *ermsg)
{
  fprintf(errfile, ermsg);
  exit(0);
}

// 0: no match
// 1: play == rack
// 2: all tiles in play are in rack with some left over
int COMPATIBLE(bitsig playsig, bitsig racksig) /* Can we make this play using this rack? */
{
      bitmask *curnode = racksig;
      bitsig newsig;
      bitmask newmask;
      bitmask *cursig  = playsig;
      int bitsleft, matched;
      char *sp;
      char errbuff[1024];

#define DOMASK(MASK) { \
  newmask = curnode[MASK] - cursig[MASK]; \
  if ((newmask & uflosig[MASK])) {matched = FALSE; break;} /* FROM SWITCH */ \
  newsig[MASK] = newmask; \
  bitsleft = bitsleft | newmask; \
  /*fprintf(errfile,"curnode: %08X - cursig: %08X, bitsleft: %08X, newsig%0d: %08X, uflosig: %08X\n",*/ \
  /*        curnode[MASK], cursig[MASK], bitsleft, MASK, newmask, uflosig[MASK]);*/ \
}

      bitsleft = 0;
      matched = TRUE; sp = errbuff; *sp = '\0';
      switch (lastmask) {
      /* DOMASK issues a "break" from the switch if not compatible */
      case 2: DOMASK(2)  /* 3 calls to DOMASK allows up to 48 different letters */
      case 1: DOMASK(1)  /* because I think one language has 33 letters */
      case 0: DOMASK(0)  /* and 2 calls are not enough */
      }
//      fprintf(errfile, "%s", errbuff);
      if (matched) {
        if (!bitsleft) {
          /* exact match.  Remove lower-scoring item */
          //fprintf(errfile, "Exact (Bingo) match!:\n");
          return(1);
        } else {
          /* we can make this play and have some tiles left over */
          //fprintf(errfile, "Subset match:\n");
          return(2);
        }
      } else {
        /* otherwise we could not make this play */
        //fprintf(errfile, "No match:\n");
        return(0);
      }
}