package org.tribbloid.spookystuff.selenium;

import org.apache.commons.io.IOUtils;
import org.openqa.selenium.*;

import java.io.IOException;
import java.io.Serializable;
import java.util.List;

import static java.lang.Thread.currentThread;

//require support from Java
public class BySizzleCssSelector extends By implements Serializable {

  private static final long serialVersionUID = -584931842702178943L;

  private final String selector;

  private static String sizzleSource = null;

  public BySizzleCssSelector(String selector) {
    this.selector = selector;
  }

  @Override
  public WebElement findElement(SearchContext context) {

    if (context instanceof JavascriptExecutor) {
      List<WebElement> webElements = evaluateSizzleSelector((JavascriptExecutor) context, selector);
      return webElements.isEmpty() ? null : webElements.get(0);
    }
    else {
      throw new WebDriverException(
        "Driver does not support finding an element by selector: " + selector);
    }
  }

  @Override
  public List<WebElement> findElements(SearchContext context) {

    if (context instanceof JavascriptExecutor) {
      return evaluateSizzleSelector((JavascriptExecutor) context, selector);
    }
    else {
      throw new WebDriverException(
        "Driver does not support finding an element by selector: " + selector);
    }
  }

  @Override
  public String toString() {
    return "By.selector: " + selector;
  }

  protected List<WebElement> evaluateSizzleSelector(JavascriptExecutor context, String selector) {
    injectSizzleIfNeeded(context);

    String sizzleSelector = selector.replace("By.selector: ", "");
    if (context instanceof WebElement)
      return executeJavaScript(context, "return Sizzle(arguments[0], arguments[1])", sizzleSelector, context);
    else
      return executeJavaScript(context, "return Sizzle(arguments[0])", sizzleSelector);
  }

  protected void injectSizzleIfNeeded(JavascriptExecutor context) {
    if (!sizzleLoaded(context)) {
      injectSizzle(context);
    }
  }

  protected Boolean sizzleLoaded(JavascriptExecutor context) {
    try {
      return executeJavaScript(context, "return Sizzle() != null");
    } catch (WebDriverException e) {
      return false;
    }
  }

  protected static synchronized void injectSizzle(JavascriptExecutor context) {
    if (sizzleSource == null) {
      try {
        sizzleSource = IOUtils.toString(currentThread().getContextClassLoader().getResource("sizzle.js"));
      } catch (IOException e) {
        throw new RuntimeException("Cannot load sizzle.js from classpath", e);
      }
    }
    executeJavaScript(context, sizzleSource);
  }

  protected static <T> T executeJavaScript(JavascriptExecutor context, String jsCode, Object... arguments) {
    return (T) context.executeScript(jsCode, arguments);
  }
}
@@ -111,36 +111,8 @@
 *;%0A%0A
-import java.io.IOException;%0A
 impo
@@ -164,83 +164,8 @@
 t;%0A%0A
-import static java.lang.Thread.currentThread;%0A%0A//require support from Java%0A
 publ
@@ -2141,23 +2141,16 @@
 otected 
-static 
 synchron
@@ -2290,45 +2290,21 @@
 ing(
-currentThread().getContextClassLoader
+this.getClass
 ().g
@@ -2315,16 +2315,17 @@
 source(%22
+/
 sizzle.j
@@ -2349,19 +2349,17 @@
 ch (
-IOException
+Throwable
  e) 

fix the classloader problem that caused sizzle.js to be unfound