/*
 * $Id$
 * @author aakimov
 * @date   Jun 16, 2016 7:03:27 PM
 *
 * Copyright (C) 2016 Scytl Secure Electronic Voting SA
 *
 * All rights reserved.
 */
package com.scytl.math.jni;

import java.text.MessageFormat;

import javax.annotation.concurrent.ThreadSafe;

/**
 * Utility class which loads the JNI library.
 * <p>
 * The loading process has the following features:
 * <ul>
 * <li>The library is loaded once during static initialization.</li>
 * <li>The library is loaded by it's "generic" name {@code scytl-math} as
 * described in the contract of {@link System#loadLibrary(String)}.</li>
 * <li>Possible {@link UnsatisfiedLinkedError} is not reported as a fatal
 * problem, it means that the library is not available.</li>
 * <li>System property {@code -Dcom.scytl.math.jni.debug=true} allows to trace
 * how the library is loaded in the {@link System#err}</li>
 * </ul>
 * <p>
 * The methods of this class are not a part of public API of the library,
 * clients should not use them directly.
 * 
 * @author aakimov
 */
@ThreadSafe
public final class JNI {
    private static final String DEBUG_PROPERTY = "com.scytl.math.jni.debug";
    private static final String LIBRARY_NAME = "scytl-math";
    private static final boolean AVAILABLE;

    static {
        boolean loaded;
        boolean debug = Boolean
                .parseBoolean(System.getProperty(DEBUG_PROPERTY));
        String mappedLibraryName = System.mapLibraryName(LIBRARY_NAME);
        try {
            if (debug) {
                System.err.println(MessageFormat.format(
                        "Loading JNI library ''{0}'' ({1})...", LIBRARY_NAME,
                        mappedLibraryName));
            }
            System.loadLibrary(LIBRARY_NAME);
            loaded = true;
            if (debug) {
                System.err.println(MessageFormat.format(
                        "JNI library ''{0}'' ({1}) has been loaded.",
                        LIBRARY_NAME, mappedLibraryName));
            }
        } catch (UnsatisfiedLinkError e) {
            loaded = false;
            if (debug) {
                System.err.println(MessageFormat.format(
                        "Failed to load JNI library ''{0}'' ({1}).",
                        LIBRARY_NAME, mappedLibraryName));
                e.printStackTrace();
            }
        }
        AVAILABLE = loaded;
    }

    private JNI() {
    }

    /**
     * Returns whether the JNI is available.
     * 
     * @return the JNI is available.
     */
    public static boolean isAvailable() {
        return AVAILABLE;
    }
}
