/* display.cc */

#include "component.h"
#include "element.h"
#include "function.h"
#include "parser.h"
#include "id_lookup.h"
#include "cor_pipe.h"

#define EXTRA_DISP_JUNK

#ifdef DC_TRACING_ON
set<tag> monitored;
#endif

static ostream *s;
static int tabs = 0;

/* defined as extern in display.h */
int disp_verbose = 1;
bool disp_substitute = false;
bool disp_as_parsed = true;

void tab_in( void ) {
  for( int t = 0 ; t < tabs ; t++ ) {
    *s << "  ";
  }
}

void output_tabbed( dc_label *l ) {
  tab_in();
  if( l == nil ) {
    *s << "<nil>\n";
    return;
  }

  switch( l->sub_type() ) {
  case Component_t : case Modification_t : case GA_t :
    *s << *l << "\n";
    break;
  case Element_t :
    *s << *l << "\n";
    break;
  case Clock_t :
    *s << *l << "\n";
    break;
  case Boolean_t :
    *s << l->full_type() << " = " << *( ( dc_boolean * )l ) << "\n";
    break;
  case Distrib_t :
    *s << l->full_type() << " = " << *( ( dc_distrib * )l ) << "\n";
    break;    
  case Real_t :
    *s << l->full_type() << " = " << *( ( dc_real * )l ) << "\n";
    break;
  case Int_t :
    *s << l->full_type() << " = " << *( ( dc_int * )l ) << "\n";
    break;
  case Pointer_t :
    *s << l->full_type() << " = " << *( ( dc_pointer * )l ) << "\n";
    break;
  case Rect_Matrix_t :
    *s << l->full_type() << " = \n" << *( ( dc_rect_matrix * )l ) << "\n";
    break;
  case Set_t :
    *s << l->full_type() << " = " << *( ( dc_set * )l ) << "\n";
    break;
  case Shape_t :
    *s << l->full_type() << " = " << *( ( dc_shape * )l ) << "\n";
    break;
  case String_t :
    *s << l->full_type() << " = " << *( ( dc_string * )l ) << "\n";
    break;
  case Symbol_t :
    *s << l->full_type() << " = " << *( ( dc_symbol * )l ) << "\n";
    break;
  case Triple_t :
    *s << l->full_type() << " = \n" << *( ( dc_triple * )l ) << "\n";
    break;
  case Vector_t :
    *s << l->full_type() << " = \n" << *( ( dc_vector * )l ) << "\n";
    break;
  default :
    *s << l->full_type() << "\n";
  }
}

ostream &dc_element::display( ostream &stream = cout ) {
  s = &stream;

  if( disp_verbose >= 0 ) {
    
    if( transparent ) {
      stream << parse_lbl[Transparent_Tag] << " ";
    }
    
    /* display return type name */
    stream << dc_type_string[ rtype ] << " ";
    
    stream << type_string() << " " << label();
    
    /* display arg list */
    if( nargs && disp_verbose >= 1 ) {
      stream << " ( ";
      list_item li = args.first();
      if( li ) {
	dc_arg *arg = args.inf( li );
	stream << dc_type_string[ arg->get_rtype() ] << " ";
	arg->display_w_default( stream );
	while( ( li = args.succ( li ) ) != nil ) {
	  stream << ", ";
	  arg = args.inf( li );
	  stream << dc_type_string[ arg->get_rtype() ] << " ";
	  arg->display_w_default( stream );
	}
      }
      stream << " )";
    }
    
    stream << " = ";
    
    if( disp_verbose >= 1 ) {
      /* display evaluation function */
      if( eval ) {
	stream << *eval;
      }
      
      dc_data *v = get();
      dc_data *old_v = get_previous();
      if( v != nil ) {
	if( eval != nil ) stream << " :: ";
	stream << *v;
	if( old_v ) stream << " : " << *old_v;
      } else if( eval == nil ) {
	stream << "<nil>";
      }
    } else {
      dc_data *v = get();
      dc_data *old_v = get_previous();
      if( v != nil ) {
	stream << *v;
	if( old_v ) stream << " : " << *old_v;
      } else {
	stream << "<nil>";
      }
    }
    
#ifdef EXTRA_DISP_JUNK
    stream << " - " << dc_status_string[status];
    
    if( is_simple() ) stream << " simple";
#endif
    
    if( clock_hash_lbl.length() ) {
      cerr << ", clock " << clock_hash_lbl;
      dc_clock *clk;
      forall( clk, secondary_clocks ) {
	stream << ", " << clk->label();
      }
    }
  } else {
    dc_data *v = get();
    if( v != nil ) {
      switch( v->type() ) {
      case Real_t :
	stream << ( ( dc_real * )v )->get() << "\n";
	break;
      case Int_t :
	stream << ( ( dc_int * )v )->get() << "\n";
	break;
      case Boolean_t :
	stream << ( ( dc_boolean * )v )->get() << "\n";
	break;
      default :;
      }
    } else {
      stream << "<nil>";
    }
  }

  return stream;
}

// ostream &dc_pipe::display( ostream &stream = cout ) {
//   s = &stream;
//   dc_data *v = get();
  
//   if( transparent ) {
//     stream << parse_lbl[Transparent_Tag] << " ";
//   }

//   /* display return type name */
//   stream << dc_type_string[ rtype ] << " ";

//   stream << type_string() << " " << label();

//   /* display arg list */
//   if( nargs ) {
//     stream << " ( ";
//     list_item li = args.first();
//     if( li ) {
//       dc_arg *arg = args.inf( li );
//       stream << dc_type_string[ arg->get_rtype() ] << " ";
//       arg->display_w_default( stream );
//       while( ( li = args.succ( li ) ) != nil ) {
// 	stream << ", ";
// 	arg = args.inf( li );
// 	stream << dc_type_string[ arg->get_rtype() ] << " ";
// 	arg->display_w_default( stream );
//       }
//     }
//     stream << " )";
//   }

//   stream << " = ";

//   /* display evaluation function */
//   if( eval ) {
//     stream << *eval;
//   }

//   /* display current value */
//   if( v != nil ) {
//     if( eval ) stream << " : ";
//     stream << *v;
//   }

//   //  stream << "\n" << Buffer_Info << "\n";
//   stream << " - " << dc_status_string[status];

//   return stream;
// }

ostream &dc_component::display( ostream &stream = cout ) {
  s = &stream;
  stream << full_type()
#ifdef EXTRA_DISP_JUNK
	 << " - " <<  dc_status_string[ status ];
  if( clock_hash_lbl.length() ) {
    cerr << ", clock " << clock_hash_lbl;
  }
#endif
  if( template_path.length() ) 
    stream << " : " << template_path;
  stream << " {\n";
  
  tabs++;
  tab_in(); stream << uts.list_types() << "\n";
  for_children( output_tabbed );
  tabs--;
  tab_in(); stream << "}";
  return stream;
}

void dc_node::list_children( ostream &stream = cout ) {
  s = &stream;
  if( child_list.empty() ) {
    tab_in();
    stream << label() << " has no children\n";
    return;
  }
  
  tab_in();
  stream << "CHILD LIST OF " << full_type() << " :\n";
  tabs++;
  for_children( output_tabbed );
  tabs--;
}

/* function display functions */
ostream &dc_const::display( ostream &stream = cout ) const {
  if( D ) {
    return stream << *D;
  } 
  return stream << "<nil>";
}

ostream &dc_elvalue::display( ostream &stream = cout ) const {
  if( disp_substitute ) {
    dc_data *d = E->get();
    if( d ) {
      return stream << *d;
    } else {
      return stream << "<nil>";
    }
  } else {
    if( old ) stream << parse_lbl[Old_Tag] << " ";
    if( E ) {
      if( disp_as_parsed && hash_path.length() ) {
	return stream << hash_path;
      } else {
	return stream << E->label();
      }
    }
    if( hash_path.length() ) {
      return stream << "<nil \"" << hash_path << "\" from " <<
	( hash_origin ? hash_origin->full_type() : string( "root" ) ) << " >";
    } else return stream << "<nil>";
  }
}

ostream &dc_op::display( ostream &stream = cout ) const {
  if( fn_list[info_index].type == FUNC ) {
    /* ouput Func name */
    stream << parse_lbl[FN_START + 1 + info_index] << "( ";
    /* output args */
    if( nargs ) {
      list_item li = args.first();
      stream << *( args.inf( li ) );
      while( ( li = args.succ( li ) ) != nil ) {
	stream << ", " << *( args.inf( li ) );
      }
    }
  } else {
    stream << "( ";
    if( nargs ) {
      if( nargs == 1 ) {
	stream << parse_lbl[FN_START + 1 + info_index] 
	       << *( args.head() );
      } else {
	list_item li = args.first();
	stream << *( args.inf( li ) );
	while( ( li = args.succ( li ) ) != nil ) {
	  stream << " " << parse_lbl[FN_START + 1 + info_index] << " " 
		 << *( args.inf( li ) );
	}
      }
    }
  }     
  return stream << " )";;
}

ostream &dc_set_op::display( ostream &stream = cout ) const {
  stream << parse_lbl[FN_START + 1 + info_index];
  if( set ) return stream << "( " << *set << " )";
  return stream << "( <nil> )";
}

ostream &dc_pset_op::display( ostream &stream = cout ) const {
  stream << parse_lbl[FN_START + 1 + info_index];
  if( disp_verbose >= 2 ) {
    if( set ) return stream << "( " << *set << " )";
    return stream << "( <nil> )";
  } else if( disp_as_parsed ) {
    return stream << "( " << label << " )";
  } else {
    if( id ) {
      return stream << "( " << id->label() << " )";
    } else {
      return stream << "( <nil> )";
    }
  }
}

ostream &dc_fcast::display( ostream &stream = cout ) const {
  return stream << "( " << dc_type_string[T] << " )( " << *f << " )";
}

ostream &dc_ucast::display( ostream &stream = cout ) const {
  return stream << "( " << coeff << uv << " )( " << *f << " )";
}

ostream &dc_arg::display( ostream &stream = cout ) const { 
  return stream << name; 
}

ostream &dc_arg::display_w_default( ostream &stream = cout ) const { 
  stream << name;
  if( default_val ) {
    stream << " = " << *default_val;
  }
  return stream;
}

ostream &dc_func_call::display( ostream &stream = cout ) const {
  if( disp_substitute ) {
    if( E ) { 
      dc_data *d = E->call( args );
      if( d ) {
	return stream << *d;
      }
    }
    return stream << "<nil>";
  } else {
    if( E ) {
      if( disp_as_parsed ) {
	/* function name */
	stream << hash_path << "( ";
      } else {
	stream << E->label() << "( ";
      }
    } else {
      stream << "<nil>( ";
    }
    
    /* arg list */
    if( nargs ) {
      list_item li = args.first();
      dc_func *f = args.inf( li );
      if( f ) stream << *f;
      while( ( li = args.succ( li ) ) != nil ) {
	stream << ", ";
	dc_func *f = args.inf( li );
	if( f ) {
	  stream << *( args.inf( li ) );
	}
      }

      /*    if( arg_data_list.length() ) {
      list_item li = arg_data_list.first();
      if( li ) {
	arg_data *ad = arg_data_list.inf( li );
	if( ad ) {
	  if( ad->label.length() ) {
	    stream << ad->label << " = ";
	  }
	  stream << *( ad->f );
	}
      }
      
      while( ( li = arg_data_list.succ( li ) ) != nil ) {
	stream << ", ";
	arg_data *ad = arg_data_list.inf( li );
	if( ad ) {
	  if( ad->label.length() ) {
	    stream << ad->label << " = ";
	  }
	  stream << *( ad->f );
	}
      }*/
    }
    
    return stream << " )";
  }
}

ostream &dc_set::display_c( ostream &stream = cout ) const {
  if( disp_verbose >= 2 ) {
    stream << "( ";
    tag T;
    tabs++;
    ostream *old_s = s;
    s = &stream;
    forall( T, members ) {
      dc_label *id = lookup( T );
      output_tabbed( id );
    }
    tabs--;
    s = old_s;
    tab_in();
    return stream << " )";
  }

  dc_finite_set *fset;
  bool first = true;
  forall( fset, sets ) {
    if( first ) first = false; else stream << " & ";
    stream << *fset;
  }
  if( exceptions.size() ) {
    stream << " except ";
    first = true;
    forall( fset, exceptions ) {
      if( first ) first = false; else stream << " & ";
      stream << *fset;
    }
  }
  return stream;
}

ostream &dc_set_atom::display( ostream &stream = cout ) const { 
  stream << parse_lbl[None_Tag];
  return stream;
}

ostream &dc_all_set::display( ostream &stream = cout) const {
  stream << parse_lbl[All_Tag];
  return stream;
}

ostream &dc_finite_set::display( ostream &stream = cout ) const {
  stream << parse_lbl[Set_Tag] << "( ";
  tag T;
  tabs++;
  ostream *old_s = s;
  s = &stream;
  forall( T, S ) {
    dc_label *l = lookup( T );
    if( disp_verbose >= 2 ) {
      output_tabbed( l );
    } else {
      tab_in();
      stream << l->label() << "\n";
    }
  }
  tabs--;
  s = old_s;
  tab_in(); stream << " )";
  return stream;
}

ostream &dc_desc_set::display( ostream &stream = cout ) const {
  if( disp_verbose >= 2 ) {
    return dc_finite_set::display( stream );
  }

  int n = 0; /* used to count how many non-default criterion */
  if( key.length() != 0 ) {
    stream << parse_lbl[Key_Tag] << " " << key;
    n = 1;
  }  
  if( u_type != Undefined_Type ) {
    if( n++ ) stream << " " << parse_lbl[Of_Tag] << " ";
    stream << parse_lbl[Type_Tag] << " " << u_type_string( u_type );
  }
  if( !n ) stream << parse_lbl[Descendent_Tag];
  stream << " " << parse_lbl[Of_Tag] << " " 
	 << ( desc_origin ? desc_origin->label() : ID_SEP_STRING );
  return stream;
}

ostream &dc_tquery::display( ostream &stream = cout ) const {
  if( T ) return stream << "time";
  else return stream << "delta_time";
}

ostream &dc_iter_loop::display( ostream &stream = cout ) const {
  stream << "for( " << dc_type_string[arg.get_rtype_c()] << " " << arg << ", ";
  if( disp_as_parsed && label.length() != 0 ) {
    stream << label;
  } else if( set ) {
    stream << *set;
  } else stream << "<nil>";
  if( func ) {
    return stream << " ){ " << *func << " }";
  } 
  return stream << " ){ <nil> }";
}

ostream &dc_link::display( ostream &stream = cout ) const {
  stream << "link ";
  if( disp_as_parsed ) {
    if( hash_source.length() ) {
      stream << hash_source;
    } else {
      dc_component *src = get_source();
      if( src ) stream << src->label(); 
      else stream << "<nil>";      
    }
    if( hash_target.length() ) {
      stream << ( directed ? " -> " : " , " ) << hash_target;
    } else {
      dc_component *trgt = get_target();
      if( trgt ) stream << ( directed ? " -> " : " , " ) << trgt->label();
    }
  } else {
    dc_component *src = get_source();
    if( src ) stream << src->label(); 
    else stream << "<nil>";
    dc_component *trgt = get_target();
    if( trgt ) {
      if( directed ) stream << " -> ";
      else stream << ", ";  
      stream << trgt->label();
    }
  }
  
  dc_link_type lt = type();
  if( lt != Base_lt ) {
    stream << " : " << dc_lt_string[type()];
  }
  return stream;
}

string tag_descrip( tag T ) {
  dc_label *l = lookup( T );
  if( l ) {
    return l->full_type();
  } else {
    return string( "<nil>" );
  }
}

#ifdef DC_TRACING_ON
bool check_monitored( const dc_label *l, cstring message ) {
  if( !( l && monitored.member( l->get_tag() ) ) ) return false;
  if( disp_verbose >= 0 ) {
    cerr << "MONITORED \"" << l->label() << "\" : " << message << "\t";
  } else {
    cerr << string( "%5ld\t", l->get_tag() );
  }
  return true;
}
#endif
