package com.pty4j.util;

import com.google.common.base.Function;
import com.google.common.collect.Lists;
import com.pty4j.windows.WinPty;
import com.sun.jna.Platform;

import java.io.File;
import java.net.URI;
import java.security.CodeSource;
import java.util.List;
import java.util.Map;

/**
 * @author traff
 */
public class PtyUtil {
  public static final String OS_VERSION = System.getProperty("os.version").toLowerCase();

  private final static String PTY_LIB_FOLDER = System.getenv("PTY_LIB_FOLDER");

  public static String[] toStringArray(Map<String, String> environment) {
    if (environment == null) return new String[0];
    List<String> list = Lists.transform(Lists.newArrayList(environment.entrySet()), new Function<Map.Entry<String, String>, String>() {
      public String apply(Map.Entry<String, String> entry) {
        return entry.getKey() + "=" + entry.getValue();
      }
    });
    return list.toArray(new String[list.size()]);
  }

  /**
   * Returns the folder that contains a jar that contains the class
   *
   * @param aclass a class to find a jar
   * @return
   */
  public static String getJarContainingFolderPath(Class aclass) throws Exception {
    CodeSource codeSource = aclass.getProtectionDomain().getCodeSource();

    File jarFile;

    if (codeSource.getLocation() != null) {
      jarFile = new File(codeSource.getLocation().toURI());
    } else {
      String path = aclass.getResource(aclass.getSimpleName() + ".class").getPath();

      int startIndex = path.indexOf(":") + 1;
      int endIndex = path.indexOf("!");
      if (startIndex == -1 || endIndex == -1) {
        throw new IllegalStateException("Class " + aclass.getSimpleName() + " is located not within a jar: " + path);
      }
      String jarFilePath = path.substring(startIndex, endIndex);
      jarFilePath = new URI(jarFilePath).getPath();
      jarFile = new File(jarFilePath);
    }
    return jarFile.getParentFile().getAbsolutePath();
  }

  public static String getPtyLibFolderPath() throws Exception {
    if (PTY_LIB_FOLDER != null) {
      return PTY_LIB_FOLDER;
    }
    //Class aclass = WinPty.class.getClassLoader().loadClass("com.jediterm.pty.PtyMain");
    Class aclass = WinPty.class;

    return getJarContainingFolderPath(aclass);
  }

  public static File resolveNativeLibrary() throws Exception {
    String libFolderPath = getPtyLibFolderPath();

    if (libFolderPath != null) {

      File libFolder = new File(libFolderPath);
      File lib = resolveNativeLibrary(libFolder);

      lib = lib.exists() ? lib : resolveNativeLibrary(new File(libFolder, "libpty"));

      if (!lib.exists()) {
        throw new IllegalStateException(String.format("Couldn't find %s, jar folder %s", lib.getName(),
                libFolder.getAbsolutePath()));
      }

      return lib;
    } else {
      throw new IllegalStateException("Couldn't detect lib folder");
    }
  }

  public static File resolveNativeLibrary(File parent) {
    return resolveNativeFile(parent, getNativeLibraryName());
  }

  public static File resolveNativeFile(String fileName) throws Exception {
    File libFolder = new File(getPtyLibFolderPath());
    File file = resolveNativeFile(libFolder, fileName);
    return file.exists() ? file : resolveNativeFile(new File(libFolder, "libpty"), fileName);
  }

  public static File resolveNativeFile(File parent, String fileName) {
    File path = new File(parent, getPlatformFolder());

    path = isWinXp() ? new File(path, "xp") :
            (Platform.is64Bit() ? new File(path, "x86_64") :
                    new File(path, "x86"));

    return new File(path, fileName);
  }

  private static String getPlatformFolder() {
    String result;

    if (Platform.isMac()) {
      result = "macosx";
    } else if (Platform.isWindows()) {
      result = "win";
    } else if (Platform.isLinux()) {
      result = "linux";
    } else {
      throw new IllegalStateException("Platform " + Platform.getOSType() + " is not supported");
    }

    return result;
  }

  private static String getNativeLibraryName() {
    String result;

    if (Platform.isMac()) {
      result = "libpty.dylib";
    } else if (Platform.isWindows()) {
      result = "libwinpty.dll";
    } else if (Platform.isLinux()) {
      result = "libpty.so";
    } else {
      throw new IllegalStateException("Platform " + Platform.getOSType() + " is not supported");
    }

    return result;
  }

  public static boolean isWinXp() {
    return Platform.isWindows() && (OS_VERSION.equals("5.1") || OS_VERSION.equals("5.2"));
  }
}

@@ -3371,24 +3371,30 @@
 Name) %7B%0A    
+final 
 File path = 
@@ -3437,20 +3437,29 @@
 );%0A%0A    
-path
+String prefix
  = isWin
@@ -3468,43 +3468,15 @@
 () ?
- new File(path,
  %22xp%22
-)
  :
-%0A           
  (Pl
@@ -3498,104 +3498,124 @@
 ) ? 
-new File(path, %22x86_64%22) :%0A                    new File(path, %22x86%22));%0A%0A    return new File(path
+%22x86_64%22: %22x86%22);%0A%0A    if (isWin10()) %7B%0A        prefix = %22win10_%22;%0A    %7D%0A%0A    return new File(new File(path, prefix)
 , fi
@@ -4545,11 +4545,116 @@
 %22));%0A  %7D
+%0A%0A  public static boolean isWin10() %7B%0A    return Platform.isWindows() && (OS_VERSION.equals(%2210.0%22));%0A  %7D
 %0A%7D%0A

Handle win10 prefix