package com.codeborne.selenide.impl;

import com.codeborne.selenide.Condition;
import com.codeborne.selenide.ShouldableWebElement;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;

import java.io.File;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import static com.codeborne.selenide.DOM.assertElement;
import static com.codeborne.selenide.WebDriverRunner.fail;

public class ShouldableWebElementProxy implements InvocationHandler {
  public static ShouldableWebElement wrap(WebElement element) {
    return (element instanceof ShouldableWebElement) ?
        (ShouldableWebElement) element :
        (ShouldableWebElement) Proxy.newProxyInstance(
          element.getClass().getClassLoader(), new Class<?>[]{ShouldableWebElement.class}, new ShouldableWebElementProxy(element));
  }

  private final WebElement delegate;

  private ShouldableWebElementProxy(WebElement delegate) {
    this.delegate = delegate;
  }

  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    if ("should".equals(method.getName()) || "shouldHave".equals(method.getName()) || "shouldBe".equals(method.getName())) {
      Condition[] conditions = (Condition[]) args[0];
      for (Condition condition : conditions) {
        assertElement(delegate, condition);
      }
      return proxy;
    }
    if ("shouldNot".equals(method.getName()) || "shouldNotHave".equals(method.getName()) || "shouldNotBe".equals(method.getName())) {
      Condition[] conditions = (Condition[]) args[0];
      for (Condition condition : conditions) {
        if (condition.apply(delegate)) {
          fail("Element " + delegate.getTagName() + " has " + condition);
        }
      }
      return proxy;
    }
    else if ("find".equals(method.getName())) {
      return wrap((args[0] instanceof By) ?
                  delegate.findElement((By) args[0]) :
                  delegate.findElement(By.cssSelector((String) args[0])));
    }
    else if ("toString".equals(method.getName())) {
      return new Describe(delegate)
        .attr("id").attr("name").attr("class").attr("value").attr("disabled").attr("type").attr("placeholder")
        .attr("onclick").attr("onClick").attr("onchange").attr("onChange")
        .toString();
    }
    else if ("uploadFromClasspath".equals(method.getName())) {
      String fileName = (String) args[0];
      File file = new File(Thread.currentThread().getContextClassLoader().getResource(fileName).toURI());
      if (!"input".equals(delegate.getTagName())) {
        throw new IllegalArgumentException("Cannot upload file because " + delegate + " is not an INPUT");
      }
      delegate.sendKeys(file.getAbsolutePath());
      return file;
    }
    else {
      return delegateMethod(method, args);
    }
  }

  private Object delegateMethod(Method method, Object[] args) throws Throwable {
    try {
      return method.invoke(delegate, args);
    } catch (InvocationTargetException e) {
      throw e.getTargetException();
    }
  }
}
@@ -376,16 +376,37 @@
 t.Proxy;
+%0Aimport java.net.URL;
 %0A%0Aimport
@@ -2449,156 +2449,8 @@
 ) %7B%0A
-      String fileName = (String) args%5B0%5D;%0A      File file = new File(Thread.currentThread().getContextClassLoader().getResource(fileName).toURI());%0A
     
@@ -2607,24 +2607,330 @@
 T%22);%0A      %7D
+%0A%0A      String fileName = (String) args%5B0%5D;%0A      URL resource = Thread.currentThread().getContextClassLoader().getResource(fileName);%0A      if (resource == null) %7B%0A        throw new IllegalArgumentException(%22File not found in classpath: %22 + fileName);%0A      %7D%0A      File file = new File(resource.toURI());
 %0A      deleg

Check if file exists