package pages.base;

import java.util.List;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.openqa.selenium.By;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.StaleElementReferenceException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.PageFactory;
import org.openqa.selenium.support.pagefactory.AjaxElementLocatorFactory;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

public abstract class BasePage {

	protected static final Logger LOGGER = LogManager.getLogger(BasePage.class);
	protected WebDriver driver;
	public int TimeoutValue = 60;

	protected BasePage(WebDriver driver) {
		this.driver = driver;
		LOGGER.info("Navigating to [{}]...", this.getClass().getSimpleName());
		PageFactory.initElements(new AjaxElementLocatorFactory(driver, TimeoutValue), this);       
	}

	protected WebDriver getDriverProxy() {
		return driver;
	}

	protected void waitForElement(WebElement element , long waitforseconds){
		WebDriverWait wait = new WebDriverWait(driver, waitforseconds);
		wait.until(ExpectedConditions.visibilityOf(element));    	
	}

	protected void waitForElements(BasePage page, final WebElement... elements) {
		new WebDriverWait(getDriverProxy(), 40)
		.withMessage("Timed out navigating to [" + page.getClass().getName() + "]. Expected elements were not found. See screenshot for more details.")
		.until((WebDriver d) -> {
			for (WebElement elm : elements) {
				try {
					elm.isDisplayed();
				} catch (NoSuchElementException e) {
					// This is expected exception since we are waiting for the selenium element to come into existence.
					// This method will be called repeatedly until it reaches timeout or finds all selenium given.
					return false;
				}
			}
			return true;
		});
	}

	protected void waitForElements(BasePage page, final By... elements) {
		new WebDriverWait(getDriverProxy(), 40)
		.withMessage("Timed out navigating to [" + page.getClass().getName() + "]. Expected selenium elements were not found. See screenshot for more details.")
		.until((WebDriver d) -> {
			boolean success = true;
			for (By elm : elements) {
				List<WebElement> foundElements = d.findElements(elm);
				if (!foundElements.isEmpty()) {
					try {
						((WebElement) foundElements.get(0)).isDisplayed();
					} catch (NoSuchElementException e) {
						// This is expected exception since we are waiting for the selenium element to come into existence.
						// This method will be called repeatedly until it reaches timeout or finds all selenium given.
						success = false;
						break;
					}
				} else {
					success = false;
					break;
				}
			}
			return success;
		});
	}

	protected void waitForElementToNotExist(WebElement element) {
		new WebDriverWait(getDriverProxy(), 20)
		.withMessage("Timed out waiting for element to not exist.")
		.until((WebDriver d) -> {
			boolean conditionMet = false;
			try {
				// We don't really care whether it's displayed or not, just if it exists.
				element.isDisplayed();
			} catch (NoSuchElementException | StaleElementReferenceException e) {
				conditionMet = true;
			}
			return conditionMet;
		});
	}

}