package com.codeborne.selenide.impl;
import com.codeborne.selenide.Condition;
import com.codeborne.selenide.SelenideElement;
import com.codeborne.selenide.ex.ElementNotFound;
import org.openqa.selenium.By;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.SearchContext;
import org.openqa.selenium.WebElement;
import java.lang.reflect.Proxy;
import java.util.List;
import static com.codeborne.selenide.Condition.exist;
import static com.codeborne.selenide.Selenide.$;
import static com.codeborne.selenide.WebDriverRunner.getWebDriver;
import static java.lang.Thread.currentThread;
public class ElementFinder extends WebElementSource {
public static SelenideElement wrap(By criteria) {
return wrap(null, criteria, 0);
}
public static SelenideElement wrap(SearchContext parent, By criteria, int index) {
return wrap(SelenideElement.class, parent, criteria, index);
}
@SuppressWarnings("unchecked")
public static <T extends SelenideElement> T wrap(Class<T> clazz, SearchContext parent, By criteria, int index) {
return (T) Proxy.newProxyInstance(
currentThread().getContextClassLoader(),
new Class<?>[]{clazz},
new SelenideElementProxy(new ElementFinder(parent, criteria, index)));
}
private final SearchContext parent;
private final By criteria;
private final int index;
ElementFinder(SearchContext parent, By criteria, int index) {
this.parent = parent;
this.criteria = criteria;
this.index = index;
}
@Override
public SelenideElement find(SelenideElement proxy, Object arg, int index) {
return arg instanceof By ?
wrap(proxy, (By) arg, index) :
wrap(proxy, By.cssSelector((String) arg), index);
}
@Override
public WebElement getWebElement() throws NoSuchElementException, IndexOutOfBoundsException {
return index == 0 ?
WebElementSelector.instance.findElement(getSearchContext(), criteria) :
WebElementSelector.instance.findElements(getSearchContext(), criteria).get(index);
}
@Override
public List<WebElement> findAll() throws NoSuchElementException, IndexOutOfBoundsException {
return index == 0 ?
WebElementSelector.instance.findElements(getSearchContext(), criteria) :
super.findAll();
}
private SearchContext getSearchContext() {
return parent == null ? getWebDriver() :
(parent instanceof SelenideElement) ? ((SelenideElement) parent).toWebElement() :
parent;
}
@Override
public ElementNotFound createElementNotFoundError(Condition condition, Throwable lastError) {
if (parent instanceof SelenideElement) {
((SelenideElement) parent).should(exist);
}
else if (parent instanceof WebElement) {
$((WebElement) parent).should(exist);
}
return super.createElementNotFoundError(condition, lastError);
}
@Override
public String getSearchCriteria() {
return index == 0 ?
Describe.selector(criteria) :
Describe.selector(criteria) + '[' + index + ']';
}
@Override
public String toString() {
return "{" + getSearchCriteria() + '}';
}
}