/**
 * Benchmark the speeed of different Selenium locators.
 * - Put SeleniumData.html in the root directory of your webserver
 * - You may have to change localhost to your correspondent host.
 * Author: Xuan Ngo
 */
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
 
import java.util.Calendar;
import java.util.Formatter;
 
import com.thoughtworks.selenium.DefaultSelenium;
 
public class LocatorsBenchmark
{
 
  public static void main(String[] args) 
  {
    LocatorsBenchmark oLocatorsBenchmark = new LocatorsBenchmark();
 
    /**
     * Generate test data.
     * SeleniumData.html should be put in the root directory 
     *  of your web server.
     */
    final String sFilename = "SeleniumData.html";
    final int iMaxInputsFields = 500;
    oLocatorsBenchmark.generateData(sFilename, iMaxInputsFields);
 
    /*******************************
     * Benchmark process start here.
     *******************************/
    final int iMaxFillInput = 50;
    final int iTry = 5;
 
    long lId              = 0;
    long lName            = 0;
    long lRelativeXpath   = 0;
    long lAbsoluteXpath   = 0;
    long lNameAsIdentifier= 0;
    long lCssSelector     = 0;
 
    final String[] aBrowserTypes = {"*firefox", "*iexplore"};
    for(int j=0; j<aBrowserTypes.length; j++)
    {
      final String sBaseUrl = "http://localhost";
      final String sUrl = "http://localhost/SeleniumData.html";
      final String sBrowserType = aBrowserTypes[j];
      for(int i=0; i<iTry; i++)
      {
        System.out.println(sBrowserType+":  Try "+i);
        lId               += oLocatorsBenchmark.fillData(iMaxFillInput, LocatorsBenchmark.ID, sBaseUrl, sUrl, sBrowserType);
        lName             += oLocatorsBenchmark.fillData(iMaxFillInput, LocatorsBenchmark.NAME, sBaseUrl, sUrl, sBrowserType);
        lCssSelector      += oLocatorsBenchmark.fillData(iMaxFillInput, LocatorsBenchmark.CSS_SELECTOR, sBaseUrl, sUrl, sBrowserType);
        lRelativeXpath    += oLocatorsBenchmark.fillData(iMaxFillInput, LocatorsBenchmark.RELATIVE_XPATH, sBaseUrl, sUrl, sBrowserType);
        lAbsoluteXpath    += oLocatorsBenchmark.fillData(iMaxFillInput, LocatorsBenchmark.ABSOLUTE_XPATH, sBaseUrl, sUrl, sBrowserType);
        lNameAsIdentifier += oLocatorsBenchmark.fillData(iMaxFillInput, LocatorsBenchmark.NAME_AS_IDENTIFIER, sBaseUrl, sUrl, sBrowserType);
        System.out.println("===================================\n");
      }
      /*************************
       * Calculate average time.
       *************************/
      System.out.println("SUMMARY: "+sBrowserType+ "["+iTry+" tries]");
      System.out.println("=========================");
      System.out.println( (new Formatter()).format("%27s %11s %-32s", "ID Avg. = ", (double)lId/(double)iTry+" ms", "  (id=idX)") );
      System.out.println( (new Formatter()).format("%27s %11s %-32s", "NAME Avg. = ", (double)lName/(double)iTry+" ms", "  (name=nameX)") );
      System.out.println( (new Formatter()).format("%27s %11s %-32s", "CSS_SELECTOR Avg. = ", (double)lCssSelector/(double)iTry+" ms", "  (css=input[name=\"nameX\"])") );
      System.out.println( (new Formatter()).format("%27s %11s %-32s", "RELATIVE_XPATH Avg. = ", (double)lRelativeXpath/(double)iTry+" ms", "  (xpath=//input[@name='nameX'])") );
      System.out.println( (new Formatter()).format("%27s %11s %-32s", "ABSOLUTE_XPATH Avg. = ", (double)lAbsoluteXpath/(double)iTry+" ms", "  (xpath=/html/body/input[X])") );
      System.out.println( (new Formatter()).format("%27s %11s %-32s", "NAME_AS_IDENTIFIER Avg. = ", (double)lNameAsIdentifier/(double)iTry+" ms", "  (identifier=nameX)") );
    }
  }
 
  /**
   * Implementation of benchmark class. 
   */
  public static int ID                = 0;
  public static int NAME              = 1;
  public static int RELATIVE_XPATH    = 2;
  public static int ABSOLUTE_XPATH    = 3;
  public static int NAME_AS_IDENTIFIER= 4; // Use the value of @name as identifier.
  public static int CSS_SELECTOR      = 5;
 
  private String[] m_aLocatorType = new String[]{ "ID", 
                          "NAME", 
                          "RELATIVE_XPATH",
                          "ABSOLUTE_XPATH", 
                          "NAME_AS_IDENTIFIER",
                          "CSS_SELECTOR", 
                          };
 
  private void generateData(final String sFilename, final int iMax)
  {
    try
    {
      BufferedWriter out = new BufferedWriter(new FileWriter(sFilename));
      out.write("<html><head><title>Selenium benchmark data</title></head><body>");
      for(int i=0; i<iMax; i++)
      {
        out.write("<input type=\"text\" id=\"id"+i+"\" name=\"name"+i+"\"/> "+i+"<br />");
      }
      out.write("</body></html>");
      out.close();
    }
    catch(IOException e) 
    {
      System.out.println(e.getMessage()+":\n"+e.getStackTrace());
    }   
  }
 
  private final long fillData(final int iMax, final int iLocatorType, final String sBaseUrl, final String sUrl, final String sBrowserType)
  {
    /*********************
     * Open test web page.
     *********************/
    final String sServerHost = "localhost";
    final int iServerPort = 4444;
    DefaultSelenium oDefaultSelenium = new DefaultSelenium(sServerHost, iServerPort, sBrowserType, sBaseUrl);
 
    oDefaultSelenium.start();
//oDefaultSelenium.useXpathLibrary("javascript-xpath");
    oDefaultSelenium.open(sUrl);
 
    /**************************************
     * Time time took to fill input fields.
     **************************************/
    Calendar oStart = Calendar.getInstance();
    for(int i=0; i<iMax; i++)
    {
      if(iLocatorType==ID)
      {
        oDefaultSelenium.type("id=id"+i, i+""); // ID
      }
      else if(iLocatorType==NAME)
      {
        oDefaultSelenium.type("name=name"+i, i+""); // NAME
      }
      else if(iLocatorType==RELATIVE_XPATH)
      {
        oDefaultSelenium.type("xpath=//input[@name='name"+i+"']", i+""); // RELATIVE_XPATH
      }
      else if(iLocatorType==ABSOLUTE_XPATH)
      {
        oDefaultSelenium.type("xpath=/html/body/input["+(i+1)+"]", i+""); // ABSOLUTE_XPATH
      }     
      else if(iLocatorType==NAME_AS_IDENTIFIER)
      {
        oDefaultSelenium.type("identifier=name"+i, i+""); // NAME_AS_IDENTIFIER
      }
      else if(iLocatorType==CSS_SELECTOR)
      {
        oDefaultSelenium.type("css=input[name=\"name"+i+"\"]", i+""); // CSS_SELECTOR
      }     
      else
      {
        System.out.println("Unknown Locator type: "+iLocatorType);
      }
    }
    Calendar oEnd = Calendar.getInstance();
 
    // Uncomment below to pause the execution of intructions so that you can see the results.
//    try{ Thread.sleep(10000); } catch(Exception ex){System.out.println(ex.getMessage());}
 
    oDefaultSelenium.stop();
 
    /************************
     * Calculate statistics. 
     ***********************/
    long lTotalRuntime = oEnd.getTimeInMillis() - oStart.getTimeInMillis();
    long lRuntime = lTotalRuntime;
 
    long lRuntimeHrs = lRuntime/(1000*3600);
    lRuntime = lRuntime - (lRuntimeHrs*1000*3600);// Runtime remaining.
    long lRuntimeMin = (lRuntime)/(1000*60);
    lRuntime = lRuntime - (lRuntimeMin*1000*60);  // Runtime remaining.
    long lRuntimeSec = lRuntime/(1000);
    lRuntime = lRuntime - (lRuntimeSec*1000);     // Runtime remaining.
 
    System.out.println(this.m_aLocatorType[iLocatorType]+" => Time Elapsed("+lTotalRuntime+" ms): "+lRuntimeHrs+" hr(s)  "+lRuntimeMin+" min(s)  "+lRuntimeSec+" sec(s)  "+lRuntime+" ms");
    return lTotalRuntime;
  }
 
}
