package fmph.features.mitochondrion1;

import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import calhoun.analysis.crf.AbstractFeatureManager;
import calhoun.analysis.crf.CacheStrategySpec;
import calhoun.analysis.crf.FeatureList;
import calhoun.analysis.crf.FeatureManagerEdge;
import calhoun.analysis.crf.FeatureManagerNode;
import calhoun.analysis.crf.ModelManager;
import calhoun.analysis.crf.CacheStrategySpec.CacheStrategy;
import calhoun.analysis.crf.io.InputSequence;
import calhoun.analysis.crf.io.TrainingSequence;

/** Implements Exonerate features.
 * Symbols:
 * 0 - unknown
 * 1 - exon plus
 * 2 - exon minus
 * 3 - intron plus
 * 4 - intron minus
 */

public class ExonerateMitochondrion1 extends AbstractFeatureManager<Integer> implements FeatureManagerNode<Integer> , FeatureManagerEdge<Integer> {
	private static final Log log = LogFactory.getLog(ExonerateMitochondrion1.class);
	boolean debug = log.isDebugEnabled();
	

	
	int startIx;  // The index of the first feature managed by this FeatureManager
	ModelManager model;
	
	boolean[] intergenicState;
	boolean[] plusExonState;
	boolean[] minusExonState;
	boolean[] plusIntronState;
	boolean[] minusIntronState;	
	
	public ExonerateMitochondrion1() {
	}

	public int getNumFeatures() {
		return 10;
	}	
	
	public String getFeatureName(int featureIndex) {
		String[] types = new String[] {"exon plus", "exon minus", "intron plus", "intron minus", "Intergenic"};
		int raw = featureIndex-startIx;
		if(raw < 5) {
			return "Exonerate "+types[raw];
		}
		else {
			String[] edge = new String[] {"acc plus", "acc minus", "donor plus", "donor minus", "no edge"};
			return "Exonerate "+edge[raw-5];
		}
	}

	public void evaluateNode(InputSequence<? extends Integer> seq, int pos, int state, FeatureList result) {
                            
		int exState  = seq.getX(pos).intValue();
		// 0 - unknown
		// 1 - exon plus
		// 2 - exon minus
		// 3 - intron plus
                // 4 - intron minus

		if (plusExonState[state] && (exState==1)) { result.addFeature(startIx, 1); }
		if (minusExonState[state] && (exState==2)) { result.addFeature(startIx+1, 1); }
		
		if (plusIntronState[state] && (exState==3)) { result.addFeature(startIx+2, 1); }
		if (minusIntronState[state] && (exState==4)) { result.addFeature(startIx+3, 1); }

		if (intergenicState[state] && exState > 0) { result.addFeature(startIx+4, 1); }			
	}

	public void evaluateEdge(InputSequence<? extends Integer> seq, int pos, int prevState, int state, FeatureList result) {
            if( (pos == seq.length()-1) || (pos == 0) ) {
                return;
            }	
            
	    int exState  = seq.getX(pos).intValue();
	    int exStateP  = seq.getX(pos-1).intValue();
            
	    // 0 - unknown
	    // 1 - exon plus
	    // 2 - exon minus
	    // 3 - intron plus
	    // 4 - intron minus
            
            Boolean plusacc = ((exStateP==3) && (exState==1));
            Boolean plusdon = ((exStateP==1) && (exState==3));
            Boolean minusacc = ((exStateP==4) && (exState==2));
            Boolean minusdon = ((exStateP==2) && (exState==4));
            
            if (plusacc  && plusExonState[state] && plusIntronState[prevState]) { result.addFeature(startIx+5,1); return; }
            if (minusacc && minusExonState[prevState] && minusIntronState[state]) { result.addFeature(startIx+6,1); return;}
            
            if (plusdon && plusIntronState[state] && plusExonState[prevState]) { result.addFeature(startIx+7,1); return;}
            if (minusdon && plusIntronState[prevState] && plusExonState[state]) { result.addFeature(startIx+8,1); return;}
            
	    result.addFeature(startIx+9,1);
	}
		
	public void train(int startingIndex, ModelManager modelInfo, List<? extends TrainingSequence<? extends Integer>> data) {
		startIx = startingIndex;
		model = modelInfo;

		int nStates = model.getNumStates();
		
		plusExonState = new boolean[nStates];
		plusExonState[model.getStateIndex("exon0")] = true;
		plusExonState[model.getStateIndex("exon1")] = true;
		plusExonState[model.getStateIndex("exon2")] = true;
		
		minusExonState = new boolean[nStates]; 
		minusExonState[model.getStateIndex("exon0m")] = true;
		minusExonState[model.getStateIndex("exon1m")] = true;
		minusExonState[model.getStateIndex("exon2m")] = true;		
		
		plusIntronState = new boolean[nStates];
		plusIntronState[model.getStateIndex("intron0")] = true;
		plusIntronState[model.getStateIndex("intron1")] = true;
		plusIntronState[model.getStateIndex("intron2")] = true;
		
		minusIntronState = new boolean[nStates]; 
		minusIntronState[model.getStateIndex("intron0m")] = true;
		minusIntronState[model.getStateIndex("intron1m")] = true;
		minusIntronState[model.getStateIndex("intron2m")] = true;	

		intergenicState = new boolean[nStates];
		intergenicState[model.getStateIndex("intergenic")] = true;
	}

	@Override
	public CacheStrategySpec getCacheStrategy() {
		return new CacheStrategySpec(CacheStrategy.DENSE);
	}

}

