#include "global.hh"
#include "sgraph.hh"
#include "grammar.hh"
#include "const.hh"
#include <cstdio>
#include <sstream>

extern MGraph mgraph;

//====================================================================================================

int SGraph::add_base_snode(int mnodeind)
{
  SNode& newnode =  makenewnode(); 

  newnode.mnode=mnodeind;

  for(vector<int>::iterator pm=mgraph[newnode.mnode].pred.begin(); pm!=mgraph[newnode.mnode].pred.end(); ++pm)
    for(vector<int>::iterator ps=mgraph[*pm].snodes.begin(); ps!=mgraph[*pm].snodes.end(); ++ps)
      if(nodes[*ps].in_LH)
      {
        newnode.LV.set(*ps);
        if(nodes[*ps].saturated()) newnode.LV |= nodes[*ps].LH;
      }

  mgraph[newnode.mnode].snodes.push_back(lastnodeind());

  newnode.in_LH=true;

  newnode.edge.push_back(lastnodeind());

  newnode.edge_contains_self = true ;

  return lastnodeind();
}

//====================================================================================================

void SGraph::update_left(int headind, int depind)
{
  SNode &head=nodes[headind], &dep=nodes[depind];

  if(dep.saturated())  head.LV |= dep.LV,  head.LD |= dep.LD;
}


void SGraph::update_right(int headind, int depind)
{
  SNode &head=nodes[headind], &dep=nodes[depind];

  dep.LH.set(headind);
  if(head.saturated())  dep.LH |= head.LH;
} 

//====================================================================================================

int SGraph::clone(int ancind, NodeProp newprop)
{
  SNode &newnode=makenewnode();
  SNode &ancnode = nodes[ancind];

  newnode.prop=newprop;
  newnode.mnode=ancnode.mnode;
  mgraph[newnode.mnode].snodes.push_back(lastnodeind());

  return lastnodeind();
}

//====================================================================================================

int SGraph::print_node(FILE* f, int n, unsigned int info)
{
  char buf[50000];
  sprint_node(buf,n,-1,info);
  fputs(buf,f);
}

//----------------------------------------------------------------------------------------------------

int SGraph::print_node_debug(FILE* f, const char* pref, int n, int anc)
{
  char buf[50000];
  sprint_node_debug(buf,pref,n,anc);
  fputs(buf,f);
}

//----------------------------------------------------------------------------------------------------

void SGraph::print_arc(FILE* f, const char* msg, int head, int dep, Role role, int dir) // 0 - left, 1 - right
{
  if(dir==0)
    fprintf(f,"%s  %s:%d <-- %d\n", msg, role.str(), dep, head);
  else
    fprintf(f,"%s  %s:%d --> %d\n", msg, role.str(), head, dep);
}

//====================================================================================================

int SGraph::sprint_node(char* buf, int nodeind, int anc, unsigned int info)
{
  char* buf0=buf;

  SNode &node=nodes[nodeind];

  buf+=sprintf(buf," dgp:%d",nodeind);
  if(anc>=0) buf+=sprintf(buf,"(%d)",anc);
  buf+=sprintf(buf, saturated(nodeind) ? ";s" : ";u");

  if (info&HEADS || info&DEPS)
    buf+=sprintf(buf,";");

  bool cont=false;

  if (info&HEADS)
    for(vector<Arc>::iterator h=node.heads.begin(); h!=node.heads.end(); ++h)
    {
      buf+=sprintf(buf,"(++%s:%d)",h->role.str(),h->dst);
    }

  if (info&DEPS)
    for(vector<Arc>::iterator d=node.deps.begin(); d!=node.deps.end(); ++d)
    {
      buf+=sprintf(buf,"(--%s:%d)",d->role.str(),d->dst);
    }
  
  if (info&SETS)
  {
    int ord=0;
    buf+=sprintf(buf,";{");
    for(vector<int>::iterator pm=mgraph[node.mnode].pred.begin(); pm!=mgraph[node.mnode].pred.end(); ++pm)
      for(vector<int>::iterator ps=mgraph[*pm].snodes.begin(); ps!=mgraph[*pm].snodes.end(); ++ps)
        buf+=sprintf(buf, ord++ ? ",%d" : "%d", *ps);
    buf+=sprintf(buf,"};{");
    ord=0;for(int j=0; j<size(); ++j) if(node.LV[j]) buf+=sprintf(buf, ord++ ? ",%d" : "%d", j);
    buf+=sprintf(buf,"};{");
    ord=0;for(int j=0; j<size(); ++j) if(node.LH[j]) buf+=sprintf(buf, ord++ ? ",%d" : "%d", j);
    buf+=sprintf(buf,"};{");
    ord=0;for(int j=0; j<size(); ++j) if(node.LD[j]) buf+=sprintf(buf, ord++ ? ",%d" : "%d", j);
    buf+=sprintf(buf,"}");
  }

  if (info&CONSTRAINTS)//  buf+=sprint_node_constraints(buf,n);
  {
    buf+=sprintf(buf,";");
    int cont=0;
    for(Role i=1; i<=Role::count(); ++i)
      if(node.prop.forbidden[i]) buf+=sprintf(buf,"%s!%s",(cont++)?",":"",i.str());
    for(Role i=1; i<=Role::count(); ++i)
      if(node.prop.required[i]) buf+=sprintf(buf,"%s-%s",(cont++)?",":"",i.str());
    for(Role i=1; i<=Role::count(); ++i)
      if(node.prop.attached[i]) buf+=sprintf(buf,"%s+%s",(cont++)?",":"",i.str());
    for(Flag i=1; i<=Flag::count(); ++i)
      if(node.prop.flags [i]) buf+=sprintf(buf,"%s<%s>",(cont++)?",":"",i.str());
    if(node.prop.init_attached)
      buf+=sprintf(buf,"<init>");
    if(node.prop.fin_attached)
      buf+=sprintf(buf,"<fin>");

    stringstream oss;
    for(list<Boubble*>::iterator b = node.prop.boubbles.begin(); b != node.prop.boubbles.end(); b++)
      oss << (cont++ ? "," : "") << **b;
    buf+=sprintf(buf,oss.str().c_str());
  }
  
//   buf+=sprintf(buf,"\n");
  
  return buf-buf0;
}


int SGraph::sprint_node_debug(char* buf, const char* pref, int n, int anc)
{
  char *buf0 = buf;
  buf+=sprintf(buf,"%-10s",pref);
  buf+=sprintf(buf,"%d.%s",n,form(n));
  buf+=sprintf(buf,";");
  buf+=sprintf(buf,"%s ",cat(n).str());
  while(buf-buf0<40) buf+=sprintf(buf," ");
  buf+=sprint_node(buf,n,anc,HEADS|DEPS|SETS|CONSTRAINTS);
  
  // buf+=sprintf(buf,"/");
  // for(vector<int>::iterator e = nodes[n].edge.begin(); e != nodes[n].edge.end(); e++ )
  //   buf += sprintf(buf,"%d ", *e);

  buf+=sprintf(buf,"\n");
  return buf-buf0;
}

