/*
Copyright 2012 Opera Software ASA

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.
*/

package com.opera.core.systems.testing.drivers;

import com.opera.core.systems.OperaDriver;
import com.opera.core.systems.OperaProduct;
import com.opera.core.systems.runner.OperaRunner;
import com.opera.core.systems.runner.launcher.OperaLauncherRunnerSettings;
import com.opera.core.systems.scope.internal.OperaIntervals;
import com.opera.core.systems.scope.services.IOperaExec;

import org.openqa.selenium.Capabilities;
import org.openqa.selenium.Platform;
import org.openqa.selenium.remote.DesiredCapabilities;

import java.util.concurrent.TimeUnit;
import java.util.logging.Level;

/**
 * Provides access to the {@link com.opera.core.systems.runner.OperaRunner}, so we can detect
 * crashes.
 */
public class TestOperaDriver extends OperaDriver {

  public static enum ClosingStrategy {SWITCH_TO, ACTION}

  private final String controlWindow;
  private final Platform currentPlatform = Platform.getCurrent();

  private OperaProduct currentProduct;

  /**
   * Creates a new TestOperaDriver with the given capabilities.
   *
   * @param capabilities the set of capabilities to use
   */
  public TestOperaDriver(Capabilities capabilities) {
    super(capabilities);
    controlWindow = getWindowHandle();
  }

  /**
   * Provides access to {@link OperaRunner} which is used for monitoring the Opera process.
   *
   * @return instance of runner control interface for this driver instance
   */
  public OperaRunner getRunner() {
    return runner;
  }

  /**
   * Return the currently used set of capabilities.
   *
   * @return currently used capabilities
   */
  public Capabilities getCapabilities() {
    return capabilities;
  }

  public boolean isRunning() {
    return runner.isOperaRunning();
  }

  public boolean isOperaIdleAvailable() {
    return super.isOperaIdleAvailable();
  }

  public IOperaExec getExecService() {
    return super.getExecService();
  }

  public OperaLauncherRunnerSettings getSettings() {
    return super.settings;
  }

  /**
   * Get the window handle of the initial control window, that is, the first window that was
   * opened.
   *
   * @return window handle of control window
   */
  public String getControlWindow() {
    return controlWindow;
  }

  /**
   * Closes all windows except the control window using the {@link ClosingStrategy#SWITCH_TO}
   * strategy.
   */
  public void closeAll() {
    closeAll(ClosingStrategy.SWITCH_TO);
  }

  /**
   * Allows you to specifying the strategy for closing all windows (apart from the control window).
   * Windows can either be closed using a {@link OperaDriver#switchTo()} and {@link
   * OperaDriver#close()} call, or by sending the action "Close all pages".  The latter method
   * <strong>does not</strong> guarantee that all windows are in fact closed.
   *
   * This method is failsafe, meaning that if there are no windows open it will not do anything.
   *
   * @param strategy the strategy to use for closing windows; either {@link
   *                 ClosingStrategy#SWITCH_TO} or {@link ClosingStrategy#ACTION}
   */
  public void closeAll(ClosingStrategy strategy) {
    int windowCountBeforeClosing = getWindowCount();

    // Either control window (1) or no windows (0)
    if (windowCountBeforeClosing <= 1) {
      return;
    }

    switch (strategy) {
      case SWITCH_TO:
        closeAllUsingSwitchTo();
        break;
      case ACTION:
        closeAllUsingAction();
        break;
    }

    // Were all windows closed?
    if (getWindowCount() != 1) {
      logger.warning("Should have had " + (windowCountBeforeClosing - 1) + " fewer window(s)");
    }

    // Make sure we're in the control window before continuing
    if (!getControlWindow().equals(getWindowHandle())) {
      logger.warning("After closing windows, we were not in the default control window");
      switchTo().window(getControlWindow());
    }
  }

  public TestOperaUtils utils() {
    return new TestOperaUtils();
  }

  public class TestOperaUtils extends OperaUtils {

    /**
     * Overrides the default {@link OperaDriver.OperaUtils#getProduct()} to also take the
     * environmental variable <code>OPERA_PRODUCT</code> into account, which can be used for
     *
     * @return browser's product type
     */
    public OperaProduct getProduct() {
      if (currentProduct == null) {
        currentProduct = OperaProduct.CORE;  // default
        String requestedProduct = System.getenv("OPERA_PRODUCT");

        if (isRunning() && (requestedProduct == null || requestedProduct.isEmpty())) {
          requestedProduct = super.getProduct().toString();
        } else {
          logger.warning("Driver is not running, defaulting to " + currentProduct);
        }

        try {
          currentProduct = OperaProduct.get(requestedProduct);
        } catch (IllegalArgumentException e) {
          logger.warning("Product '" + requestedProduct + "' not found, defaulting to " +
                         currentProduct);
        }
      }

      return currentProduct;
    }

    public Platform getPlatform() {
      return currentPlatform;
    }

  }

  /**
   * Get the default set of capabilities used in OperaDriver and modifies them.
   *
   * @return capability defaults for {@link TestOperaDriver}
   */
  public static Capabilities getDefaultCapabilities() {
    DesiredCapabilities c = (DesiredCapabilities) OperaDriver.getDefaultCapabilities();
    c.setCapability(OperaDriver.LOGGING_LEVEL, Level.FINE);
    return c;
  }

  /**
   * Iterates through windows and closes all of them apart from the controlling window.  If the
   * default control window (first window) is closed, the browser will be quit.
   */
  private void closeAllUsingSwitchTo() {
    // Close all windows apart from our first control window
    for (String windowHandle : getWindowHandles()) {
      if (!windowHandle.equals(getControlWindow())) {
        switchTo().window(windowHandle);
        close();
      }
    }
  }

  /**
   * Uses an Opera action to close all open windows.  There is no guarantee that this call will
   * succeed.
   */
  private void closeAllUsingAction() {
    if (utils().getProduct().is(OperaProduct.DESKTOP)) {
      throw new UnsupportedOperationException("Closing pages by Opera action not supported on " +
                                              "product DESKTOP");
    }

    services.getExec().action("Close all pages");
  }

}
@@ -825,69 +825,8 @@
 gs;%0A
-import com.opera.core.systems.scope.internal.OperaIntervals;%0A
 impo
@@ -1017,46 +1017,8 @@
 s;%0A%0A
-import java.util.concurrent.TimeUnit;%0A
 impo
@@ -2137,24 +2137,42 @@
 %7B%0A    return
+ runner != null &&
  runner.isOp

Check for whether we're using a local launcher