package io.magentys.cinnamon.webdriver.support.ui;

import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.when;
import io.magentys.cinnamon.webdriver.conditions.Condition;

import java.util.List;
import java.util.concurrent.TimeUnit;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.openqa.selenium.By;
import org.openqa.selenium.SearchContext;
import org.openqa.selenium.TimeoutException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.Clock;
import org.openqa.selenium.support.ui.FluentWait;
import org.openqa.selenium.support.ui.Sleeper;

import com.google.common.collect.Lists;

public class CinnamonExpectedConditionsTest {

    @Mock
    private WebDriver mockDriver;
    @Mock
    private WebElement mockElement;
    @Mock
    private WebElement mockNestedElement;
    @Mock
    private Clock mockClock;
    @Mock
    private Sleeper mockSleeper;
    @Mock
    private Condition<WebElement> mockCondition;

    private FluentWait<SearchContext> wait;

    @Rule
    public ExpectedException expectedException = ExpectedException.none();

    @Before
    public void setUpMocks() {
        MockitoAnnotations.initMocks(this);
        wait = new FluentWait<SearchContext>(mockDriver, mockClock, mockSleeper).withTimeout(5, TimeUnit.SECONDS).pollingEvery(1000,
                TimeUnit.MILLISECONDS);
    }

    @Test
    public void conditionsOfElementLocatedReturnsWebElement() {
        List<WebElement> webElements = Lists.newArrayList(mockElement);
        when(mockDriver.findElements(By.id("someid"))).thenReturn(webElements);
        when(mockCondition.apply(mockElement)).thenReturn(true);
        WebElement elementLocated = wait.until(CinnamonExpectedConditions.conditionOfElementLocated(By.id("someid"), mockCondition));
        assertEquals(mockElement, elementLocated);
    }

    @Test
    public void conditionsOfElementLocatedThrowsTimeoutExceptionWhenNoElementsFound() {
        expectedException.expect(TimeoutException.class);
        expectedException.expectMessage("tried for 5 second");

        List<WebElement> webElements = Lists.newArrayList();
        when(mockDriver.findElements(By.id("someid"))).thenReturn(webElements);
        wait.until(CinnamonExpectedConditions.conditionOfElementLocated(By.id("someid"), mockCondition));
    }

    @Test
    public void conditionsOfElementLocatedThrowsTimeoutExceptionWhenNoElementsMatchCondition() {
        expectedException.expect(TimeoutException.class);
        expectedException.expectMessage("tried for 5 second");

        List<WebElement> webElements = Lists.newArrayList(mockElement);
        when(mockDriver.findElements(By.id("someid"))).thenReturn(webElements);
        when(mockCondition.apply(mockElement)).thenReturn(false);
        wait.until(CinnamonExpectedConditions.conditionOfElementLocated(By.id("someid"), mockCondition));
    }

    @Test
    public void conditionsOfAllElementsLocatedReturnsWebElements() {
        List<WebElement> webElements = Lists.newArrayList(mockElement);
        when(mockDriver.findElements(By.id("someid"))).thenReturn(webElements);
        when(mockCondition.apply(mockElement)).thenReturn(true);
        List<WebElement> allElementsLocated = wait.until(CinnamonExpectedConditions.conditionOfAllElementsLocated(By.id("someid"),
                mockCondition));
        assertEquals(webElements, allElementsLocated);
    }

    @Test
    public void conditionsOfAllElementsLocatedThrowsTimeoutExceptionWhenNoElementsFound() throws InterruptedException {
        expectedException.expect(TimeoutException.class);
        expectedException.expectMessage("tried for 5 second");

        List<WebElement> webElements = Lists.newArrayList();
        when(mockDriver.findElements(By.id("someid"))).thenReturn(webElements);
        wait.until(CinnamonExpectedConditions.conditionOfAllElementsLocated(By.id("someid"), mockCondition));
    }

    @Test
    public void conditionsOfAllElementsLocatedThrowsTimeoutExceptionWhenNoElementsMatchCondition() {
        expectedException.expect(TimeoutException.class);
        expectedException.expectMessage("tried for 5 second");

        List<WebElement> webElements = Lists.newArrayList(mockElement);
        when(mockDriver.findElements(By.id("someid"))).thenReturn(webElements);
        when(mockCondition.apply(mockElement)).thenReturn(false);
        wait.until(CinnamonExpectedConditions.conditionOfAllElementsLocated(By.id("someid"), mockCondition));
    }

}

@@ -56,208 +56,100 @@
 ort 
-static org.junit.Assert.assertEquals;%0Aimport static org.mockito.Mockito.when;%0Aimport io.magentys.cinnamon.webdriver.conditions.Condition;%0A%0Aimport java.util.List;%0Aimport java.util.concurrent.TimeUnit;%0A
+com.google.common.collect.Lists;%0Aimport io.magentys.cinnamon.webdriver.conditions.Condition;
 %0Aimp
@@ -349,18 +349,17 @@
 elenium.
-By
+*
 ;%0Aimport
@@ -379,28 +379,36 @@
 elenium.
-SearchContex
+support.ui.FluentWai
 t;%0Aimpor
@@ -433,284 +433,331 @@
 ium.
-TimeoutException;%0Aimport org.openqa.selenium.WebDriver;%0Aimport org.openqa.selenium.WebElemen
+support.ui.Sleeper;%0A%0Aimport java.time.Clock;%0Aimport java.time.Duration;%0Aimport java.util.Lis
 t;%0A
+%0A
 import 
-org.openqa.selenium.support.ui.Clock;%0Aimport org.openqa.selenium.support.ui.FluentWait;%0Aimport org.openqa.selenium.support.ui.Sleeper;%0A%0Aimport com.google.common.collect.Lists
+static java.time.Instant.EPOCH;%0Aimport static java.time.temporal.ChronoUnit.MILLIS;%0Aimport static java.time.temporal.ChronoUnit.SECONDS;%0Aimport static org.junit.Assert.assertEquals;%0Aimport static org.mockito.Mockito.when
 ;%0A%0Ap
@@ -906,60 +906,8 @@
 ock%0A
-    private WebElement mockNestedElement;%0A    @Mock%0A
     
@@ -1349,85 +1349,380 @@
 out(
-5, TimeUnit.SECONDS).pollingEvery(1000,%0A                TimeUnit.MILLISECONDS
+Duration.of(5, SECONDS))%0A                .pollingEvery(Duration.of(1000, MILLIS));%0A%0A        // Set up a time series that extends past the end of the wait timeout%0A        when(mockClock.instant()).thenReturn(EPOCH, EPOCH.plusMillis(1000), EPOCH.plusMillis(2000), EPOCH.plusMillis(3000), EPOCH.plusMillis(4000),%0A                EPOCH.plusMillis(5000), EPOCH.plusMillis(6000)
 );%0A 
@@ -3670,32 +3670,16 @@
 omeid%22),
-%0A               
  mockCon

update expected conditions test