/*
 * NativeTreeLikelihood.java
 *
 * Copyright (C) 2002-2006 Alexei Drummond and Andrew Rambaut
 *
 * This file is part of BEAST.
 * See the NOTICE file distributed with this work for additional
 * information regarding copyright ownership and licensing.
 *
 * BEAST is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 *  BEAST is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with BEAST; if not, write to the
 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
 * Boston, MA  02110-1301  USA
 */

package dr.evomodel.indel;




/**
 * NativeTreeLikelihood - calls an implementation of HomologyRecursion.treeRecursion in C.
 *
 * @author Gerton Lunter
 *
 * 10/9/2003 
 *
 */

public class NativeTreeLikelihood {
	
  private static boolean isNativeAvailable = false;
  private int[][] iSequences;                       // rest are references to existing arrays
  private int iNN;
  private int iMUD;
  private long iStaticDataHandle;
    
    static {
	try {

	    System.loadLibrary("NativeTreeLikelihood");
	    System.err.println("Fast TKF91 homology integrator code found");
	    isNativeAvailable = true;

	} catch (UnsatisfiedLinkError e) {

	    System.err.println("Using Java TKF91 homology integrator code");

	}
    }
    

    /**
     * Constructor
     *
     */

    public NativeTreeLikelihood() { }


    /**
     * Hello, anybody?
     *
     */

    public boolean isAvailable() {
	return isNativeAvailable;
    }

    /**
     * Initialisation.  Returns with 'handle' (actually a pointer) to static data.
     *
     */

    private native long nativeInit(int[] iParent, double[] iEquil, double[] iTrans, 
				   double[] iH, double[] iN, double[] iE, double[] iB);

    /**
     * The actual recursion.  'iSD' is the handle returned by nativeInit.
     *
     */

    private native double nativeTreeRecursion(int[] iSignature, int[] iColumn, int iNumNucs, int iMUD, long iSD);

    /**
     * Relinquishes handle.
     *
     */

    private native void nativeDestruct(long iSD);


    /**
     * Initialiser
     *
     */

    public void init(int iNumNucs, int iMaxUnalignDimension, int[] iParent, double[] iEquil, double[][][] iTrans,
		     int[][] iSequences0,
		     double[] iN, double[] iH, double[] iE, double[] iB)
    {
	if (!isNativeAvailable)
	    return;

	// copy data into local variables
	iNN = iNumNucs;
        iMUD = iMaxUnalignDimension;
	iSequences = iSequences0;

	// translate iTrans[][][] array into flat array
	int iNumNodes = iTrans.length;
	double[] iFlatTrans = new double[ iNN*iNN*iNumNodes ];
	for (int i=0; i<iNumNodes; i++) {
	    for (int j=0; j<iNN; j++) {
		for (int k=0; k<iNN; k++) {
		    iFlatTrans[ k + iNN*( j + iNN*i ) ] = iTrans[i][j][k];
		}
	    }
	}

	// store data someplace where the C code has fast access
	iStaticDataHandle = nativeInit(iParent, iEquil, iFlatTrans, iH, iN, iE, iB);
    }


    /**
     * Make sure that memory is released when this object is garbage collected
     *
     */

    protected void finalize() throws Throwable {

	if (iStaticDataHandle != 0) {
	    nativeDestruct( iStaticDataHandle );
	}
	super.finalize();
    }


    /**
     * Actual front-end for HomologyRecursion
     *
     */

    public double treeRecursion(IntMathVec iSignature, IntMathVec iPos)
    {

	int[] iColumn = new int[ iSignature.iV.length ];
	for (int i=0; i<iSignature.iV.length; i++) {
	    if (iSignature.iV[i] != 0)
		iColumn[i] = iSequences[i][iPos.iV[i]];
	}

	return nativeTreeRecursion(iSignature.iV,
				   iColumn,
				   iNN,
				   iMUD,
				   iStaticDataHandle);
    }

}	

	

