content: /**
   * Licensed to the Apache Software Foundation (ASF) under one or more
   * contributor license agreements.  See the NOTICE file distributed with
   * this work for additional information regarding copyright ownership.
   * The ASF licenses this file to You under the Apache License, Version 2.0
   * (the "License"); you may not use this file except in compliance with
   * the License.  You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package org.apache.solr.common.util;
  
  import java.lang.System;
  import java.lang.Thread;
  import java.util.*;
  
  /** A recursive timer.
   * 
   * RTimers are started automatically when instantiated; subtimers are also
   * started automatically when created.
   *
   * @since solr 1.3
   * @version $Id: RTimer.java 724867 2008-12-09 20:23:52Z ryan $
   */
  public class RTimer {
  
    public static final int STARTED = 0;
    public static final int STOPPED = 1;
    public static final int PAUSED = 2;
  
    protected int state;
    protected double startTime;
    protected double time;
    protected double culmTime;
    protected SimpleOrderedMap<RTimer> children;
  
    public RTimer() {
      time = 0;
      culmTime = 0;
      children = new SimpleOrderedMap<RTimer>();
      startTime = now();
      state = STARTED;
    }
  
    /** Get current time
     *
     * May override to implement a different timer (CPU time, etc).
     */
    protected double now() { return System.currentTimeMillis(); }
  
    /** Recursively stop timer and sub timers */
    public double stop() {
      assert state == STARTED || state == PAUSED;
      time = culmTime;
      if(state == STARTED) 
        time += now() - startTime;
      state = STOPPED;
      
      for( Map.Entry<String,RTimer> entry : children ) {
        RTimer child = entry.getValue();
        if(child.state == STARTED || child.state == PAUSED) 
          child.stop();
      }
      return time;
    }
  
    public void pause() {
      assert state == STARTED;
      culmTime += now() - startTime;
      state = PAUSED;
    }
    
    public void resume() {
      if(state == STARTED)
        return;
      assert state == PAUSED;
      state = STARTED;
      startTime = now();
    }
  
    /** Get total elapsed time for this timer.
     *
     * Timer must be STOPped.
     */
    public double getTime() {
      assert state == STOPPED;
      return time;
    }
  
    /** Create new subtimer with given name
     *
     * Subtimer will be started.
     */
    public RTimer sub(String desc) {
      RTimer child = children.get( desc );
      if( child == null ) {
        child = new RTimer();
        children.add(desc, child);
      }
      return child;
    }
  
    @Override
    public String toString() {
      return asNamedList().toString();
    }
  
    public NamedList asNamedList() {
      NamedList<Object> m = new SimpleOrderedMap<Object>();
      m.add( "time", time );
      if( children.size() > 0 ) {
        for( Map.Entry<String, RTimer> entry : children ) {
          m.add( entry.getKey(), entry.getValue().asNamedList() );
        }
      }
      return m;
    }
    
    /**
     * Manipulating this map may have undefined results.
     */
    public SimpleOrderedMap<RTimer> getChildren()
    {
      return children;
    }
  
    /*************** Testing *******/
    public static void main(String []argv) throws InterruptedException {
      RTimer rt = new RTimer(), subt, st;
      Thread.sleep(100);
  
      subt = rt.sub("sub1");
      Thread.sleep(50);
      st = subt.sub("sub1.1");
      st.resume();
      Thread.sleep(10);
      st.pause();
      Thread.sleep(50);
      st.resume();
      Thread.sleep(10);
      st.pause();
      subt.stop();
      rt.stop();
  
      System.out.println( rt.toString());
    }
  }
  