/* concprog.c: to generate a contextualised dictionary of forms from
   tagged texts -- a concordance */

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>

#define STRLEN 100
#define MAXWDS 10000
#define MAXFMS 1000
#define MAXTAGS 50
#define MAXCON 50
#define MAXTFS 150
#define MAXLINE 80
#define CONTLINES 4

FILE *flist, *keyf, *tgf, *tgd, *outf, *chf;

struct tag_word{

char *tag;
char *form;
int sub;
};

struct targets{

char *x_tag;
char *x_form[MAXTFS];
int x_count;
};

struct con_txt{

char *keytag;
char *keyform;
char *prewds[MAXCON];
char *postwds[MAXCON];
char *pretags[MAXCON];
char *posttags[MAXCON];
char *in_file;
int backstop;
int longstop;
int idno;
char *year;
};

void do_fail( char *);
void get_targets();
void get_data();
struct tag_word *read_ttext();
void compare_tags();
struct con_txt *get_contxt( int);
char *read_string(FILE *);
void sort_files();
void sort_data();
void qs( int, int);
void print_conco();

struct tag_word *tx[MAXWDS];
struct targets *target[MAXTAGS];
struct con_txt *p[MAXFMS];
char *fname, *tx_date;
int by_tag, con_total, postwords, prewords, sortcode, tagcode, targ_total, text_total, tx_id;

int main( int argc, char *argv[])
{

  prewords = atoi(argv[1]); /* scanf("%d",&prewords); */

  postwords = atoi(argv[2]); /* scanf("%d",&postwords); */

  ++postwords;

  tagcode = atoi(argv[3]); /* scanf("%d",&tagcode); */

  sortcode = atoi(argv[4]); /* scanf("%d",&sortcode); */



  get_targets();

  if( (flist = fopen("../../../../usr/local/web/data/ihd/laos/filelist.tag","r")) == 0)
    do_fail( "filelist.tag");
  else
  {
    fname = (char *)malloc(STRLEN);
    fscanf( flist,"%s",fname);
  }
 
/*
  if( (keyf = fopen("./conkey.txt","w")) == 0)
    do_fail( "conkey.txt");
  
  if( (outf = fopen("./concout","w")) == 0)
    do_fail( "concout");

  if( (chf = fopen("./checkinput","w")) == 0)
    do_fail( "checkinput");
*/

  con_total = 0;

  while( *fname != '!')
  {
    if( (tgf = fopen(fname,"r")) == 0)
      do_fail( fname);

/*
  printf("\n\n\t%s\n\n",fname);

  printf("\n\t][ Reading file '%s'\n",fname);
*/
    if( *fname!='!')
      get_data();

    fclose(tgf);
    fscanf( flist,"%s",fname);
  }

/*fclose(chf);*/

  if( con_total > 2)
  {
    if( sortcode)
      sort_files();
    else
      sort_data();
  }

  if( con_total > 0)
    print_conco();

fclose(flist);

/*
fclose(keyf);
fclose(outf);
*/

return(0);

}

/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */

void get_targets()

{
int d, j, k, v, w;

  if( (tgd = fopen("../../../../usr/local/web/data/ihd/laos/tagdic","r")) == 0)
    do_fail( "tagdic");

  j = 0;

  while( ( d=fgetc(tgd)) != EOF)
  {
    if( !feof(tgd))
      ungetc(d,tgd);

    while( (( d=fgetc(tgd)) != EOF) && !(d=='!'))
      ;

    if( !feof(tgd))
    {
      target[j] = (struct targets *)malloc(sizeof(struct targets));
      target[j]->x_count = 0;

      target[j]->x_tag = read_string(tgd);

      k = 0;


      while( ((d=fgetc(tgd))!=EOF) && !(d=='$' || d=='!'))
      {
        while( ((d=fgetc(tgd))!=EOF) && !(d=='$' || d=='!' || d=='@'))
          ;

        if( d=='@')
        {
          target[j]->x_form[k] = read_string( tgd);
          ++k;
          target[j]->x_count = k;
        }
        if( !feof(tgd))
          ungetc(d,tgd);
      }
      ++j;
    }

    if( !feof(tgd))
      ungetc(d,tgd);
  } 

  targ_total = j;
/*

for( v=0; v<targ_total; ++v)
{
  printf("\n%s",target[v]->x_tag);

  if( target[v]->x_count>0)
  {
    w = 0;
    while( w< target[v]->x_count>0)
    {
      printf(" %s",target[v]->x_form[w]);
      ++w;
    }
  }
}

printf("\n\nTARGETS = %d\n\n",targ_total);
*/


fclose(tgd);
}

/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */

void get_data()

{
int c, i;

  tx_date = (char *)malloc(STRLEN);

  while( *fname!='!' && !feof(tgf))
  {
    i = 0;

    /* read header data */

    if( ((c=fgetc(tgf))!=EOF) && (c=='#'))
    {
/*    printf( "%c",c); */

      fscanf( tgf,"%d",&tx_id);
/*    printf( " %d",tx_id); */

      while( isspace( c=fgetc(tgf)))
        ;

      if( !feof(tgf))
        ungetc(c,tgf);

/*    printf( " "); */

      while( ((c=fgetc(tgf))!=EOF) && !(c=='\n'))
       /* printf( "%c",c) */;

      fscanf( tgf,"%s",tx_date);

/*    printf( " %s\n\n",tx_date);*/

    }

    /* move to first tag */

    while( ((c=fgetc(tgf))!=EOF) && !(c=='#' || c=='$' || c=='\'' || c==';' || c=='!'))
      ;

    if( !feof(tgf))
      ungetc(c,tgf);


    while( ((c=fgetc(tgf))!=EOF) && !(c=='#'))
    {
      tx[i] = read_ttext();
      tx[i]->sub = 0;

      while( ((c=fgetc(tgf))!=EOF) && !(c=='#' || c==' ' || c=='\n'))
        ;

      if( !feof(tgf))
        ungetc(c,tgf);

      if( ((c=fgetc(tgf))!=EOF) && (c==' '))
      {
        while( ((c=fgetc(tgf))!=EOF) && !(c=='\n'))
        {
          tx[++i] = read_ttext();
          tx[i]->sub = 1;
        }
      }

      while( ((c=fgetc(tgf))!=EOF) && !(c=='#' || c=='$' || c=='\'' || c==';' || c=='!'))
        ;

      if( !feof(tgf))
        ungetc(c,tgf);

      ++i;
    }

    if( feof(tgf) || c=='#')
      ungetc(c,tgf);    

    text_total = i;

    compare_tags();

  }
}

/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */

struct tag_word *read_ttext()

{
struct tag_word *y;

  if( y = (struct tag_word *)malloc(sizeof(struct tag_word)))
  {
    y->tag = read_string(tgf);
    y->form = read_string(tgf);

    return(y);
  }

  return(0);
}

/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */

void compare_tags()

{
register int i, j, k, m, n;

  i = 0;
  k = con_total;

  while( i < targ_total)
  {
    j = 0;

    while( i<targ_total && j<text_total)
    {
      if( strcmp( tx[j]->tag,target[i]->x_tag)==0)
      {

        if( target[i]->x_count>0)
        {
          m = 1;
          n = 0;

          while( n < target[i]->x_count && ((m=strcmp( tx[j]->form,target[i]->x_form[n]))!=0))
            ++n;

          if( m==0)  /*forms match*/
          {
            p[k] = get_contxt(j);
            ++k;
          }
        }
        else
        {
          p[k] = get_contxt(j);
          ++k;
        }
      }
      ++j;
    }
    ++i;
  }

  con_total = k;
}

/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */

struct con_txt *get_contxt( i)

int i;
{
struct con_txt *z;
int a, b, finish, m, n, q, r, start;

  if( z = (struct con_txt *)malloc(sizeof(struct con_txt)) )
  {
    z->keytag = (char *)malloc(STRLEN);
    strcpy( z->keytag,tx[i]->tag);

    z->keyform = (char *)malloc(STRLEN);
    strcpy( z->keyform,tx[i]->form);

    z->in_file = (char *)malloc(STRLEN);
    strcpy( z->in_file,fname);

/*if( *fname!='!')
  printf("\n%s",z->in_file);
*/
    z->year = (char *)malloc(7);
    strcpy(z->year,tx_date);

    if( i>0)
      q = i-1;
    else
      q = 0;

    r = 0;

    while( q>0 && r<prewords)
    {
      if( tx[q]->sub==0)
        ++r;
      --q;
    }

    start = q+1;
    z->backstop = r;

    q = i+1;
    r = 0;

    while( q < text_total+1 && r < postwords)
    {
      if( tx[q] && tx[q]->sub==0)
        ++r;
      ++q;
    }

    finish = q+1;

    z->longstop = r;

    a = 0;

    for( m=start; m<i; ++m)
    {
      if( tx[m]->sub==0)
      {
        z->prewds[a] = (char *)malloc(STRLEN);
        strcpy(z->prewds[a],tx[m]->form);
        z->pretags[a] = (char *)malloc(STRLEN);
        strcpy(z->pretags[a],tx[m]->tag);

        ++a;
      }
    }

    b = 0;

    for( n=i+1; n<finish; ++n)
    {
      if( tx[n] && tx[n]->sub==0)
      {
        z->postwds[b] = (char *)malloc(STRLEN);
        strcpy(z->postwds[b],tx[n]->form);
        z->posttags[b] = (char *)malloc(STRLEN);
        strcpy(z->posttags[b],tx[n]->tag);

        ++b;
      }
    }

    z->idno = tx_id;

    return(z);
  }

  return(0);
}

/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */

char *read_string(inf)

FILE *inf;
{
char *ct, *t;
int c;

    t = (char *)malloc(STRLEN);

    if(t != 0)
    {
      ct = t;

      while( ((c = fgetc( inf)) != EOF) && !(c=='_' || c==' ' || c=='\n'))
      {
/*         if(c=='*' || c=='~' || c=='"'))
           continue;
*/
         if(ct-t < STRLEN-1)
           *ct++ = c;
      }

      if( c=='\n' || c==' ')
        ungetc(c,inf);

      *ct = 0;

      if(c==EOF && ct==t)
        return(0);
    }

    return(t);
}

/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */

void sort_files()

{
int a, b;

  by_tag = 2;      /* cause data to be sorted by filename */

  qs( 0, con_total-1);

  by_tag--;

  a = 0;

  while( a < con_total)
  {
    b = a+1;

    while( b < con_total && strcmp( p[a]->in_file,p[b]->in_file)==0)
      ++b;

    if( b-a > 1)
      qs( a,b-1); /* sort by tag under filename */

    a = b;
  }


  by_tag--;

  a = 0;

  while( a < con_total)
  {
    b = a+1;

    while( b < con_total && p[a]->in_file && p[b]->in_file && strcmp( p[a]->in_file,p[b]->in_file)==0 && strcmp( p[a]->keytag,p[b]->keytag)==0)
      ++b;

    if( b-a > 1)
      qs( a,b-1);  /* sort by form */

    a = b;
  }

}

/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */

/* Adapted from sort_data() in formx2prog.c */

void sort_data()

{
int a, b;

  by_tag = 1;

  qs( 0, con_total-1);

  by_tag--;

  a = 0;

  while( a < con_total)
  {
    b = a+1;

    while( b < con_total && strcmp( p[a]->keytag,p[b]->keytag)==0)
      ++b;

    if( b-a > 1)
      qs( a,b-1);  /* sort by form */

    a = b;
  }

  by_tag--;

  a = 0;

  while( a < con_total)
  {
    b = a+1;

    while( b < con_total && strcmp( p[a]->keytag,p[b]->keytag)==0 && strcmp( p[a]->keyform,p[b]->keyform)==0)
      ++b;

    if( b-a > 1)
      qs( a,b-1);  /* sort by idno */

    a = b;
  }
}

/*  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  */

/* Sort pointers: adaptation of Hoare's quicksort */

void qs( left,right)

int left, right;

{
register int i, j;
struct con_txt *swap, *mid;

  i = left;
  j = right;

  mid = p[(left+right)/2];         /* find middle entry */

  swap = NULL;

  do {

    if( by_tag>1)
    {
      while( (strcmp( p[i]->in_file,mid->in_file) < 0) && (i < right))
        i++;

      while( (strcmp( p[j]->in_file,mid->in_file) > 0) && (j > left))
        j--;
    }

    if( by_tag==1)
    {
      while( (strcmp( p[i]->keytag,mid->keytag) < 0) && (i < right))
        i++;

      while( (strcmp( p[j]->keytag,mid->keytag) > 0) && (j > left))
        j--;
    }

    if( by_tag==0)    
    {
      while( (strcmp( p[i]->keyform,mid->keyform) < 0) && (i < right))
        i++;

      while( (strcmp( p[j]->keyform,mid->keyform) > 0) && (j > left))
        j--;
    }

    if( by_tag<0)    
    {
      while( p[i]->idno < mid->idno && (i < right))
        i++;

      while( p[j]->idno  > mid->idno && (j > left))
        j--;
    }
      
    if( i <= j)          /* swap pointers */
    {
      swap = p[i];
      p[i] = p[j];
      p[j] = swap;

      i++;
      j--;
    }

  }while( i <= j);

  if( left<j)
    qs( left,j);

  if( i<right)
    qs( i,right);

} /* end of qs */

/*  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  */

void print_conco()

{
char *w, *x;
int len_dif[MAXCON], forms_in_line[CONTLINES], i, j, line_length;
int m, q, r, s, tags_in_line[CONTLINES];

  for( i=0; i<con_total; ++i)
  {
    printf("\n\n | ");

    if( tagcode==1)
    {
      s = 0;
      tags_in_line[s] = 0;
      line_length = 0;

      for( j=0; j<p[i]->backstop; ++j)
      {
        if( p[i] && p[i]->pretags[j])
        {
          if( !p[i] || !( p[i]->pretags[j]))
            break;

          printf(" %s ",p[i]->pretags[j]);
          len_dif[j] = strlen( p[i]->prewds[j]) - strlen( p[i]->pretags[j]);
          line_length = line_length + strlen( p[i]->pretags[j]);
          ++tags_in_line[s];

          if(len_dif[j]>=0)
          {
            for( m=0; m<len_dif[j]+1; ++m)
            {
              printf(" ");
              line_length++;
            }
          }
          else
          {
            printf(" ");
            line_length++;
          }

          if( line_length > MAXLINE)
          {
/*            printf( " | \n\n");*/
            ++s;
            tags_in_line[s] = 0;
            line_length = 0;
          }
        }
        else
          break;
      }
      printf( " | \n\n");
    }

    s = 0;
    forms_in_line[s] = 0;
    line_length = 0;

    for( j=0; j<p[i]->backstop; ++j)
    {
      if( p[i] && p[i]->prewds[j])
      {
        printf(" %s ",p[i]->prewds[j]);
        line_length = line_length + strlen(p[i]->prewds[j]);

        if( tagcode==1)
        {
          ++forms_in_line[s];

          if( len_dif[j] < 0)
          {
            len_dif[j] = len_dif[j] * (-1);

            for( m=0; m<len_dif[j]+1; ++m)
            {
              printf( " ");
              line_length++;
            }
          }
          else
          {
            printf( " ");
            line_length++;
          }

          if( forms_in_line[s] == tags_in_line[s])
          {
            printf( "\n\n");
            ++s;
            forms_in_line[s] = 0;
            line_length = 0;
          }
        }
        else
        {
          if( line_length > MAXLINE)
          {
/*            printf( " | \n\n");*/
            line_length = 0;
          }
          else
          {
            printf( " ");
            ++line_length;
          }
        }
      }
      else
        break;
    }

    printf(" | \n\n\t");

    x = p[i]->keyform;

    while( *x)
      printf("%c",*x++);

    printf(" ");

/*  r = 2*(strlen( p[i]->keyform)) - 1;*/

    r = (strlen( p[i]->keyform)) - 1;

    for( m=0; m<(40-r); ++m)
      printf( " ");

    printf("%s | \n\n\n",p[i]->keytag);

    if( tagcode==1)
    {
      s = 0;
      tags_in_line[s] = 0;
      line_length = 0;

      for( j=0; j<p[i]->longstop-1; ++j)
        if( p[i] && p[i]->posttags[j])
        {
          if( !p[i] || !( p[i]->posttags[j]))
            break;

          printf(" %s ",p[i]->posttags[j]);

          len_dif[j] = strlen( p[i]->postwds[j]) - strlen( p[i]->posttags[j]);
          line_length = line_length + strlen( p[i]->posttags[j]);
          ++tags_in_line[s];

          if(len_dif[j] >= 0)
          {
            for( m=0; m<len_dif[j]+1; ++m)
            {
              printf(" ");
              line_length++;
            }
           }
          else
          {
            printf(" ");
            ++line_length;
          }

          if( line_length > MAXLINE)
          {
/*            printf( " | \n\n");*/
            ++s;
            tags_in_line[s] = 0;
            line_length = 0;
          }
        }
        else
          break;

      printf( "| \n\n");
    }

    s = 0;
    forms_in_line[s] = 0;
    line_length = 0;

    for( j=0; j<p[i]->longstop-1; ++j)
    {
      if( !p[i] || !( p[i]->postwds[j]))
        break;

      printf(" %s ",p[i]->postwds[j]);
      line_length = line_length + strlen( p[i]->postwds[j]);

      if( tagcode==1)
      {
        ++forms_in_line[s];

        if( len_dif[j] < 0)
        {
          len_dif[j] = len_dif[j] * (-1);

          for( m=0; m<len_dif[j]+1; ++m)
          {
            printf( " ");
            ++line_length;
          }
        }
        else
        {
          printf( " ");
          ++line_length;
        }

        if( forms_in_line[s] == tags_in_line[s])
        {
/*          printf( " | \n\n");*/
          ++s;
          forms_in_line[s] = 0;
          line_length = 0;
        }
      }
      else
      {
        if( line_length > MAXLINE)
        {
/*          printf( " | \n\n");*/
          line_length = 0;
        }
        else
        {
          printf( " ");
          ++line_length;
        }
      }
    }

    printf(" | \n\n\n\t");
    
    if( isdigit( *p[i]->year))
    {
      printf(" 1");
      w = p[i]->year;

      q = 0;

      while( *w && q<3)
      {
        printf("%c",*w++);
        ++q;
      }

    }
    else
      printf(" (%s)",p[i]->year);

    printf( " | ");

    printf(" # %d %s ",p[i]->idno,p[i]->in_file);

    printf(" | \n\n");

    for( q=0; q<30; ++q)
      printf(" - ");
  }
}

/* ----------------------------------------------------------------- */

void do_fail( fname)

char *fname;

{
  printf( "\n\n\t\t\t***** FAILURE OPENING: %s *****\n\n",fname);
  exit( 0);
}

/*  (  (  (  (  (  (  E n D   O f   P r O g R a M  )  )  )  )  )  )  */
