/**
  * Checks if the given osId matches {@link OsDetector#detectOs()} and then calls {@link
  * #loadLibrary(String)}.
  *
  * @param libName The case-insensitive name of the library without os-dependent prefixes/suffixes!
  * @param osId The OS for which this library should be loaded.
  * @return Whether the given osId matched and the library was (trying to be) loaded or not.
  * @throws LoaderException
  */
 public boolean loadLibrary(final String libName, final OsIdentifier osId) throws LoaderException {
   if (osId == OsDetector.detectOs()) {
     loadLibrary(libName);
     return true;
   }
   return false;
 }
  /**
   * @param basePath
   * @param folderMap
   * @param applyLibraryPathHack
   */
  public NativesLoader(
      String basePath, Map<OsIdentifier, String> folderMap, boolean applyLibraryPathHack) {
    super();
    setBasePath(basePath);

    // Check for leading/trailing delimiters
    for (final Entry<OsIdentifier, String> entry : folderMap.entrySet()) {
      String folder = entry.getValue();

      if (!folder.startsWith("\\") && !folder.startsWith("/")) {
        // Add leading delimiter
        folder = DELIMITER + folder;
      }

      if (folder.endsWith("\\")) {
        // Cut trailing delimiter
        folder = folder.substring(0, folder.length() - 2);
      } else if (folder.endsWith("/")) {
        // Cut trailing delimiter
        folder = folder.substring(0, folder.length() - 1);
      }

      this.folderMap.put(entry.getKey(), folder);
    }

    // Eventually apply library path hack
    if (applyLibraryPathHack) {
      // Add all paths in the folder map to the library path
      StringBuffer newPath = new StringBuffer();
      newPath.append(System.getProperty(JAVA_LIBRARY_PATH_KEY));
      for (final Entry<OsIdentifier, String> entry : this.folderMap.entrySet()) {
        if (entry.getKey().equals(OsDetector.detectOs())) {
          newPath.append(";");
          newPath.append(this.basePath);
          newPath.append(entry.getValue());
        }
      }
      System.setProperty(JAVA_LIBRARY_PATH_KEY, newPath.toString());
      //
      // // Apply actual hack: Asure that the new properties are used by setting the erroneously
      // buffered 'sys_paths'
      // to
      // // 'null'.
      try {
        final Field fieldSysPath = ClassLoader.class.getDeclaredField("sys_paths");
        fieldSysPath.setAccessible(true);
        fieldSysPath.set(null, null);
        fieldSysPath.setAccessible(false);
      } catch (final NoSuchFieldException err) {
        log.fatal("Unable to perform library-path hack!", err);
      } catch (final IllegalAccessException err) {
        log.fatal("Unable to perform library-path hack!", err);
      } catch (final SecurityException err) {
        log.fatal("Unable to perform library-path hack!", err);
      } catch (final IllegalArgumentException err) {
        log.fatal("Unable to perform library-path hack!", err);
      }
      //
      // } catch (NoSuchFieldException | SecurityException | IllegalArgumentException |
      // IllegalAccessException err)
      // {
      // log.fatal("Unable to perform library-path hack!", err);
      // }
    }
  }
  /**
   * Uses {@link System#load(String)}
   *
   * @param libName The case-insensitive name of the library without os-dependent prefixes/suffixes!
   * @throws LoaderException
   */
  public void loadLibrary(final String libName) throws LoaderException {
    final OsIdentifier os = OsDetector.detectOs();
    final String folder = folderMap.get(os);

    // Check for present entry
    if (folder == null) {
      throw new LoaderException("No folder stored for OsIdentifier " + os + "!");
    }

    // Combine base path and subfolder
    final String absolutePath = basePath + folder;
    final File subFolder = new File(absolutePath);

    // Check for existence
    if (!subFolder.exists()) {
      throw new LoaderException(
          "Path '" + absolutePath + "' stored for OsIdentifier '" + os + "' does not exist!");
    }

    // Load! =)
    final String fullPath = absolutePath + DELIMITER + libName;
    final File fullFile = new File(fullPath);

    if (!fullFile.exists()) {
      // Filter for libName (while omitting os-dependent extensions)
      final File[] files =
          subFolder.listFiles(
              new FilenameFilter() {
                @Override
                public boolean accept(File file, String filename) {
                  String name = filename;
                  // Omit os-dependent suffixes
                  final String[] nameParts = name.split("\\.(?=[^\\.]+$)");
                  if ((nameParts.length < 1) || nameParts[0].isEmpty()) {
                    return false;
                  }

                  name = nameParts[0];

                  // Omit lib prefix
                  if (name.startsWith("lib") && (name.length() > 3)) {
                    name = name.substring(3);
                  }

                  if (name.endsWith("64")) {
                    name = name.substring(0, name.length() - 2);
                  }
                  return name.toLowerCase().equals(libName.toLowerCase());
                }
              });

      // If libName is unique, exactlly one file should have passed the filter
      if (files.length == 1) {
        System.load(files[0].getAbsolutePath());
      } else {
        throw new LoaderException(
            "The given lib-name '"
                + libName
                + "' seems to be non-unique in the folder '"
                + folder
                + "' for the OsIdentifier '"
                + os
                + "'.");
      }
    } else {
      // Very unlikely, as libraries normally have extensions which are typical for their
      // architecure/os
      System.load(fullPath);
    }
  }