package fmph.features.mitochondrion1;

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

import java.util.List;

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

public class IntronHitsMitochondrion1 extends AbstractFeatureManager<Integer> implements FeatureManagerNode<Integer> {
    private static final Log log = LogFactory.getLog(IntronHitsMitochondrion1.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 IntronHitsMitochondrion1() {
    }

    public int getNumFeatures() {
        return 3;
    }

    public String getFeatureName(int featureIndex) {
        String[] types = new String[] { "exon", "intron", "Intergenic" };
        int raw = featureIndex - startIx;
        return "Intron hits " + types[raw];
        
    }

    public void evaluateNode(InputSequence<? extends Integer> seq, int pos, int state, FeatureList result) {

        int intronState = seq.getX(pos).intValue();
        // 0 - unknown
        // 1 - intron plus
        // 2 - intron minus

        if ((plusExonState[state] && (intronState == 1)) || (minusExonState[state] && (intronState == 2))) {
            result.addFeature(startIx, 1);
        }

        if ((plusIntronState[state] && (intronState == 1)) || (minusIntronState[state] && (intronState == 2))) {
            result.addFeature(startIx + 1, 1);
        }

        if (intergenicState[state] && (intronState == 1 || intronState == 2)) {
            result.addFeature(startIx + 2, 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);
    }
}
