/*
 * #%L
 * wcm.io
 * %%
 * Copyright (C) 2018 wcm.io
 * %%
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * #L%
 */
package io.wcm.qa.galenium.interaction;

import static io.wcm.qa.galenium.reporting.GaleniumReportUtil.MARKER_INFO;
import static io.wcm.qa.galenium.reporting.GaleniumReportUtil.getLogger;
import static io.wcm.qa.galenium.util.GaleniumContext.getDriver;

import java.util.List;

import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.UnsupportedCommandException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Actions;

import com.galenframework.browser.SeleniumBrowser;

import io.wcm.qa.galenium.selectors.Selector;

public final class Mouse {

  private Mouse() {
    // do not instantiate
  }

  /**
   * @return current vertical scroll position of browser with 0 being the very top
   */
  public static Long getVerticalScrollPosition() {
    SeleniumBrowser seleniumBrowser = new SeleniumBrowser(getDriver());
    StringBuilder builder = new StringBuilder();
    builder.append("if (window.pageYOffset) ");
    builder.append("return window.pageYOffset;");
    builder.append("else if(window.document.documentElement.scrollTop)");
    builder.append("return window.document.documentElement.scrollTop;");
    builder.append("else ");
    builder.append("return window.document.body.scrollTop;");
    Long scrollYPosition = (Long)seleniumBrowser.executeJavascript(builder.toString());
    return scrollYPosition;
  }

  /**
   * Hover mouse over element.
   * @param selector identifies element.
   */
  public static void hover(Selector selector) {
    getLogger().debug("attempting mouse over: " + selector.elementName());
    WebDriver driver = getDriver();
    List<WebElement> mouseOverElements = driver.findElements(selector.asBy());
    if (!mouseOverElements.isEmpty()) {
      WebElement mouseOverElement = mouseOverElements.get(0);
      if (mouseOverElement.isDisplayed()) {
        getLogger().debug("Moving to element: " + mouseOverElement);
        try {
          Actions actions = getActions(driver);
          actions.moveToElement(mouseOverElement).perform();
        }
        catch (UnsupportedCommandException ex) {
          getLogger().debug("Attempting JS workaround for mouseover.");
          String javaScript = "var evObj = document.createEvent('MouseEvents');" +
              "evObj.initMouseEvent(\"mouseover\",true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);" +
              "arguments[0].dispatchEvent(evObj);";

          ((JavascriptExecutor)driver).executeScript(javaScript, mouseOverElement);
        }
      }
    }
    else {
      getLogger().debug("no elements found.");
    }
  }

  /**
   * Move mouse horizontally over page and scroll if necessary to keep it in viewport.
   * @param offsetInPixel to move mouse horizontally by (negative values move to the left.
   */
  public static void moveHorizontally(int offsetInPixel) {
    if (offsetInPixel > 0) {
      getLogger().debug(MARKER_INFO, "move mouse right by " + offsetInPixel);
    }
    else if (offsetInPixel < 0) {
      getLogger().debug(MARKER_INFO, "move mouse left by " + -offsetInPixel);
    }
    getActions(getDriver()).moveByOffset(offsetInPixel, 0).perform();
  }

  private static Actions getActions(WebDriver driver) {
    return new Actions(driver);
  }

}

@@ -2618,30 +2618,24 @@
  getActions(
-driver
 );%0A         
@@ -3362,29 +3362,32 @@
  @param 
-offsetInPixel
+horizontalOffset
  to move
@@ -3496,46 +3496,52 @@
 int 
-offsetInPixel) %7B%0A    if (offsetInPixel
+horizontalOffset) %7B%0A    if (horizontalOffset
  %3E 0
@@ -3606,29 +3606,32 @@
  by %22 + 
-offsetInPixel
+horizontalOffset
 );%0A    %7D
@@ -3644,29 +3644,32 @@
 lse if (
-offsetInPixel
+horizontalOffset
  %3C 0) %7B%0A
@@ -3734,157 +3734,537 @@
  + -
-offsetInPixel);%0A    %7D%0A    getActions(getDriver()).moveByOffset(offsetInPixel, 0).perform();%0A  %7D%0A%0A  private static Actions getActions(WebDriver driver
+horizontalOffset);%0A    %7D%0A    int verticalOffset = 0;%0A    moveByOffset(horizontalOffset, verticalOffset);%0A  %7D%0A%0A  public static void moveByOffset(int horizontalOffset, int verticalOffset) %7B%0A    getActions().moveByOffset(horizontalOffset, verticalOffset).perform();%0A  %7D%0A%0A  public static void moveTo(Selector selector) %7B%0A    getActions().moveToElement(Element.findOrFail(selector));%0A  %7D%0A%0A  public static void clickLocation(Selector selector) %7B%0A    moveTo(selector);%0A    getActions().click();%0A  %7D%0A%0A  private static Actions getActions(
 ) %7B%0A
@@ -4286,22 +4286,27 @@
 Actions(
-d
+getD
 river
+()
 );%0A  %7D%0A%0A

add more mouse specific methods