/**
 * The MIT License
 * Copyright © 2017 WebFolder OÜ
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package io.webfolder.cdp;

import static java.lang.Runtime.getRuntime;
import static java.lang.String.format;
import static java.lang.System.getProperty;
import static java.nio.file.Paths.get;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static java.util.Locale.ENGLISH;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

import io.webfolder.cdp.exception.CdpException;
import io.webfolder.cdp.session.SessionFactory;
import io.webfolder.cdp.session.SessionInfo;

public class Launcher {

    private final SessionFactory factory;

    public Launcher() {
        this(new SessionFactory());
    }

    public Launcher(final SessionFactory factory) {
        this.factory = factory;
    }

    public String findChrome() {
        String os = getProperty("os.name")
                        .toLowerCase(ENGLISH);
        boolean windows = os.startsWith("windows");
        if (windows) {
            try {
                // Chrome Canary
                Process pcanary = getRuntime().exec(new String[] {
                        "cmd",
                        "/c",
                        "echo",
                        "%localappdata%\\Google\\Chrome SxS\\Application\\chrome.exe"
                });
                int ecanary = pcanary.waitFor();
                if (ecanary == 0) {
                    String canary = toString(pcanary.getInputStream()).trim().replace("\"", "");
                    File executable = new File(canary);
                    if (executable.exists() && executable.canExecute()) {
                        return executable.toString();
                    }
                }
                // Chrome
                Process pchrome = getRuntime().exec(new String[] {
                        "cmd",
                        "/c",
                        "echo",
                        "%programfiles%\\Google\\Chrome\\Application\\chrome.exe"
                });
                int echrome = pchrome.waitFor();
                if (echrome == 0) {
                    String chrome = toString(pchrome.getInputStream()).trim().replace("\"", "");
                    File executable = new File(chrome);
                    if (executable.exists() && executable.canExecute()) {
                        return executable.toString();
                    }
                }
                return null;
            } catch (Throwable e) {
                // ignore
            }
        } else {
            return "google-chrome";
        }
        return null;
    }

    
    public SessionFactory launch() {
        return launch(new String[] { });
    }

    public SessionFactory launch(String... arguments) {
        if (launched()) {
            return factory;
        }
        String chromePath = findChrome();
        Path remoteProfileData = get(getProperty("java.io.tmpdir"))
                                        .resolve("remote-profile");
        List<String> list = new ArrayList<>();
        list.add(chromePath);
        list.add(format("--remote-debugging-port=%d", factory.getPort()));
        list.add(format("--user-data-dir=%s", remoteProfileData.toString()));
        list.add(format("--remote-debugging-address=%s", factory.getHost()));
        list.add("--disable-translate");
        list.add("--disable-extensions");
        list.add("--disable-plugin-power-saver");
        list.add("--disable-sync");
        list.add("--no-first-run");
        list.add("--safebrowsing-disable-auto-update");
        list.add("--disable-popup-blocking");
        if (arguments != null) {
            list.addAll(asList(arguments));
        }
        try {
            Process process = getRuntime().exec(list.toArray(new String[0]));
            process.getOutputStream().close();
            process.getInputStream().close();
        } catch (IOException e) {
            throw new CdpException(e);
        }
        return factory;
    }

    protected String toString(InputStream is) {
        try (Scanner scanner = new Scanner(is)) {
            scanner.useDelimiter("\\A");
            return scanner.hasNext() ? scanner.next() : "";
        }
    }

    public boolean launched() {
        List<SessionInfo> list = emptyList();
        try {
            list = factory.list();
        } catch (Throwable t) {
            // ignore
        }
        return ! list.isEmpty() ? true : false;
    }
}

@@ -2722,32 +2722,38 @@
  File executable
+Canary
  = new File(cana
@@ -2783,32 +2783,38 @@
   if (executable
+Canary
 .exists() && exe
@@ -2812,32 +2812,38 @@
 () && executable
+Canary
 .canExecute()) %7B
@@ -2876,32 +2876,38 @@
 eturn executable
+Canary
 .toString();%0A   
@@ -3649,35 +3649,802 @@
             
-return null
+// Chrome x86%0A                Process pchrome86 = getRuntime().exec(new String%5B%5D %7B%0A                        %22cmd%22,%0A                        %22/c%22,%0A                        %22echo%22,%0A                        %22%25programfiles(x86)%25%5C%5CGoogle%5C%5CChrome%5C%5CApplication%5C%5Cchrome.exe%22%0A                %7D);%0A                int echrome86 = pchrome86.waitFor();%0A                if (echrome86 == 0) %7B%0A                    String chromex86 = toString(pchrome86.getInputStream()).trim().replace(%22%5C%22%22, %22%22);%0A                    File executable86 = new File(chromex86);%0A                    if (executable86.exists() && executable86.canExecute()) %7B%0A                        return executable86.toString();%0A                    %7D%0A                %7D%0A                throw new CdpException(%22Unable to find chrome.exe%22)
 ;%0A          

throw CdpException if chrome.exe does not exist