package com.aldebaran.qimessaging;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Map;

/**
 * Tool class providing QiMessaging<->Java type system loading and
 * dynamic library loader designed to load libraries included in jar package.
 * @author proullon
 *
 */
public class EmbeddedTools
{

  public static boolean LOADED_EMBEDDED_LIBRARY = false;
  private static native void initTypeSystem(java.lang.Object str, java.lang.Object i, java.lang.Object f, java.lang.Object d, java.lang.Object l, java.lang.Object m, java.lang.Object al, java.lang.Object t, java.lang.Object o, java.lang.Object b);
  private static native void initTupleInTypeSystem(java.lang.Object t1, java.lang.Object t2, java.lang.Object t3, java.lang.Object t4, java.lang.Object t5, java.lang.Object t6, java.lang.Object t7, java.lang.Object t8);

  public static String  getSuitableLibraryExtention()
  {
    String[] ext = new String[] {".so", ".dylib", ".dll"};
    String osName = System.getProperty("os.name");

    if (osName == "Windows")
      return ext[2];
    if (osName == "Mac")
      return ext[1];

    return ext[0];
  }

  /**
   * To work correctly, QiMessaging<->java type system needs to compare type class template.
   * Unfortunately, call template cannot be retrieve on native android thread.
   * The only available way to do is to store instance of wanted object
   * and get fresh class template from it right before using it.
   */
  private boolean initTypeSystem()
  {
    String  str = new String();
    Integer i   = new Integer(0);
    Float   f   = new Float(0);
    Double  d   = new Double(0);
    Long    l   = new Long(0);
    Tuple   t   = new Tuple1<java.lang.Object>();
    Boolean b   = new Boolean(true);

    GenericObjectBuilder ob = new GenericObjectBuilder();
    Object obj  = ob.object();

    Map<java.lang.Object, java.lang.Object> m  = new Hashtable<java.lang.Object, java.lang.Object>();
    ArrayList<java.lang.Object>             al = new ArrayList<java.lang.Object>();

    // Initialize generic type system
    EmbeddedTools.initTypeSystem(str, i, f, d, l, m, al, t, obj, b);

    Tuple t1 = Tuple.makeTuple(0);
    Tuple t2 = Tuple.makeTuple(0, 0);
    Tuple t3 = Tuple.makeTuple(0, 0, 0);
    Tuple t4 = Tuple.makeTuple(0, 0, 0, 0);
    Tuple t5 = Tuple.makeTuple(0, 0, 0, 0, 0);
    Tuple t6 = Tuple.makeTuple(0, 0, 0, 0, 0, 0);
    Tuple t7 = Tuple.makeTuple(0, 0, 0, 0, 0, 0, 0);
    Tuple t8 = Tuple.makeTuple(0, 0, 0, 0, 0, 0, 0, 0);
    // Initialize tuple
    EmbeddedTools.initTupleInTypeSystem(t1, t2, t3, t4, t5, t6, t7, t8);
    return true;
  }

  /**
   * Native C++ librairies are package with java sources.
   * This way, we are able to load them anywhere, anytime.
   */
  public boolean loadEmbeddedLibraries()
  {
    if (LOADED_EMBEDDED_LIBRARY == true)
    {
      System.out.print("Native libraries already loaded");
      return true;
    }

    /*
     * Since we use multiple shared libraries,
     * we need to use libstlport_shared to avoid multiple STL declarations
     */
    loadEmbeddedLibrary("libgnustl_shared");

    if (loadEmbeddedLibrary("libqi") == false ||
        loadEmbeddedLibrary("libqitype") == false ||
        loadEmbeddedLibrary("libqimessaging") == false ||
        loadEmbeddedLibrary("libqimessagingjni") == false)
    {
      LOADED_EMBEDDED_LIBRARY = false;
      return false;
    }

    LOADED_EMBEDDED_LIBRARY = true;
    if (initTypeSystem() == false)
    {
      LOADED_EMBEDDED_LIBRARY = false;
      return false;
    }

    return true;
  }

  public boolean loadEmbeddedLibrary(String libname)
  {
    boolean usingEmbedded = false;

    // Locate native library within qimessaging.jar
    StringBuilder path = new StringBuilder();
    path.append("/" + libname+getSuitableLibraryExtention());

    // Search native library for host system
    URL nativeLibrary = null;
    if ((nativeLibrary = EmbeddedTools.class.getResource(path.toString())) == null)
    {
      try
      {
        System.loadLibrary(libname);
      }
      catch (UnsatisfiedLinkError e)
      {
        if (libname != "libgnustl_shared") // Disable warning to avoid false positive.
          System.out.printf("[WARN ] Unsatified link error : %s\n", e.getMessage());
        return false;
      }
      return true;
    }

    // Extract and load native library
    try
    {
      final File libfile = File.createTempFile(libname, getSuitableLibraryExtention());
      libfile.deleteOnExit();

      final InputStream in = nativeLibrary.openStream();
      final OutputStream out = new BufferedOutputStream(new FileOutputStream(libfile));

      int len = 0;
      byte[] buffer = new byte[10000];
      while ((len = in.read(buffer)) > -1)
      {
        out.write(buffer, 0, len);
      }

      out.close();
      in.close();

      int actualPathLength = libfile.getAbsolutePath().length();
      int actualNameLength = libfile.getName().length();
      int endIndex = actualPathLength - actualNameLength;

      // Rename tmp file to actual library name
      String pathToTmp = libfile.getAbsolutePath().substring(0, endIndex);
      File so = new File(pathToTmp + "/" + libname + getSuitableLibraryExtention());

      libfile.renameTo(so);
      System.load(so.getAbsolutePath());

      usingEmbedded = true;
    }
    catch (IOException x)
    {
      usingEmbedded = false;
    }

    return usingEmbedded;
  }
}

@@ -511,16 +511,47 @@
 ools%0A%7B%0A%0A
+  private File tmpDir = null;%0A%0A
   public
@@ -599,16 +599,16 @@
  false;%0A
-
   privat
@@ -2832,24 +2832,181 @@
  true;%0A  %7D%0A%0A
+  /**%0A   * Override directory where native libraries are extracted.%0A   */%0A  public void overrideTempDirectory(File newValue)%0A  %7B%0A    tmpDir = newValue;%0A  %7D%0A%0A
   /**%0A   * N
@@ -4831,16 +4831,24 @@
 ention()
+, tmpDir
 );%0A     
@@ -5514,16 +5514,16 @@
 Index);%0A
-
       Fi
@@ -5594,24 +5594,129 @@
 xtention());
+%0A      System.out.printf(%22Extracting %25s in %25s...%5Cn%22, libname + getSuitableLibraryExtention(), pathToTmp);
 %0A%0A      libf

Add method to override directory where native libraries are extracted