/*
 * Copyright (C) 2011 Wayne Meissner
 *
 * This file is part of the JNR project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package jnr.ffi;

/**
 * Provides a mapping between java objects and unique native addresses.
 *
 * <p>
 * The native addresses generated by this class do not relate to the object's true native address
 * (since that is not supported by most java virtual machines), but is guaranteed to be unique within
 * an ObjectReferenceManager instance.
 * <p>
 *     This would be commonly used to create a unique native pointer that can be used to retrieve an object
 *     from within a callback.
 *     e.g.
 *     <pre>
 *       <code>
 *
 *       public interface MyLib {
 *         public static interface MyCallback {
 *           {@literal @}Delegate public void call(Pointer value);
 *         }
 *
 *         public void do_something_with_callback(MyCallback cb, Pointer cb_argument);
 *       }
 *
 *       MyLib lib = LibraryLoader.create(MyLib.class).load("mylib");
 *       final ObjectReferenceManager referenceManager = Runtime.getRuntime(lib).newObjectReferenceManager();
 *
 *       MyCallback cb = new MyCallback {
 *         public void call(Pointer cb_argument) {
 *           Object javaCallbackArgument = referenceManager.get(cb_argument);
 *           System.out.println("java callback parameter=" + javaCallbackArgument);
 *         }
 *       }
 *
 *       String callbackArgument = "Hello, World";
 *       Pointer cb_argument = referenceManager.add(callback);
 *       lib.do_something_with_callback(cb, cb_argument);
 *       referenceManager.remove(cb_argument);
 *
 *       </code>
 *     </pre>
 *
 * <b>Note</b>
 * <p>
 * Each call to {@link #add(Object)} will return a unique native address, even for the same object, so each call to
 * {@link #add(Object)} must be matched with a call to {@link #remove(Pointer)}.
 */
public abstract class ObjectReferenceManager<T> {

    public static <T> ObjectReferenceManager<T> newInstance(Runtime runtime) {
        return runtime.newObjectReferenceManager();
    }

    /**
     * Adds a mapping from a java object to a unique native address.
     *
     * Each call to this method is guaranteed to produce a memory address unique within the ObjectReferenceManager
     * instance, even for the same object.
     *
     * <p>
     * A strong reference to {@code object} is maintained internally, until {@link #remove(Pointer)} is called.
     * </p>
     *
     * @param object The java object to generate a reference for
     * @return A pointer representing the unique id.
     * @deprecated use {@link #add(Object)}
     */
    @Deprecated
    public Pointer newReference(T object) {
        return add(object);
    }

    /**
     * Removes a mapping from java object to native pointer.
     *
     * @param reference a native memory pointer.
     * @deprecated use {@link #remove(Pointer)}
     */
    @Deprecated
    public void freeReference(Pointer reference) {
        remove(reference);
    }

    /**
     * Gets the java object that is mapped to the native memory address referred to by {@code reference}.
     *
     * @param reference a native memory pointer.
     * @return The java object corresponding to {@code pointer}.
     * @deprecated use {@link #get(Pointer)}
     */
    @Deprecated
    public T getObject(Pointer reference) {
        return get(reference);
    }

    /**
     * Adds a mapping from a java object to a unique native address.
     *
     * Each call to this method is guaranteed to produce a memory address unique within the ObjectReferenceManager
     * instance, even for the same object.
     *
     * <p>
     * A strong reference to {@code object} is maintained internally, until {@link #remove(Pointer)} is called.
     * </p>
     *
     * @param object The java object to generate a reference for
     * @return A pointer representing the unique id.
     */
    public abstract Pointer add(T object);

    /**
     * Removes a mapping from java object to native pointer.
     *
     * @param reference a native memory pointer.
     * @return true if the mapping was removed.
     */
    public abstract boolean remove(Pointer reference);

    /**
     * Gets the java object that is mapped to the native memory address referred to by {@code reference}.
     *
     * @param reference a native memory pointer.
     * @return The java object corresponding to {@code pointer}.
     */
    public abstract T get(Pointer reference);
}
