/*
   * (non-Javadoc)
   *
   * @see
   * org.eclipse.linuxtools.tmf.trace.ITmfTrace#seekEvent(org.eclipse.linuxtools
   * .tmf.event.TmfTimestamp)
   */
  @Override
  public synchronized TmfExperimentContext seekEvent(TmfTimestamp timestamp) {

    //		Tracer.trace("Ctx: seekEvent(TS) - start");

    if (timestamp == null) {
      timestamp = TmfTimestamp.BigBang;
    }

    // First, find the right checkpoint
    int index = Collections.binarySearch(fCheckpoints, new TmfCheckpoint(timestamp, null));

    // In the very likely case that the checkpoint was not found, bsearch
    // returns its negated would-be location (not an offset...). From that
    // index, we can then position the stream and get the event.
    if (index < 0) {
      index = Math.max(0, -(index + 2));
    }

    // Position the experiment at the checkpoint
    ITmfLocation<?> location;
    synchronized (fCheckpoints) {
      if (fCheckpoints.size() > 0) {
        if (index >= fCheckpoints.size()) {
          index = fCheckpoints.size() - 1;
        }
        location = fCheckpoints.elementAt(index).getLocation();
      } else {
        location = null;
      }
    }

    TmfExperimentContext context = seekLocation(location);
    context.setRank((long) index * fIndexPageSize);

    // And locate the event
    TmfEvent event = parseEvent(context);
    while (event != null && event.getTimestamp().compareTo(timestamp, false) < 0) {
      getNextEvent(context);
      event = parseEvent(context);
    }

    if (event == null) {
      context.setLocation(null);
      context.setRank(ITmfContext.UNKNOWN_RANK);
    }

    return context;
  }
  /*
   * (non-Javadoc)
   *
   * @see
   * org.eclipse.linuxtools.tmf.trace.ITmfTrace#parseEvent(org.eclipse.linuxtools
   * .tmf.trace.TmfContext)
   */
  @Override
  public TmfEvent parseEvent(TmfContext context) {

    // Validate the context
    if (!(context instanceof TmfExperimentContext)) {
      return null; // Throw an exception?
    }

    if (!context.equals(fExperimentContext)) {
      //    		Tracer.trace("Ctx: Restoring context");
      seekLocation(context.getLocation());
    }

    TmfExperimentContext expContext = (TmfExperimentContext) context;

    // If an event was consumed previously, get the next one from that trace
    int lastTrace = expContext.getLastTrace();
    if (lastTrace != TmfExperimentContext.NO_TRACE) {
      TmfContext traceContext = expContext.getContexts()[lastTrace];
      expContext.getEvents()[lastTrace] =
          expContext.getTraces()[lastTrace].getNextEvent(traceContext);
      expContext.setLastTrace(TmfExperimentContext.NO_TRACE);
      fExperimentContext = (TmfExperimentContext) context;
    }

    // Scan the candidate events and identify the "next" trace to read from
    int trace = TmfExperimentContext.NO_TRACE;
    TmfTimestamp timestamp = TmfTimestamp.BigCrunch;
    for (int i = 0; i < expContext.getTraces().length; i++) {
      TmfEvent event = expContext.getEvents()[i];
      if (event != null && event.getTimestamp() != null) {
        TmfTimestamp otherTS = event.getTimestamp();
        if (otherTS.compareTo(timestamp, true) < 0) {
          trace = i;
          timestamp = otherTS;
        }
      }
    }

    TmfEvent event = null;
    if (trace != TmfExperimentContext.NO_TRACE) {
      event = expContext.getEvents()[trace];
    }

    return event;
  }
  @Override
  public synchronized TmfEvent getNextEvent(TmfContext context) {

    // Validate the context
    if (!(context instanceof TmfExperimentContext)) {
      return null; // Throw an exception?
    }

    if (!context.equals(fExperimentContext)) {
      //    		Tracer.trace("Ctx: Restoring context");
      fExperimentContext = seekLocation(context.getLocation());
    }

    TmfExperimentContext expContext = (TmfExperimentContext) context;

    //		dumpContext(expContext, true);

    // If an event was consumed previously, get the next one from that trace
    int lastTrace = expContext.getLastTrace();
    if (lastTrace != TmfExperimentContext.NO_TRACE) {
      TmfContext traceContext = expContext.getContexts()[lastTrace];
      expContext.getEvents()[lastTrace] =
          expContext.getTraces()[lastTrace].getNextEvent(traceContext);
      expContext.setLastTrace(TmfExperimentContext.NO_TRACE);
    }

    // Scan the candidate events and identify the "next" trace to read from
    TmfEvent eventArray[] = expContext.getEvents();
    if (eventArray == null) {
      return null;
    }
    int trace = TmfExperimentContext.NO_TRACE;
    TmfTimestamp timestamp = TmfTimestamp.BigCrunch;
    if (eventArray.length == 1) {
      if (eventArray[0] != null) {
        timestamp = eventArray[0].getTimestamp();
        trace = 0;
      }
    } else {
      for (int i = 0; i < eventArray.length; i++) {
        TmfEvent event = eventArray[i];
        if (event != null && event.getTimestamp() != null) {
          TmfTimestamp otherTS = event.getTimestamp();
          if (otherTS.compareTo(timestamp, true) < 0) {
            trace = i;
            timestamp = otherTS;
          }
        }
      }
    }
    // Update the experiment context and set the "next" event
    TmfEvent event = null;
    if (trace != TmfExperimentContext.NO_TRACE) {
      updateIndex(expContext, timestamp);

      TmfContext traceContext = expContext.getContexts()[trace];
      TmfExperimentLocation expLocation = (TmfExperimentLocation) expContext.getLocation();
      //	        expLocation.getLocation()[trace] = traceContext.getLocation().clone();
      expLocation.getLocation().locations[trace] = traceContext.getLocation();

      //	        updateIndex(expContext, timestamp);

      expLocation.getRanks()[trace] = traceContext.getRank();
      expContext.setLastTrace(trace);
      expContext.updateRank(1);
      event = expContext.getEvents()[trace];
      fExperimentContext = expContext;
    }

    //		if (event != null) {
    //    		Tracer.trace("Exp: " + (expContext.getRank() - 1) + ": " +
    // event.getTimestamp().toString());
    //    		dumpContext(expContext, false);
    //    		Tracer.trace("Ctx: Event returned= " + event.getTimestamp().toString());
    //		}

    return event;
  }
 /**
  * Returns the timestamp of the event at the requested index. If none, returns null.
  *
  * @param index
  * @return
  */
 public TmfTimestamp getTimestamp(int index) {
   TmfExperimentContext context = seekEvent(index);
   TmfEvent event = getNextEvent(context);
   return (event != null) ? event.getTimestamp() : null;
 }