#include <stdio.h>
#include "Fields.h"
#include <list>
#include <map>
#include <string>
#include <stack>
#include <queue>

using namespace std;

class Vertex;

class Edge {
public:
  Edge(Vertex *vtx1, Vertex *vtx2) {
    v1 = vtx1;
    v2 = vtx2;
  }
  Vertex *getVertex1() { return v1; }
  Vertex *getVertex2() { return v2; }

protected:
    Vertex *v1;
    Vertex *v2;
};

class Vertex {
protected:
  string name;
  list<Edge *> edges;
  int nincident;
  list<Edge *>::iterator edgesIter;
  bool visited;
public:
  Vertex(string n) {
    name = n;
    nincident = 0;
    visited = false;
  }
  string getName() { return name; }
  bool getVisited() { return visited; }
  void setVisited(bool flag) { visited = flag; }
  int getNumIncident() { return nincident; }
  void firstEdge() { edgesIter = edges.begin(); }
  void nextEdge() { edgesIter++; }
  bool endOfEdges() { return edgesIter == edges.end(); }
  Edge *getEdge() { return *edgesIter; }

  void addEdge(Edge *e) { 
    edges.push_back(e); 
    e->getVertex2()->nincident++;
  }

  void deleteEdge() {
    Edge *e = getEdge();
    e->getVertex2()->nincident--;
    edgesIter = edges.erase(edgesIter);
  }
};

void find_zero_incident(map<string, Vertex *> &g, 
			queue<Vertex *> &start_vertices)
{
  Vertex *v;

  map<string, Vertex *>::iterator verticesIter;
  for (verticesIter = g.begin(); verticesIter != g.end(); verticesIter++) {
    v = verticesIter->second;
    if (v->getNumIncident() == 0) {
      start_vertices.push(v);
    }
  }
}

void dfs(Vertex *v, stack<Vertex *> &top_order) {
  v->setVisited(true);
  for (v->firstEdge(); !v->endOfEdges(); v->nextEdge()) {
    Edge *e = v->getEdge();
    Vertex *toVertex = e->getVertex2();
    if (!toVertex->getVisited())
      dfs(toVertex, top_order);
  }
  top_order.push(v);
}

main() 
{
  Fields *f;
  map<string, Vertex *> g;
  stack<Vertex *> topological_order;
  queue<Vertex *> start_vertices;
  Vertex *v;
  Vertex *v2;
  Edge *e;
  string s;

  v = 0;

  f = new Fields();

  while (f->get_line() >= 0) {
    if (f->get_NF() > 0) {
      if (f->get_field(0) == "CLASS") {
        if (f->get_NF() != 2) {
          fprintf(stderr, "%d: CLASS name\n", f->get_line_number());
          exit(1);
        } 
        s = f->get_field(1);
	v = g[s];
        if (v == 0) {
	  v = new Vertex(s);
          g[s] = v;
        } 
      } else if (f->get_field(0) == "PREREQ") {
        if (f->get_NF() != 2) {
          fprintf(stderr, "%d: PREREQ class\n", f->get_line_number());
          exit(1);
        } 
        if (v == 0) {
          fprintf(stderr, "%d: PREREQ -- no current vertex\n", 
                  f->get_line_number());
          exit(1);
        } 
        s = f->get_field(1);
        v2 = g[s];
        if (v2 == 0) {
	  v2 = new Vertex(s);
	  g[s] = v2;
        } 
        e = new Edge(v2, v);
        v2->addEdge(e);
    
      } else {
          fprintf(stderr, "%d: lines must be CLASS or PREREQ\n", 
                   f->get_line_number());
          exit(1);
      }
    }
  }

  find_zero_incident(g, start_vertices);
  while (!start_vertices.empty()) {
    v = start_vertices.front();
    start_vertices.pop();
    dfs(v, topological_order);
  }
  while (!topological_order.empty()) {
    v = topological_order.top();
    topological_order.pop();
    printf("%s\n", v->getName().c_str());
  }
}
    

