/** ***************************************************************************** */
  void addEntry(String s) {
    // System.err.println("TRACX: " + s);
    if (trace_writer != null) trace_writer.println(s);

    char s0 = s.charAt(0);
    if (s0 == 'T') { // THREAD
      if (thread_entries != null) {
        for (TraceEntry te : thread_entries) pending_entries.add(te);
        thread_entries = null;
      }
      StringTokenizer tok = new StringTokenizer(s);
      tok.nextToken();
      int id = Integer.parseInt(tok.nextToken());
      current_thread = thread_map.get(id);
      if (current_thread == null) {
        int tid = Integer.parseInt(tok.nextToken());
        String tnm = tok.nextToken("\n");
        current_thread = new ThreadData(++thread_counter, tid, tnm);
        thread_map.put(id, current_thread);
      }
      thread_entries = new ArrayList<TraceEntry>();
    } else if (s0 == 'D') { // DONE
      if (trace_writer != null) trace_writer.flush();
      if (thread_entries != null) {
        for (TraceEntry te : thread_entries) pending_entries.add(te);
        thread_entries = null;
      }
      StringTokenizer tok = new StringTokenizer(s);
      tok.nextToken();
      long time = Long.parseLong(tok.nextToken());
      if (next_time != 0) {
        int ct = 0;
        // System.err.println("TRACE: Pending size = " + pending_entries.size());
        while (!pending_entries.isEmpty() && pending_entries.peek().getTime() < next_time) {
          TraceEntry te = pending_entries.remove();
          ++ct;
          outputEntry(te);
        }
        if (ct > 0) {
          for (BdynEventUpdater eu : update_listeners) {
            eu.eventsAdded();
          }
        }
        end_time = Math.max(next_time, end_time);
      }
      next_time = time;
    } else if (s0 == 'S') {
      if (cpu_time == null) {
        StringTokenizer tok = new StringTokenizer(s);
        tok.nextToken();
        cpu_time = Boolean.parseBoolean(tok.nextToken());
      }
    } else if (cpu_time != null) {
      TraceEntry te = new TraceEntry(s, current_thread, cpu_time);
      if (thread_entries == null) pending_entries.add(te);
      else {
        thread_entries.add(te);
        if (te.isExit()) {
          int sz = thread_entries.size();
          int loc = te.getEntryLocation();
          if (sz >= 4) {
            TraceEntry t3 = thread_entries.get(sz - 2);
            if (!t3.isExit() && t3.getEntryLocation() == loc) {
              TraceEntry t2 = thread_entries.get(sz - 3);
              if (t2.isExit() && t2.getEntryLocation() == loc) {
                TraceEntry t1 = thread_entries.get(sz - 4);
                if (!t1.isExit()
                    && t1.getEntryLocation() == loc
                    && (te.getTime() - t1.getTime()) < MERGE_TIME) {
                  t1.merge(t2.getTime(), t3.getTime(), te.getTime());
                  thread_entries.remove(sz - 2);
                  thread_entries.remove(sz - 3);
                }
              }
            }
          }
        }
      }
    }
  }