package examples.cluster.utils;

import java.util.*;
import java.text.NumberFormat;

/**
 * Utility class to keep track of clustered actions. 
 * Uniquely associating the action with a cluster member.
 * <p>
 * It expects messages in the format [message : weblogic.system.name].
 * Example: <tt>addClusterMessage("Hello : cluster1");</tt>
 * <p>
 * It keeps track of the unique system names and
 * tabulates the results.
 */

public class ClusterUtils {
  
  /* Hash of unique cluster members */
  private Hashtable clusterMembers;

  /* Keep track of number of exceptions */
  private int numExceptions = 0;

  /* Vector of results */
  private Vector results = new Vector();

  /** 
   * Token used to split the message from <tt>addClusterMessage(String message)</tt>
   * into a message and the <tt>weblogic.system.name</tt>.
   */
  private String token = ":";

  /**
   * Constructor
   */    
  public ClusterUtils(){
    clusterMembers = new Hashtable();
  }

  /**
   * Constructor
   * @param iterations        int Number of iterations
   * @deprecated              Use <tt>ClusterUtils()</tt> instead
   *                          as size is now dynamically allocated.
   */    
  public ClusterUtils(int iterations){
    clusterMembers = new Hashtable();
  }

  /**
   * Default expectation for format [message : weblogic.system.name].
   * Example: <tt>addClusterMessage("Hello : cluster1");</tt>
   * @param message           String Message
   */
  public void addClusterMessage(String message){
    results.addElement(message);
  }
  
  /**
   * Allow someone to overide the default token used ":".
   * @param token             String New token for dividing message
   */
  public void setToken(String token){
    this.token = token;
  }
  
  public int getIterations(){
    return results.size();
  }

  public int getExceptionCount(){
    return numExceptions;
  }

  public void incrementExceptionCount(){
    numExceptions++;
  }
  
  /**
   * Prepares report of results from statistics.
   */
  public String processStatistics(){
    int invocations = 0;
    for(int i=0; i < results.size(); i++){
      if (results.elementAt(i) != null) {
        invocations++;
        StringTokenizer tokens = new StringTokenizer((String)results.elementAt(i), token);
        tokens.nextToken();
        String clusterName = tokens.nextToken();
        clusterName = clusterName.trim();
        Cluster cluster = null;
        if(!knownCluster(clusterName)){
          cluster = new Cluster(clusterName);
        }else{
          cluster = (Cluster)clusterMembers.get(clusterName);
        }
        cluster.increment();
        clusterMembers.put(clusterName, cluster);
      }
    }
    StringBuffer stats = new StringBuffer("");
    if (clusterMembers.isEmpty() | invocations == 0) {
      stats.append("No statistics are available.\n");
    } else {
      Enumeration enum = clusterMembers.keys();
      while(enum.hasMoreElements()){
        String key = (String)enum.nextElement();
        Cluster cluster = (Cluster)clusterMembers.get(key);
        stats.append("\"" + key + "\" processed " + cluster.getIncInt()  
          + " (" + getPercent(cluster.getIncInt(),invocations) + ") of "
          + invocations + " invocations\n");
      }
    }
    return stats.toString();
  }
  
  private boolean knownCluster(String clusterName){
    if(clusterMembers.containsKey(clusterName))
      return true;
    return false;
  }

  private String getPercent (int top, int bottom){
    NumberFormat nf = NumberFormat.getPercentInstance();
    return nf.format(new Float( (float)top / (float)bottom) );
  }

/**
 * Inner class to keep track of unique cluster members. 
 */
  class Cluster{
    String name  = null;
    int messages = 0;

    Cluster(String clusterName){
      name = clusterName;
    }

    public void increment(){
      messages++;
    }

    public String getName(){
      return name;
    }

    public int getIncInt(){
      return messages;
    }
  }
}


