/*  
 *  src/org/metaqtl/EMCriteria.java
 * 
 *  $Author: veyrieras $, $Date: 2006-10-17 15:41:54 $, $Version$
 *
 *  MetaQTL : a Java package for QTL Meta-Analysis
 * 
 *  Copyright (C) 2003-2006  Jean-Baptiste Veyrieras, INRA, France.
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program 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 General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA * 
 */
package org.metaqtl;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;


/**
 * 
 * @author jveyrier
 *
 * 
 */
public class EMCriteria  implements Serializable {
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	public final static int AIC = 0;
	
	public final static int AIC3 = 1;
	
	public final static int ICOMP = 2;
	
	public final static int BIC   = 3;
	
	public final static int AWE   = 4;
	
	public final static int AICc   = 5;
	
	public final static String AIC_NAME = "AIC";
	
	public final static String AICc_NAME = "AICc";
	
	public final static String AIC3_NAME = "AIC3";
	
	public final static String ICOMP_NAME = "ICOMP";
	
	public final static String BIC_NAME   = "BIC";
	
	public final static String AWE_NAME   = "AWE";
	
	public double aic = Double.POSITIVE_INFINITY;
	
	public double aicc = Double.POSITIVE_INFINITY;
	
	public double aic3 = Double.POSITIVE_INFINITY;
	
	public double bic = Double.POSITIVE_INFINITY;
	
	public double mir = Double.POSITIVE_INFINITY;
	
	public double icomp = Double.POSITIVE_INFINITY;
	
	public double awe = Double.POSITIVE_INFINITY;
	
	/**
	 * Get the criterion value according to its integer
	 * code.
	 * @param criterion
	 * @return the value of the criterion.
	 */
	public double getCriterion(int criterion) {
		switch(criterion) {
			case AIC :
				return aic;
			case AICc :
				return aicc;
			case AIC3 :
				return aic3;
			case ICOMP :
				return icomp;
			case BIC :
				return bic;
			case AWE :
				return awe;
			default :
				return aic;
		}
	}

	/**
	 * For the given criterion <code>criterion</code> this methods
	 * looks into the array of {@link EMResult} and find the model
	 * which is optimal.
	 * 
	 * @param clusterings
	 * @param criterion
	 * @return the result which is optimal according to the criterion.
	 */
	public static EMResult getBestResult(EMResult[] clusterings, int criterion) {
		
		if (clusterings == null) return null;
		
		int    mini = -1;
		double min  = Double.POSITIVE_INFINITY;
		
		for(int i=0;i<clusterings.length;i++) {
			
			if (clusterings[i] != null) {
			
				double u = clusterings[i].criteria.getCriterion(criterion);
				
				if (u < min && i == mini+1) {
					min  = u;
					mini = i;	
				} else if (i > mini + 1) break;
			
			}
			
		}
		
		return clusterings[mini];
		
	}
	
	public static EMResult getBestResult(EMResult[] clusterings, int n, int criterion) {
		
		if (clusterings == null) return null;
		
		EMResult[] nfirst = new EMResult[Math.min(n, clusterings.length)];
		
		for(int i=0;i<nfirst.length;i++)
			nfirst[i]=clusterings[i];
		
		return  getBestResult(nfirst, criterion);
		
	}
	/**
	 * 
	 * @param clusterings
	 * @param criterion
	 * @return
	 */
	public static EMResult getBestResult(EMResult[] clusterings, String criterion) {
		
		return getBestResult(clusterings, getCriterionIdx(criterion));
		
	}
	
	/**
	 * 
	 * @param clusterings
	 * @param criterion
	 * @return
	 */
	public static EMResult getBestResult(EMResult[] clusterings, int n, String criterion) {
		
		return getBestResult(clusterings, n, getCriterionIdx(criterion));
		
	}
	
	
	/**
	 * Returns an iterator on the criteria
	 * @return
	 */
	public static Iterator getCriteria() {
		ArrayList list = new ArrayList(5);
		
		list.add(AIC_NAME);
		list.add(AICc_NAME);
		list.add(AIC3_NAME);
		//list.add(ICOMP_NAME);
		list.add(BIC_NAME);
		list.add(AWE_NAME);
		
		return list.iterator();
	}
	/**
	 * Returns the integer code for the criterion which matches
	 * the given name.
	 * @param name
	 * @return
	 */
	public static int getCriterionIdx(String name) {
		if (name.equalsIgnoreCase(AIC_NAME)) return AIC;
		if (name.equalsIgnoreCase(AICc_NAME)) return AICc;
		if (name.equalsIgnoreCase(AIC3_NAME)) return AIC3;
		if (name.equalsIgnoreCase(ICOMP_NAME)) return ICOMP;
		if (name.equalsIgnoreCase(BIC_NAME)) return BIC;
		if (name.equalsIgnoreCase(AWE_NAME)) return AWE;
		else return AIC;
	}

	/**
	 * @param criterion
	 * @return
	 */
	public double getCriterion(String criterion) {
		return getCriterion(getCriterionIdx(criterion));
	}
}