/* test_parse.cc */

const char RC_FILE[] = ".test_parse_rc";

#include "parser.h"
#include "id_lookup.h"
#include "user_types.h"
#include "root.h"
#include <fstream.h>
#include <string.h>
#include <ctype.h>
#include "display.h"
#include "pattern_match.h"
#include <sys/ddi.h>
#include "cor_syn_iface.h"
#include "rc_file.h"
#include "ga_optimizer.h"

set<tag> watched;

int sstring( const string &s ) {
  cerr << "\"" << s << "\"\n";
  return s.length();
}

void demo_lookup( void );

bool check_switch( string switch_str, int argc, char *argv[] ) {
  for( int i = 0 ; i < argc ; i++ ) {
    if( switch_str == string( argv[i] ) ) return true;
  }
  return false;
}

int main( int argc, char *argv[] ) {
  if( check_switch( "?", argc, argv ) ) {
    cerr << "Usage : " << argv[0] 
	 << " [<filename>] (-s)|([-flush] [-list] [-gfx])\n";
    return 0;
  }

  if( load_rc( RC_FILE ) ) {
    cerr << "Error loading rc file \"" << RC_FILE << "\"\n";
    return 1;
  }

  list<string> const *vals = nil;
  if( ( vals = rc_get( "trace" ) ) != nil ) {
    string s;
    int trace_lvl;
    if( sscanf( s, "%d", &trace_lvl ) ) {
      set_trace_level( ( trace_level )trace_lvl );
      cerr << "Trace_level is " << trace_lvl << "\n";
    } else {
      cerr << "\"" << RC_FILE << "\" : could not set trace level to \"" << s 
	   << "\"\n";
    }
  } else {
    set_trace_level( TRACE_FEW );
  }
  init_parse();
  
  string filename;
  if( argc >= 2 && argv[1][0] != '-' ) {
    filename = string( argv[1] );
  } else if( ( vals = rc_get( "infile" ) ) != nil ) {
    if( vals->length() ) {
      filename = vals->head();
    } else {
      cerr << "Usage : " << argv[0] 
	   << " <filename> (-s)|([-flush] [-list] [-gfx])\n";
      return 1;
    }
  }

  if( check_switch( string( "-s" ), argc, argv ) ) {
    token_queue tq( filename );
    tq.flush_out();
    return 0;
  }

  if( check_switch( string( "-flush" ), argc, argv ) ) {
    flush_on_death = true;
  } else if( ( vals = rc_get( "flush" ) ) != nil ) {
    if( vals->length() ) {
      if( vals->head() == "yes" ) flush_on_death = true;
    } else 
      flush_on_death = true;
  }
  
  if( check_switch( string( "-gfx" ), argc, argv ) ) {
    activate_gfx();
  } else if( ( vals = rc_get( "gfx" ) ) != nil ) {
    if( vals->length() ) {
      if( vals->head() == "yes" ) activate_gfx();
    } else 
      activate_gfx();
  }

  // get monitored
  if( ( vals = rc_get( "monitored" ) ) != nil ) {
    string s;
    forall( s, *vals ) {
      tag T;
      if( sscanf( s, "%lu", &T ) ) {
	monitored.insert( T );
      } else {
	cerr << "\"" << RC_FILE << "\" : could not add \"" << s 
	     << "\" to monitored list\n";
      }
    }
  }

  // get watched
  if( ( vals = rc_get( "watched" ) ) != nil ) {
    string s;
    forall( s, *vals ) {
      tag T;
      if( sscanf( s, "%lu", &T ) ) {
	watched.insert( T );
      } else {
	cerr << "\"" << RC_FILE << "\" : could not add \"" << s 
	     << "\" to watched list\n";
      }
    }
  }
  
  int nparsed = parse( filename );
  cout << nparsed << " ITEMS PARSED\n";

  int n = rehash();
  if( n ) {
    cout << "REHASH -- " << n << " rehashing errors\n";
  } else {
    cout << "REHASH -- successful\n";
  }
  list_u_types();

  cout << "\nLINKS\n";
  display_links();

  cerr << "\n\n";
  if( check_switch( string( "-list" ), argc, argv ) ) {
    list_tags();
  } else if( ( vals = rc_get( "list" ) ) != nil ) {
    if( vals->length() ) {
      if( vals->head() == "yes" ) list_tags();
    } else 
      list_tags();
  }

  demo_lookup();

  return 0;
}

string get_lowercase_string( void ) {
  string s;
  cin >> s;
  int len = s.length();
  if( len > 1 && s[0] == '\"' && s[len-1] == '\"' ) {
    s = s( 1, len-2 );
  } else {
    for( int i = 0 ; i < len ; i++ ) {
      s[i] = tolower( s[i] );
    }
  }
  return s;
}

const string command_string = string( "Enter [\"old\"] <label> to lookup or 'q' quits, \"adv_t\" advances time, \"step\" <real>, \"flag\", \"typeof\", \"all_constr\", \"unit\", \"cline\", \"verbose|substitute|as_parsed\" 'y'|'n', \"print\", \"freeze <label> 'y'|'n'\", \"dormant\" <label> 'y'|'n', \"monitor\" <label>, \"unmonitor\" '*'|<label>, \"locate\" <label>, \"pwatch\", \"bad_constr\", \"watch\" <label>, \"unwatch\" <label>, \"reset\", \"run\" <ga>, \"simulate\", \"close\" <ga> )\n" );

void demo_lookup( void ) {
  ga *active_ga = nil;

  string lu_string;
  dc_label *lu;
  dc_label *loc = nil;
    
  cout << command_string << "\n";
  do {
    cout << "\n> ";
    lu_string = get_lowercase_string();

    if( lu_string == 'q' || lu_string == "quit" || lu_string == "exit" ) 
      break;
    if( lu_string == "adv_t" ) {
      lu_string = get_lowercase_string();
      double nsteps;
      if( sscanf( lu_string, "%lf", &nsteps ) ) {
	advance_time( nsteps );
      } else {
	dc_label *constr = lookup( lu_string );
	if( constr && constr->type() == Element_t && 
	    ( ( dc_element * )constr )->get_rtype() == Boolean_t ) {
	  dc_boolean *b;
	  do {
	    advance_time( 1 );
	    b = ( dc_boolean * )( ( ( dc_element * )constr )->get() );
	  } while( b && b->get() );
	} else {
	  cerr << "ERROR -- \"" << lu_string << "\" not found\n";
	}
      }
    } else if( lu_string == "adv_c" ) {
      lu_string = get_lowercase_string();
      double nsteps;
      if( sscanf( lu_string, "%lf", &nsteps ) ) {
	advance_coriolis_time( nsteps );
      } else {
	dc_label *constr = lookup( lu_string );
	if( constr && constr->type() == Element_t && 
	    ( ( dc_element * )constr )->get_rtype() == Boolean_t ) {
	  dc_boolean *b;
	  do {
	    advance_coriolis_time( 1 );
	    b = ( dc_boolean * )( ( ( dc_element * )constr )->get() );
	  } while( b && b->get() );
	} else {
	  cerr << "ERROR -- \"" << lu_string << "\" not found\n";
	}
      }
    } else if( lu_string == "step" ) {
      lu_string = get_lowercase_string();
      double time_step;
      if( sscanf( lu_string, "%lf", &time_step ) ) {
	root.iter_counter->set_interval( time_step );
	root.iter_counter->init_interval( time_step );
	coriolis_clock->set_interval( time_step );
	coriolis_clock->init_interval( time_step );
	cout << "time step set to " << time_step << "\n";
      } else {
	cerr << "illegal time step " << time_step << "\n";
      }
    } else if( lu_string == "typeof" ) {
      lu_string = get_lowercase_string();
      lu = search( lu_string, loc );
      if( !lu ) {
	if( lu_string == ID_SEPARATOR ) {
	  loc = nil;
	} else {
	  cout << lu_string << " not found\n";
	}
      } else if( lu->type() == Element_t ) {
	/*xtype xt;
	( ( dc_element * )lu )->get_xtype( xt );
	cout << xt << "\n";*/
	dc_type t = ( ( dc_element * )lu )->get_rtype();
	cout << lu->label() << " : " << dc_type_string[t] << "\n";
      } else if( lu->sub_type() == Component_t ) {
	cout << lu->label() << " : " 
	     << ( ( dc_component * )lu )->list_u_types() << "\n";
      }
    } else if( lu_string == "flag" ) {
      int n = flag_constraints();
      if( n >= 0 )
	cerr << n << " constraints flagged\n";
      else
	cerr << "Error evaluating constraints\n";
    } else if( lu_string == "all_constr" ) {
      list_constraints( cout );
    } else if( lu_string == "unit" ) {
      lu_string = get_lowercase_string();
      double coeff;
      unit *U = ub.lookup( lu_string, coeff );
      if( U ) {
	cout << coeff << " " << *U << "\n";
      } else {
	cout << "unit \"" << lu_string << "\" not found\n";
      }
    } else if( lu_string == "cline" ) {
      parse( cin );
    } else if( lu_string == "verbose" ) {
      lu_string = get_lowercase_string();
      cerr << "was " << disp_verbose << "\n";
      if( lu_string == 'y' ) {
	disp_substitute = true;
      } else if ( lu_string == 'n' ) {
	disp_substitute = false;
      } else {
	cerr << "error.  expected 'y' or 'n'.\n";
      }
      cerr << "is " << ( disp_substitute ? 'y' : 'n' ) << "\n";
    } else if( lu_string == "substitute" ) {
      lu_string = get_lowercase_string();
      cerr << "was " << ( disp_substitute ? 'y' : 'n' ) << "\n";
      if( lu_string == 'y' ) {
	disp_substitute = true;
      } else if ( lu_string == 'n' ) {
	disp_substitute = false;
      } else {
	cerr << "error.  expected 'y' or 'n'.\n";
      }
      cerr << "is " << ( disp_substitute ? 'y' : 'n' ) << "\n";
    } else if( lu_string == "as_parsed" ) {
      lu_string = get_lowercase_string();
      cerr << "was " << ( disp_as_parsed ? 'y' : 'n' ) << "\n";
      if( lu_string == 'y' ) {
	disp_as_parsed = true;
      } else if ( lu_string == 'n' ) {
	disp_as_parsed = false;
      } else {
	cerr << "error.  expected 'y' or 'n'.\n";
      }
      cerr << "is " << ( disp_as_parsed ? 'y' : 'n' ) << "\n";
    } else if( lu_string == "print" ) {
      lu_string = get_lowercase_string();
      dic_item l_it;
      forall_items( l_it, root.tag_list ) {
	dc_label *l = root.tag_list.inf( l_it );
	if( pattern_match( l->local_label(), lu_string ) ) {
	  if( l->is_data() ) {
	    cout << l->full_type() << " = ";
	  }
	  cout << *l << "\n";
	}
      }
      cout << "\n";
    } else if( lu_string == "rehash" ) {
      int n;
      if( ( n = rehash() ) != 0 ) {
	cerr << "\nREHASH -- " << n << " rehashing errors\n";
      } else {
	cout << "\nREHASH -- successful\n";
      }
    } else if( lu_string == "freeze" ) {
      lu_string = get_lowercase_string();
      lu = search( lu_string, loc, true );
      if( !lu ) {
	cerr << lu_string << " not found\n";
      } else {
	bool set = false;
	set = get_lowercase_string() == "y";

	switch( lu->sub_type() ) {
	case Component_t : 
	  ( ( dc_component * )lu )->set_frozen( set );
	  cout << *lu << "\n";
	  break;
	case Element_t :
	  ( ( dc_element * )lu )->set_frozen( set );
	  cout << *lu << "\n";
	  break;
	default : cerr << lu_string << " cannot be frozen/unfrozen\n";;
	}
      }
    } else if( lu_string == "dormant" ) {
      lu_string = get_lowercase_string();
      lu = search( lu_string, loc, true );
      if( !lu ) {
	cout << lu_string << " not found\n";
      } else {
	bool set = false;
	set = get_lowercase_string() == "y";

	switch( lu->sub_type() ) {
	case Component_t : 
	  ( ( dc_component * )lu )->set_dormant( set );
	  cout << *lu << "\n";
	  break;
	case Element_t :
	  ( ( dc_element * )lu )->set_dormant( set );
	  cout << *lu << "\n";
	  break;
	default : cerr << lu_string << " cannot be made dormant/non-dormant\n";
	}
      }
    } else if( lu_string == ID_SEP_STRING ) {
      loc = nil;
      cout << "root\n";
    } else if( lu_string == "monitor" ) {
      lu_string = get_lowercase_string();
      lu = search( lu_string, loc, true );
      if( lu == nil ) {
	cerr << lu_string << " not found\n";
      } else {
	monitored.insert( lu->get_tag() );
	cout << lu->full_type() << " monitored\n";
      }
    } else if( lu_string == "unmonitor" ) {
      lu_string = get_lowercase_string();
      if( lu_string == "*" ) {
	monitored.clear();
	cout << "monitored list cleared\n";
      } else {
	lu = search( lu_string, loc, true );
	if( lu == nil ) {
	  cerr << lu_string << " not found\n";
	} else {
	  monitored.del( lu->get_tag() );
	  cout << lu->full_type() << " no longer monitored\n";
	}
      }
    } else if( lu_string == "locate" ) {
      lu_string = get_lowercase_string();
      lu = search( lu_string, loc, true );
      if( !lu ) {
	cerr << lu_string << " not found\n";
      } else {
	switch( lu->sub_type() ) {
	case Component_t : case Modification_t : case GA_t :
	  cout << lu->full_type() << " : ";
	  cout << ( ( dc_component * )lu )->buffer_info() << "\n";
	  break;
	case Element_t :
	  cout << lu->full_type() << " : ";
	  cout << ( ( dc_element * )lu )->buffer_info() << "\n";
	  break;
	default :
	  cerr << lu->full_type() << " does not have location info\n";
	}
	loc = lu;
      }
    } else if( lu_string == "pwatch" ) {
      tag T;
      forall( T, watched ) {
	dc_label *l = lookup( T );
	if( l ) cout << T << " : " << *l << "\n";
      }
    } else if( lu_string == "bad_constr" ) {
      list_failed_constraints( cout );
    } else if( lu_string == "watch" ) {
      lu_string = get_lowercase_string();
      lu = search( lu_string, loc, true );
      if( lu == nil ) {
	cerr << lu_string << " not found\n";
      } else {
	watched.insert( lu->get_tag() );
	cout << lu->full_type() << " watched\n";
      }
    } else if( lu_string == "unwatch" ) {
      lu_string = get_lowercase_string();
      if( lu_string == "*" ) {
	watched.clear();
	cout << "watched list cleared\n";
      } else {
	lu = search( lu_string, loc, true );
	if( lu == nil ) {
	  cerr << lu_string << " not found\n";
	} else {
	  watched.del( lu->get_tag() );
	  cout << lu->full_type() << " no longer watched\n";
	}
      }
    } else if( lu_string == "reset" ) {
      reset_all();
    } else if( lu_string == "old" ) {
      lu_string = get_lowercase_string();      
      lu = search( lu_string, loc, true );
      if( !lu ) {
	cerr << lu_string << " not found\n";
      } else if( lu->type() != Element_t ) {
	cerr << lu->full_type() << " is not an element\n"; 
      } else {
	cout << "tag " << lu->get_tag() << " :: " << "old " << lu->full_type() 
	     << " = " << *( ( ( dc_element * )lu )->get_previous() ) << "\n";
	loc = lu;
      }
    } else if( lu_string == "run" ) {
      if( active_ga ) {
	cout << "Closing " << active_ga->full_type() << "\n";
	active_ga->close();
	active_ga = nil;
      }
      lu_string = get_lowercase_string();      
      active_ga = ( ga * )t_search( lu_string, GA_t, loc, true );
      if( !active_ga ) {
	cerr << lu_string << " not found\n";
      } else {
	if( active_ga->execute() ) {
	  cerr << "GA " << lu_string << " failed\n";
	} else {
	  cout << "GA " << lu_string << " succeeded\n";
	}
      }
    } else if( lu_string == "simulate" ) {
      if( active_ga != nil ) {
	cout << "Simulating " << active_ga->full_type() << "\n";
	if( active_ga->simulate() ) {
	  cerr << "Simulation of " << active_ga->full_type() << " failed\n";
	} else {
	  cout << "Simulation of " << active_ga->full_type() << " succeeded\n";
	}
      } else {
	cerr << "Cannot simulate.  No open ga\n";
      }
    } else if( lu_string == "close" ) {
      if( active_ga != nil ) {
	cout << "Closing " << active_ga->full_type() << "\n";
	active_ga->close();
	active_ga = nil;
      } else {
	cerr << "Cannot close.  No open ga\n";
      }
    } else {
      lu = search( lu_string, loc, true );
      if( !lu ) {
	cerr << lu_string << " not found\n";
      } else {
	if( disp_verbose >= 0 ) {
	  cout << "tag " << lu->get_tag() << " :: ";
	}
	cout << *lu << "\n";
	loc = lu;
      }
    }
  } while( 1 );

  if( active_ga != nil ) {
    cout << "Closing " << active_ga->full_type() << "\n";
    active_ga->close();
    active_ga = nil;
  }

  cerr << "Trace_level was " << get_trace_level() << "\n";
}

