/*
 * #%L
 * wcm.io
 * %%
 * Copyright (C) 2017 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.listeners;

import static io.wcm.qa.galenium.reporting.GaleniumReportUtil.getLogger;

import org.openqa.selenium.WebDriver;
import org.testng.ITestContext;
import org.testng.ITestListener;
import org.testng.ITestResult;

import io.wcm.qa.galenium.util.GaleniumContext;
import io.wcm.qa.galenium.util.TestDevice;
import io.wcm.qa.galenium.util.TestInfoUtil;
import io.wcm.qa.galenium.webdriver.WebDriverManager;


public class WebDriverListener implements ITestListener {

  private Boolean isDriverInitialized = false;

  @Override
  public void onFinish(ITestContext context) {
    // if not running multiple tests/method/classes in parallel, then the same WebDriver instance is
    // used for all tests methods, and we have to make sure to close the driver after all tests have finished
    if (!isRunningTestsInSeparateThreads(context)) {
      getLogger().debug("Closing the WebDriver driver that was used for all tests...");
      closeDriver();
    }
  }

  @Override
  public void onStart(ITestContext context) {
    getLogger().trace("WebDriverListener active.");
  }

  @Override
  public void onTestFailedButWithinSuccessPercentage(ITestResult result) {
    closeDriverIfRunningInParallel(result);
  }

  @Override
  public void onTestFailure(ITestResult result) {
    closeDriverIfRunningInParallel(result);
  }

  @Override
  public void onTestSkipped(ITestResult result) {
    closeDriverIfRunningInParallel(result);
  }

  @Override
  public void onTestStart(ITestResult result) {
    TestDevice testDevice = TestInfoUtil.getTestDevice(result);
    if (testDevice != null) {
      WebDriverManager.getDriver(testDevice);
    }
  }

  @Override
  public void onTestSuccess(ITestResult result) {
    closeDriverIfRunningInParallel(result);
  }

  private void closeDriverIfRunningInParallel(ITestResult result) {
    ITestContext testContext = result.getTestContext();
    if (getDriver() == null) {
      getLogger().debug("No WebDriver to close for thread " + Thread.currentThread().getName());
    }
    else if (isRunningTestsInSeparateThreads(testContext)) {
      getLogger().info("Closing WebDriver for thread " + Thread.currentThread().getName() + " on host '" + testContext.getSuite().getHost() + "'");
      closeDriver();
    }
    else {
      getLogger().debug("Reusing WebDriver for thread " + Thread.currentThread().getName());
    }
  }

  /**
   * @param context of the current test case
   * @return true if any of the parallel execution modes is used
   */
  private boolean isRunningTestsInSeparateThreads(ITestContext context) {

    // getParallel() will return "methods", "classes", "tests" or "false" (which is the default)
    return !"false".equals(context.getSuite().getParallel());
  }

  protected void closeDriver() {
    WebDriverManager.closeDriver();
    isDriverInitialized = false;
  }

  protected WebDriver getDriver() {
    if (isDriverInitialized) {
      return GaleniumContext.getDriver();
    }
    else if (GaleniumContext.getTestDevice() != null) {
      isDriverInitialized = true;
      return WebDriverManager.getDriver(GaleniumContext.getTestDevice());
    }
    // no driver and no test device
    return null;
  }

}

@@ -660,16 +660,92 @@
 eners;%0A%0A
+import static io.wcm.qa.galenium.reporting.GaleniumReportUtil.MARKER_ERROR;%0A
 import s
@@ -813,47 +813,73 @@
 er;%0A
-%0A
 import 
-org.openqa.selenium.Web
+static io.wcm.qa.galenium.util.GaleniumContext.get
 Driver;%0A
 impo
@@ -870,24 +870,25 @@
 .getDriver;%0A
+%0A
 import org.t
@@ -976,56 +976,8 @@
 t;%0A%0A
-import io.wcm.qa.galenium.util.GaleniumContext;%0A
 impo
@@ -1179,56 +1179,8 @@
  %7B%0A%0A
-  private Boolean isDriverInitialized = false;%0A%0A
   @O
@@ -2255,45 +2255,304 @@
     
-WebDriverManager.getDriver(testDevice
+getLogger().debug(%22new driver for: %22 + testDevice);%0A      WebDriverManager.getDriver(testDevice);%0A      if (getDriver() == null) %7B%0A        getLogger().warn(MARKER_ERROR, %22driver not instantiated%22);%0A      %7D%0A    %7D%0A    else %7B%0A      getLogger().debug(%22no test device set for: %22 + result.getTestName()
 );%0A 
@@ -3715,384 +3715,8 @@
 ();%0A
-    isDriverInitialized = false;%0A  %7D%0A%0A  protected WebDriver getDriver() %7B%0A    if (isDriverInitialized) %7B%0A      return GaleniumContext.getDriver();%0A    %7D%0A    else if (GaleniumContext.getTestDevice() != null) %7B%0A      isDriverInitialized = true;%0A      return WebDriverManager.getDriver(GaleniumContext.getTestDevice());%0A    %7D%0A    // no driver and no test device%0A    return null;%0A
   %7D%0A

simplify driver handling, more log output