package com.autonomy.abc.matchers;

import com.hp.autonomy.frontend.selenium.util.AppElement;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeMatcher;
import org.openqa.selenium.By;
import org.openqa.selenium.TimeoutException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

import static org.hamcrest.Matchers.containsString;

public class ElementMatchers {
    public static Matcher<? super WebElement> containsElement(final By by) {
        return new TypeSafeMatcher<WebElement>() {
            @Override
            protected boolean matchesSafely(WebElement webElement) {
                return webElement.findElements(by).size() > 0;
            }

            @Override
            public void describeTo(Description description) {
                description.appendText("a parent element containing a child ").appendValue(by);
            }

            @Override
        public void describeMismatchSafely(final WebElement webElement, final Description description) {
                description.appendText("no child found inside ").appendValue(webElement);
            }
        };
    }

    public static Matcher<? super WebElement> containsText(final String text) {
        return new TypeSafeMatcher<WebElement>() {
            private Matcher<String> container = containsString(text);

            @Override
            protected boolean matchesSafely(WebElement item) {
                return container.matches(item.getText());
            }

            @Override
            public void describeTo(Description description) {
                description.appendText("a tag containing ").appendValue(text);
            }

            @Override
            public void describeMismatchSafely(final WebElement item, final Description description) {
                description.appendText("<" + item.getTagName() + "> tag had text ").appendValue(item.getText());
            }
        };
    }

    public static Matcher<? super WebElement> hasAttribute(final String text) {
        return new TypeSafeMatcher<WebElement>() {

            @Override
            protected boolean matchesSafely(WebElement item) {
                return item.getAttribute(text) != null;
            }

            @Override
            public void describeTo(Description description) {
                description.appendText("a tag with attribute ").appendValue(text);
            }

            @Override
            public void describeMismatchSafely(final WebElement item, final Description description) {
                description.appendText("element was ").appendText(item.toString());
            }
        };
    }

    public static Matcher<? super WebElement> disabled() {
        return new TypeSafeMatcher<WebElement>() {

            @Override
            protected boolean matchesSafely(WebElement item) {
                return item.getAttribute("disabled") != null;
            }

            @Override
            public void describeTo(Description description) {
                description.appendText("an element that is disabled");
            }

            @Override
            public void describeMismatchSafely(final WebElement item, final Description description) {
                description.appendText("element was ").appendText(item.toString());
            }
        };
    }

    public static Matcher<? super AppElement> appearsWithin(final int seconds) {
        return new TypeSafeMatcher<AppElement>() {
            @Override
            protected boolean matchesSafely(AppElement item) {
                try {
                    new WebDriverWait(item.getDriver(), seconds).until(ExpectedConditions.visibilityOf(item));
                    return true;
                } catch (TimeoutException e) {
                    return false;
                }
            }

            @Override
            public void describeTo(Description description) {
                description.appendText("an element appeared within " + seconds + " seconds");
            }

            @Override
            protected void describeMismatchSafely(AppElement item, Description description) {
                description.appendText("element was ").appendText(item.toString());
            }
        };
    }

    public static  Matcher<? super WebElement> appearsWithin(final int seconds, final WebDriver driver) {
        return new TypeSafeMatcher<WebElement>() {
            @Override
            protected boolean matchesSafely(WebElement item) {
                try {
                    new WebDriverWait(driver, seconds).until(ExpectedConditions.visibilityOf(item));
                    return true;
                } catch (TimeoutException e) {
                    return false;
                }
            }

            @Override
            public void describeTo(Description description) {
                description.appendText("an element appeared within " + seconds + " seconds");
            }

            @Override
            protected void describeMismatchSafely(WebElement item, Description description) {
                description.appendText("element was ").appendText(item.toString());
            }
        };
    }

}

@@ -2076,32 +2076,981 @@
       %7D;%0A    %7D%0A%0A
+    public static Matcher%3C? super WebElement%3E hasTextThat(final Matcher%3CString%3E matcher) %7B%0A        return new TypeSafeMatcher%3CWebElement%3E() %7B%0A            @Override%0A            protected boolean matchesSafely(WebElement item) %7B%0A                return matcher.matches(item.getText());%0A            %7D%0A%0A            @Override%0A            public void describeTo(Description description) %7B%0A                description.appendText(%22a tag whose text is %22).appendDescriptionOf(matcher);%0A            %7D%0A%0A            @Override%0A            protected void describeMismatchSafely(WebElement item, Description mismatchDescription) %7B%0A//                mismatchDescription.appendText(%22%3C%22 + item.getTagName() + %22%3E tag had text %22).appendValue(item.getText());%0A                mismatchDescription.appendText(%22was a %3C%22 + item.getTagName() + %22%3E tag whose text %22);%0A                matcher.describeMismatch(item.getText(), mismatchDescription);%0A            %7D%0A        %7D;%0A    %7D%0A%0A
     public stati
@@ -6287,10 +6287,750 @@
 %0A    %7D%0A%0A
+    public static Matcher%3C? super WebElement%3E modalIsDisplayed() %7B%0A        return new TypeSafeMatcher%3CWebElement%3E() %7B%0A            @Override%0A            protected boolean matchesSafely(WebElement item) %7B%0A                return !item.findElement(By.xpath(%22//*%22)).findElements(By.cssSelector(%22.modal%5Baria-hidden='false'%5D%22)).isEmpty();%0A            %7D%0A%0A            @Override%0A            public void describeTo(Description description) %7B%0A                description.appendText(%22a modal is displayed%22);%0A            %7D%0A%0A            @Override%0A            protected void describeMismatchSafely(WebElement item, Description mismatchDescription) %7B%0A                mismatchDescription.appendText(%22no modal was displayed%22);%0A            %7D%0A        %7D;%0A    %7D%0A%0A
 %7D%0A

Add convenience matchers for WebElements: hasTextThat and modalIsDisplayed