package com.codeborne.selenide.webdriver;

import org.openqa.selenium.Proxy;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;

import static com.codeborne.selenide.Configuration.*;
import static com.codeborne.selenide.WebDriverRunner.CHROME;

class ChromeDriverFactory extends AbstractDriverFactory {

  private static final Logger log = Logger.getLogger(ChromeDriverFactory.class.getName());

  WebDriver create(final Proxy proxy) {
    ChromeOptions options = createChromeOptions(proxy);
    return new ChromeDriver(options);
  }

  @Override
  boolean supports() {
    return CHROME.equalsIgnoreCase(browser);
  }

  ChromeOptions createChromeOptions(Proxy proxy) {
    ChromeOptions options = new ChromeOptions();
    options.setHeadless(headless);
    if (!browserBinary.isEmpty()) {
      options.setBinary(browserBinary);
    }
    options.addArguments("--no-sandbox");  // This make Chromium reachable (?)
    if (chromeSwitches != null) {
      options.addArguments(chromeSwitches);
    }
    options.merge(createCommonCapabilities(proxy));
    options = transferChromeOptionsFromSystemProperties(options);
    log.config("Chrome options:" + options.toString());
    return options;
  }


  /**
   * This method only handles so-called "arguments" and "preferences" for ChromeOptions (there is also "Extensions" etc.)
   *
   * @param currentChromeOptions
   * @return
   */
  private ChromeOptions transferChromeOptionsFromSystemProperties(ChromeOptions currentChromeOptions) {
    String prefix = "chromeoptions.";
    for (String key : System.getProperties().stringPropertyNames()) {
      if (key.startsWith(prefix)) {
        String capability = key.substring(prefix.length());
        String value = System.getProperties().getProperty(key);
        switch (capability) {
          case "args": {
            List<String> args = Arrays.asList(value.split(","));
            currentChromeOptions.addArguments(args);
            break;
          }
          case "prefs": {
            Map<String, Object> prefs = new HashMap<>();
            Arrays.asList(value.split(","))
                    .forEach(expOpt -> {
                              String[] keyValue = expOpt.split("=");
                              prefs.put(keyValue[0], keyValue[1]);
                    });
            currentChromeOptions.setExperimentalOption("prefs", prefs);
            break;
          }
          default:
            log.warning(capability + "is ignored." +
                    "Only so-called arguments (chromeoptions.args=<values comma separated>) " +
                    "and preferences (chromeoptions.prefs=<comma-separated dictionary of key=value> " +
                    "are supported for the chromeoptions at the moment");
            break;
        }
      }
    }
    return currentChromeOptions;
  }
}

@@ -1482,16 +1482,21 @@
 erences%22
+%0A   *
  for Chr
@@ -1540,16 +1540,16 @@
 %22 etc.)%0A
-
    *%0A   
@@ -2272,35 +2272,134 @@
     
-Arrays.asList(value
+String%5B%5D allPrefs = value.split(%22,%22);%0A            for (String pref: allPrefs) %7B%0A              String%5B%5D keyValue = pref
 .split(%22
 ,%22))
@@ -2394,20 +2394,20 @@
 .split(%22
-,%22))
+=%22);
 %0A       
@@ -2417,120 +2417,506 @@
     
-      .forEach(expOpt -%3E %7B%0A                              String%5B%5D keyValue = expOpt.split(%22=%22);%0A                
+if (keyValue.length == 1)%7B%0A                log.warning(%22Missing '=' sign while parsing %3Ckey=value%3E pairs from %22%0A                        + capability + %22. Key '%22 + keyValue%5B0%5D + %22' is ignored.%22);%0A                continue;%0A              %7D%0A              else if (keyValue.length %3E 2)%7B%0A                log.warning(%22More than one '=' sign while parsing %3Ckey=value%3E pairs from %22%0A                        + capability + %22. Key '%22 + keyValue%5B0%5D + %22' is ignored.%22);%0A                continue;%0A              %7D%0A
     
@@ -2948,16 +2948,28 @@
 lue%5B0%5D, 
+parseString(
 keyValue
@@ -2972,16 +2972,17 @@
 alue%5B1%5D)
+)
 ;%0A      
@@ -2991,19 +2991,9 @@
     
-        %7D);
+%7D
 %0A   
@@ -3149,16 +3149,17 @@
 lity + %22
+ 
 is ignor
@@ -3478,24 +3478,24 @@
     %7D%0A    %7D%0A
-
     return c
@@ -3518,11 +3518,296 @@
 ons;%0A  %7D
+%0A%0A  private Object parseString(String value) %7B%0A    if (value.equals(%22true%22))%7B%0A%0A      return true;%0A    %7D%0A    if (value.equals(%22false%22))%7B%0A%0A      return false;%0A    %7D%0A    try %7B%0A%0A      return Integer.parseInt(value);%0A    %7D%0A    catch (NumberFormatException e)%7B%0A%0A      return value;%0A    %7D%0A  %7D
 %0A%7D%0A

add parser from string to boolean, int, string