
#include <stdio.h>

#include "grammar.hh"

bool (*constraint[MAXCONSTRS])(int head, int dep);


int chk_type(const char* s, int lineno) // SIDE EFECTS!
{
  if(Role::index(s)>0) return 1;

  fprintf(stderr,"%8d: Invalid type '%s'. Line ignored.\n",lineno,s);
  return 0;
}

int chk_cat(const char* s, int lineno)
{
  if(Cat::index(s)>0) return 1;

  fprintf(stderr,"%8d: Invalid category '%s'. Line ignored.\n",lineno,s);
  return 0;
}

void Grammar::add_category(const char* s)
{
  Cat::add(s);
  if(Cat::count()>cats_sz)
  {
    cats_sz += 16;
    connect.resize(cats_sz);
    for(int i=0; i<cats_sz; ++i)
      connect[i].resize(cats_sz);
    obl.resize(cats_sz);
  }
}

void Grammar::add_type(const char* s)
{  
  Role::add(s);
  if(Role::count()>types_sz)
  {
    types_sz += 16;
    lt.resize(types_sz);
    gt.resize(types_sz);
  }
}

void Grammar::add_flag(const char* s)
{  
  Flag::add(s);
  if(Flag::count()>flags_sz)
  {
    flags_sz += 16;
    pass.resize(flags_sz);
  }
}


void Grammar::set_lt(Role s, Role t)
{
  lt[s].set(t);
  gt[t].set(s);
  if(s==0||(int)t==0)
    return;
  else
  {
    for(int i=0; i<Role::count(); ++i)
      if(lt[i][s])
	set_lt(i,t);
    for(int i=0; i<Role::count(); ++i)
      if(lt[t][i])
	set_lt(s,i);
  }
}  


void Grammar::compute_gt()
{
  for(Role s=0; s<Role::count(); ++s)
    for(Role t=0; t<Role::count(); ++t)
      if(lt[s][t])
	gt[t].set(s);
}


bool Grammar::read(FILE* f)
{
  int lineno=0;
  char line[MAXLINE]; // line has the structure: key [arg1 [arg2 [arg3]]]
  char key[MAXLINE];
  char arg1[MAXLINE];
  char arg2[MAXLINE];
  char arg3[MAXLINE];

  while(fgets(line,MAXLINE,f))
  {
    lineno++;
    int fields=sscanf(line,"%s %s %s %s",key,arg1,arg2,arg3);

    if(fields<1 || key[0]=='#') continue; // skip empty lines and comments

    if     (strcmp(key,"CAT")==0 && fields>=2)
    {
      add_category(arg1);
    }
    else if(strcmp(key,"ROLE")==0 && fields>=2)
    {
      add_type(arg1);
    }
    else if(strcmp(key,"SGL")==0 && fields>=2)
    {  
      if(chk_type(arg1,lineno))
        set_sgl(arg1);
    }
    else if(strcmp(key,"LEFT")==0 && fields>=2)
    { 
      if(chk_type(arg1,lineno))
        set_left(arg1);
    }
    else if(strcmp(key,"RIGHT")==0 && fields>=2)
    {
      if(chk_type(arg1,lineno))
        set_right(arg1);
    }
    else if(strcmp(key,"REQ")==0 && fields>=3)
    {
      if(chk_cat(arg1,lineno) + chk_type(arg2,lineno) == 2)
        set_obl(arg1,arg2);
    }
    else if(strcmp(key,"LINK")==0 && fields>=4)
    { 
      if(chk_cat(arg1,lineno) + chk_cat(arg2,lineno) + chk_type(arg3,lineno) == 3)    
        set_connect(arg1,arg2,arg3);
    }
    // FLAG DECLARATION
    else if(strcmp(key,"FLAG")==0 && fields>=2)
    { 
      add_flag(arg1);
    }

    else fprintf(stderr,"Invalid line %d. Ignored.\n", lineno);
  }

//   compute_gt();

  return true;
  
}

void Grammar::write(FILE* f)
{
  for(Cat i=1; i<Cat::count(); ++i)
    fprintf(f,"CAT\t%s\n",i.str());

  for(Role i=1; i<Role::count(); ++i)
    fprintf(f,"ROLE\t%s\n",i.str());

  for(Role i=1; i<Role::count(); ++i)
    if(sgl.test(i)) fprintf(f,"SGL\t%s\n",i.str());
  
  for(Role i=1; i<Role::count(); ++i)
    if(left.test(i)) fprintf(f,"LEFT\t%s\n",i.str());

  for(Role i=1; i<Role::count(); ++i)
    if(right.test(i)) fprintf(f,"RIGHT\t%s\n",i.str());

  for(Cat c=1; c<Cat::count(); ++c)
    for(Role r=1; r<Role::count(); ++r)
      if(obl[c].test(r)) fprintf(f,"REQ\t%s\t%s\n",c.str(),r.str());
  
  for(Cat c=1; c<Cat::count(); ++c)
    for(Cat d=1; d<Cat::count(); ++d)
      for(Role t=1; t<Role::count(); ++t)
	if(connect[c][d].count(t))
          fprintf(f,"LINK\t%s\t%s\t%s\n",c.str(),d.str(),t.str());

  for(Flag i=1; i<Flag::count(); ++i)
    fprintf(f,"FLAG\t%s\n",i.str());
}

