/**
  * @param event
  * @param depth
  * @param lfc
  * @param ndcStr
  */
 private void start(LoggingEvent event, int depth, TimelineLifecycle lfc, String ndcStr) {
   NdcContext ndcCtxt = getNdcContext(lfc);
   if (ndcCtxt.getNdcObj() != null)
     throw new IllegalStateException(
         "ZMonitor Log4j stack Operation Logic Error or forget to cleanup the state.");
   ndcCtxt.doStart(createName(event, null), event.getRenderedMessage(), ndcStr, depth);
 }
  private static void autoEnd(NdcContext ndcCtxt) {
    NdcObj last = ndcCtxt.getNdcObj();

    StringBuffer sb = new StringBuffer();
    Strings.append(
        sb, "dnc[", last.depth, "|", (last == null ? 0 : last.ndcStr), "], recursive Ending...");

    ndcCtxt.doEnd(new StringName("L4J_FORCE_END"), sb.toString());
  }
  /**
   * @param finalName
   * @param finalMesg
   */
  private void complete(LoggingEvent event, String finalMesg, TimelineLifecycle lfc) {
    Name jName = createName(event, "END");

    NdcContext ndcCtxt = getNdcContext(lfc);

    int currentTlDepth = getCurrentTlDepth(lfc);
    while (currentTlDepth > 1) {
      autoEnd(ndcCtxt);
      currentTlDepth = getCurrentTlDepth(lfc);
    }
    ndcCtxt.doEnd(jName, finalMesg);
  }
  /**
   * Developer will use log4j's: NDC.push() & NDC.pop() to command ZMonitor to do: tl.start() &
   * tl.end()
   *
   * <p>ASSUMPTION: user wont use ZMonitor directly while using log4j NDC, the current tl.depth will
   * always match to the last NDC state we may consider the direct operation of timeline in the
   * future.
   *
   * <p>Base on this concept:
   *
   * <p>If: current NDC Depth > last NDC Depth( or there's no last NDC Depth) we need to do
   * tl.start(), and push current NDC Depth. (check : if currentTlDepth != lastTlDepth do failover.)
   *
   * <p>If: current NDC Depth = last NDC Depth we simply do tl.record().
   *
   * <p>If: current NDC Depth < last NDC Depth if: current NDC Depth = last.last NDC Depth We call
   * tl.end() and pop NDC stack, because user is telling us he want to end the current stack. (check
   * : if currentTlDepth != lastTlDepth do failover.)
   *
   * <p>if: current NDC Depth > last.last NDC Depth We simply do tl.record() because it's not reach
   * the end yet. (check : if currentTlDepth != lastTlDepth do failover.)
   *
   * <p>if: current NDC Depth < last.last NDC Depth We recursively do tl.end with Pop NDCStack and
   * renew the last NDC depth till this condition is not satisfied.
   *
   * @param event
   * @param message
   * @param ndcDepth
   * @param ndcStr
   */
  private void record(LoggingEvent event, int ndcDepth, TimelineLifecycle lfc, String ndcStr) {

    // TODO: how to figure out this part?
    // condition 1. Timeline already started.

    NdcContext ndcCtxt = getNdcContext(lfc);
    NdcObj last = ndcCtxt.getNdcObj();

    //		if(last.tlDepth != getCurrentTlDepth(lfc)){
    //			//TODO: Timeline is operated between two LOG4J log commands, the stack information might be
    // f****d up!
    //			/*
    //			 * Should I allow user to mix log4j with native ZMonitor API?
    //			 */
    //		}

    String mesg = event.getRenderedMessage();
    if (last == null) {
      ndcCtxt.doRecord(createName(event, null), mesg, ndcDepth);
      return;
    }

    if (ndcDepth > last.depth) {
      ndcCtxt.doStart(createName(event, null), mesg, ndcStr, ndcDepth);

    } else if (ndcDepth == last.depth) {
      ndcCtxt.doRecord(createName(event, null), mesg, ndcDepth);

    } else { // if( ndcDepth < last.depth )
      if (ndcDepth == last.previous.depth) {
        ndcCtxt.doEnd(createName(event, "L4J_END"), mesg);

      } else if (ndcDepth > last.previous.depth) {
        ndcCtxt.doRecord(createName(event, null), mesg, ndcDepth);

      } else { // if(ndcDepth < last.previous.depth)
        autoEnd(ndcCtxt);
        record(event, ndcDepth, lfc, ndcStr); // recursive call...
        return;
      }
    }
  }