package com.bootstrapium.tests.internal;

import static com.bootstrapium.config.DriverType.determineEffectiveDriverType;
import io.appium.java_client.AppiumDriver;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.openqa.selenium.remote.SessionId;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.AfterSuite;
import org.testng.annotations.BeforeSuite;
import org.testng.annotations.Listeners;

import com.bootstrapium.config.DriverType;
import com.bootstrapium.config.EFWebDriver;
import com.bootstrapium.listeners.MethodInterceptor;
import com.bootstrapium.listeners.SauceLabsListener;
import com.bootstrapium.listeners.ScreenshotListener;
import com.bootstrapium.listeners.TestListener;
import com.bootstrapium.reporting.AllureProperties;
import com.saucelabs.common.SauceOnDemandAuthentication;
import com.saucelabs.common.SauceOnDemandSessionIdProvider;
import com.saucelabs.testng.SauceOnDemandAuthenticationProvider;

@Listeners({ ScreenshotListener.class, MethodInterceptor.class,
        SauceLabsListener.class, TestListener.class })
public abstract class BaseTest implements SauceOnDemandSessionIdProvider,
        SauceOnDemandAuthenticationProvider {

    private static List<WebDriver> webDriverPool = Collections
            .synchronizedList(new ArrayList<WebDriver>());
    private static ThreadLocal<WebDriver> driverThread;

    private static DriverType desiredDriver = determineEffectiveDriverType();

    @BeforeSuite(alwaysRun = true)
    public static void instantiateNonNativeDriverObject() {
        driverThread = new ThreadLocal<WebDriver>() {
            @Override
            protected WebDriver initialValue() {
                final WebDriver webDriver = desiredDriver.instantiate();
                webDriverPool.add(webDriver);
                return webDriver;
            }
        };
    }

    public static WebDriver getDriver() {
        return driverThread.get();
    }

    @AfterMethod(alwaysRun = true)
    public static void clearSession() {
        if (DriverType.isNative()) {
            ((AppiumDriver) ((EFWebDriver) getDriver()).getWrappedDriver())
                    .resetApp();
        } else {
            getDriver().manage().deleteAllCookies();
        }
    }

    @AfterSuite(alwaysRun = true)
    public static void closeDriverObject() {
        for (WebDriver driver : webDriverPool) {
            driver.quit();
        }
    }

    @AfterSuite(alwaysRun = true)
    public static void createAllureProperties() {
        AllureProperties.create();
    }

    /**
     *
     * @return the Sauce Job id for the current thread
     */
    @Override
    public String getSessionId() {
        SessionId sessionId = ((RemoteWebDriver) ((EFWebDriver) getDriver())
                .getWrappedDriver()).getSessionId();
        return (sessionId == null) ? null : sessionId.toString();
    }

    /**
     *
     * @return the {@link SauceOnDemandAuthentication} instance containing the
     *         Sauce username/access key
     */
    @Override
    public SauceOnDemandAuthentication getAuthentication() {
        return new SauceOnDemandAuthentication();
    }
}
@@ -240,16 +240,100 @@
 .List;%0A%0A
+import org.apache.logging.log4j.LogManager;%0Aimport org.apache.logging.log4j.Logger;%0A
 import o
@@ -458,16 +458,76 @@
 sionId;%0A
+import org.openqa.selenium.remote.SessionNotFoundException;%0A
 import o
@@ -553,22 +553,21 @@
 ns.After
-Method
+Suite
 ;%0Aimport
@@ -586,34 +586,36 @@
 annotations.
-AfterSuite
+BeforeMethod
 ;%0Aimport org
@@ -1717,16 +1717,148 @@
 ype();%0A%0A
+    protected static final Logger logger = LogManager.getLogger();%0A    %0A    private static ThreadLocal%3CBoolean%3E requiresReset;%0A    %0A
     @Bef
@@ -1922,17 +1922,8 @@
 iate
-NonNative
 Driv
@@ -2223,24 +2223,210 @@
           %7D%0A
+        %7D;%0A        requiresReset = new ThreadLocal%3CBoolean%3E() %7B%0A            @Override%0A            protected Boolean initialValue() %7B%0A                return Boolean.FALSE;%0A            %7D%0A%0A
         %7D;%0A 
@@ -2520,21 +2520,22 @@
 %7D%0A%0A    @
-After
+Before
 Method(a
@@ -2583,32 +2583,84 @@
 learSession() %7B%0A
+        if(requiresReset.get()) %7B%0A        try %7B%0A    
         if (Driv
@@ -2676,24 +2676,28 @@
 Native()) %7B%0A
+    
             
@@ -2780,16 +2780,20 @@
         
+    
 .resetAp
@@ -2805,16 +2805,20 @@
         
+  
+  
 %7D else %7B
@@ -2818,16 +2818,20 @@
  else %7B%0A
+    
         
@@ -2871,24 +2871,213 @@
 lCookies();%0A
+            %7D%0A        %7D catch (SessionNotFoundException e) %7B%0A            logger.error(%22Session quit unexpectedly.%22);%0A        %7D%0A        %7D else %7B%0A            requiresReset.set(Boolean.TRUE);%0A
         %7D%0A  
@@ -3225,22 +3225,154 @@
     
-driver.quit();
+try %7B%0A                driver.quit();%0A            %7D catch (Exception e) %7B%0A                logger.error(%22Session quit unexpectedly.%22);%0A            %7D
 %0A   

Reset app / clear cookies only when necessary