package de.otto.jlineup.config;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName;
import de.otto.jlineup.browser.Browser;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;

public final class Config {

    public static final String LINEUP_CONFIG_DEFAULT_PATH = "./lineup.json";

    public static final String EXAMPLE_URL = "https://www.example.com";

    public static final Browser.Type DEFAULT_BROWSER = Browser.Type.PHANTOMJS;
    public static final float DEFAULT_MAX_DIFF = 0;
    public static final int DEFAULT_WINDOW_HEIGHT = 800;
    public static final float DEFAULT_GLOBAL_WAIT_AFTER_PAGE_LOAD = 0f;
    public static final List<Integer> DEFAULT_WINDOW_WIDTHS = ImmutableList.of(800);
    public static final List<String> DEFAULT_PATHS = ImmutableList.of("/");
    public static final int DEFAULT_MAX_SCROLL_HEIGHT = 100000;
    public static final int DEFAULT_WAIT_AFTER_PAGE_LOAD = 0;
    public static final int DEFAULT_WAIT_FOR_NO_ANIMATION_AFTER_SCROLL = 0;
    public static final int DEFAULT_WARMUP_BROWSER_CACHE_TIME = 0;

    public final Map<String, UrlConfig> urls;
    public final Browser.Type browser;
    @SerializedName(value = "wait-after-page-load", alternate = "async-wait")
    public final Float globalWaitAfterPageLoad;
    @SerializedName("window-height")
    public final Integer windowHeight;

    private final static Gson gson = new Gson();

    /* Used by GSON to set default values */
    public Config() {
        urls = null;
        browser = DEFAULT_BROWSER;
        globalWaitAfterPageLoad = DEFAULT_GLOBAL_WAIT_AFTER_PAGE_LOAD;
        windowHeight = DEFAULT_WINDOW_HEIGHT;

    }

    public Config(final Map<String, UrlConfig> urls, final Browser.Type browser, final Float globalWaitAfterPageLoad, final Integer windowHeight) {
        this.urls = urls;
        this.browser = browser != null ? browser : DEFAULT_BROWSER;
        this.globalWaitAfterPageLoad = globalWaitAfterPageLoad != null ? globalWaitAfterPageLoad : DEFAULT_GLOBAL_WAIT_AFTER_PAGE_LOAD;
        this.windowHeight = windowHeight != null ? windowHeight : DEFAULT_WINDOW_HEIGHT;
    }

    public static Config defaultConfig() {
        return defaultConfig(EXAMPLE_URL);
    }

    public static Config defaultConfig(String url) {
        return new Config(ImmutableMap.of(url, new UrlConfig()), null, null, null);
    }

    public static Config exampleConfig() {
        return new Config(ImmutableMap.of("http://www.example.com",
                new UrlConfig(
                        ImmutableList.of("/","someOtherPath"),
                        DEFAULT_MAX_DIFF,
                        ImmutableList.of(
                                new Cookie("exampleCookieName", "exampleValue", "http://www.example.com", "/", new Date(1000L), true)
                        ),
                        ImmutableMap.of("live", "www"),
                        ImmutableMap.of("exampleLocalStorageKey", "value"),
                        ImmutableList.of(600,800,1000),
                        DEFAULT_MAX_SCROLL_HEIGHT,
                        DEFAULT_WAIT_AFTER_PAGE_LOAD,
                        DEFAULT_WAIT_FOR_NO_ANIMATION_AFTER_SCROLL,
                        DEFAULT_WARMUP_BROWSER_CACHE_TIME,
                        "console.log('This is JavaScript!')"
                )),
                Browser.Type.PHANTOMJS,
                DEFAULT_GLOBAL_WAIT_AFTER_PAGE_LOAD,
                DEFAULT_WINDOW_HEIGHT
        );
    }

    public static Config readConfig(final Parameters parameters) throws FileNotFoundException {
        return Config.readConfig(parameters.getWorkingDirectory(), parameters.getConfigFile());
    }

    public static Config readConfig(final String workingDir, final String configFileName) throws FileNotFoundException {

        List<String> searchPaths = new ArrayList<>();
        Path configFilePath = Paths.get(workingDir + "/" + configFileName);
        searchPaths.add(configFilePath.toString());
        if (!Files.exists(configFilePath)) {
            configFilePath = Paths.get(configFileName);
            searchPaths.add(configFilePath.toString());
            if (!Files.exists(configFilePath)) {
                configFilePath = Paths.get(LINEUP_CONFIG_DEFAULT_PATH);
                searchPaths.add(configFilePath.toString());
                if (!Files.exists(configFilePath)) {
                    throw new FileNotFoundException("Config file not found. Search locations were: " + Arrays.toString(searchPaths.toArray()));
                }
            }
        }

        BufferedReader br = new BufferedReader(new FileReader(configFilePath.toString()));
        return gson.fromJson(br, Config.class);

    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Config config = (Config) o;

        if (urls != null ? !urls.equals(config.urls) : config.urls != null) return false;
        if (browser != config.browser) return false;
        if (globalWaitAfterPageLoad != null ? !globalWaitAfterPageLoad.equals(config.globalWaitAfterPageLoad) : config.globalWaitAfterPageLoad != null) return false;
        return windowHeight != null ? windowHeight.equals(config.windowHeight) : config.windowHeight == null;

    }

    @Override
    public int hashCode() {
        int result = urls != null ? urls.hashCode() : 0;
        result = 31 * result + (browser != null ? browser.hashCode() : 0);
        result = 31 * result + (globalWaitAfterPageLoad != null ? globalWaitAfterPageLoad.hashCode() : 0);
        result = 31 * result + (windowHeight != null ? windowHeight.hashCode() : 0);
        return result;
    }

    @Override
    public String toString() {
        return "Config{" +
                "urls=" + urls +
                ", browser=" + browser +
                ", globalWaitAfterPageLoad=" + globalWaitAfterPageLoad +
                ", windowHeight=" + windowHeight +
                '}';
    }
}

@@ -5093,17 +5093,16 @@
  false;%0A
-%0A
         
@@ -5129,25 +5129,24 @@
 fig) o;%0A
-%0A
         
 if (urls
@@ -5141,31 +5141,21 @@
     
-if (urls != null ? !url
+return Object
 s.eq
@@ -5163,22 +5163,13 @@
 als(
-config.
 urls
-) :
+,
  con
@@ -5180,40 +5180,28 @@
 urls
- != null) return false;%0A
+) &&%0A       
         
 if (
@@ -5200,20 +5200,17 @@
     
-if (
+ 
 browser 
 != c
@@ -5205,17 +5205,17 @@
 browser 
-!
+=
 = config
@@ -5226,102 +5226,43 @@
 wser
-) return false;%0A        if (globalWaitAfterPageLoad != null ? !globalWaitAfterPageLoad
+ &&%0A                Objects
 .equals(
 conf
@@ -5257,23 +5257,16 @@
 .equals(
-config.
 globalWa
@@ -5280,19 +5280,17 @@
 PageLoad
-) :
+,
  config.
@@ -5316,90 +5316,44 @@
 Load
- != null) return false;%0A        return windowHeight != null ? windowHeight
+) &&%0A                Objects
 .equals(
 conf
@@ -5348,23 +5348,16 @@
 .equals(
-config.
 windowHe
@@ -5360,19 +5360,17 @@
 owHeight
-) :
+,
  config.
@@ -5385,18 +5385,10 @@
 ight
- == null;%0A
+);
 %0A   
@@ -5445,345 +5445,81 @@
     
-int result = urls != null ? urls.hashCode() : 0;%0A        result = 31 * result + (browser != null ? browser.hashCode() : 0);%0A        result = 31 * result + (globalWaitAfterPageLoad != null ? globalWaitAfterPageLoad.hashCode() : 0);%0A        result = 31 * result + (windowHeight != null ? windowHeight.hashCode() : 0);%0A        return result
+return Objects.hash(urls, browser, globalWaitAfterPageLoad, windowHeight)
 ;%0A  

Fix equals and hashcode