package mlproject.util;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintWriter;

import java.text.DecimalFormat;

import java.util.List;

import mlproject.hmm.StateModel;

import mlproject.io.TrainingSequence;

import mlproject.phylo.EvolutionaryModel;

public class Util {
    public Util() {
    }

    public static boolean containsElement(int[] a, int b) {
        for (int i = 0; i < a.length; i++) {
            if (a[i] == b)
                return true;
        }
        return false;
    }

    public static void printPhyloValues(String location, List<TrainingSequence> list, EvolutionaryModel emodelIntergenic,
                                        EvolutionaryModel emodelIntronic, List<EvolutionaryModel> emodelExonic,
                                        StateModel stateModel) throws FileNotFoundException {

        PrintWriter pwExon = new PrintWriter(new FileOutputStream(location + "exon.values"));
        for (TrainingSequence s : list) {
            pwExon.println(">" + s.getInputSequence().getName());
            

            for (int i = 0; i < s.getInputSequence().getComponent(0).length(); i++) {
                
                if(!s.isValid()){
                    pwExon.println(0);
                    continue;
                }
                
                int state = s.getY(i);
                String column = (String)s.getInputSequence().getComponent(1).getX(i);

                if (Util.containsElement(stateModel.getIntergenicStates(), state)) {
                    pwExon.println(-emodelExonic.get(0).getColumnLogProbability(column, false)/emodelIntronic.getColumnLogProbability(column, false));
                }

                if (Util.containsElement(stateModel.getPlusExon0States(), state)) {
                    pwExon.println(-emodelExonic.get(0).getColumnLogProbability(column, false)/emodelIntronic.getColumnLogProbability(column, false));
                }

                if (Util.containsElement(stateModel.getPlusExon1States(), state)) {
                    pwExon.println(-emodelExonic.get(1).getColumnLogProbability(column, false)/emodelIntronic.getColumnLogProbability(column, false));
                }

                if (Util.containsElement(stateModel.getPlusExon2States(), state)) {
                    pwExon.println(-emodelExonic.get(2).getColumnLogProbability(column, false)/emodelIntronic.getColumnLogProbability(column, false));
                }

                if (Util.containsElement(stateModel.getMinusExon0States(), state)) {
                    pwExon.println(-emodelExonic.get(0).getColumnLogProbability(column, true)/emodelIntronic.getColumnLogProbability(column, true));
                }

                if (Util.containsElement(stateModel.getMinusExon1States(), state)) {
                    pwExon.println(-emodelExonic.get(1).getColumnLogProbability(column, true)/emodelIntronic.getColumnLogProbability(column, true));
                }

                if (Util.containsElement(stateModel.getMinusExon2States(), state)) {
                    pwExon.println(-emodelExonic.get(2).getColumnLogProbability(column, true)/emodelIntronic.getColumnLogProbability(column, true));
                }

                if (Util.containsElement(stateModel.getPlusIntronicStates(), state)) {
                    pwExon.println(-emodelExonic.get(0).getColumnLogProbability(column, false)/emodelIntronic.getColumnLogProbability(column, false));
                }

                if (Util.containsElement(stateModel.getMinusIntronicStates(), state)) {
                    pwExon.println(-emodelExonic.get(0).getColumnLogProbability(column, true)/emodelIntronic.getColumnLogProbability(column, true));
                }
            }
        }
        pwExon.close();

    }
    
    public static void printPhyloValues2(String location, List<TrainingSequence> list, EvolutionaryModel emodelIntergenic,
                                        EvolutionaryModel emodelIntronic, List<EvolutionaryModel> emodelExonic,
                                        StateModel stateModel) throws FileNotFoundException {

        PrintWriter pwInter = new PrintWriter(new FileOutputStream(location + "inter.values"));
        PrintWriter pwIntron = new PrintWriter(new FileOutputStream(location + "intron.values"));
        PrintWriter pwExon = new PrintWriter(new FileOutputStream(location + "exon.values"));
        for (TrainingSequence s : list) {
            pwInter.println(">" + s.getInputSequence().getName());
            pwIntron.println(">" + s.getInputSequence().getName());
            pwExon.println(">" + s.getInputSequence().getName());
            

            for (int i = 0; i < s.getInputSequence().getComponent(0).length(); i++) {
                
                if(!s.isValid()){
                    pwInter.println(0);
                    pwIntron.println(0);
                    pwExon.println(0);
                    continue;
                }
                
                int state = s.getY(i);
                String column = (String)s.getInputSequence().getComponent(1).getX(i);
                pwInter.println(emodelIntergenic.getColumnLogProbability(column, false));

                if (Util.containsElement(stateModel.getIntergenicStates(), state)) {
                    pwIntron.println(emodelIntronic.getColumnLogProbability(column, false));
                    pwExon.println(emodelExonic.get(0).getColumnLogProbability(column, false));
                }

                if (Util.containsElement(stateModel.getPlusExon0States(), state)) {
                    pwIntron.println(emodelIntronic.getColumnLogProbability(column, false));
                    pwExon.println(emodelExonic.get(0).getColumnLogProbability(column, false));
                }

                if (Util.containsElement(stateModel.getPlusExon1States(), state)) {
                    pwIntron.println(emodelIntronic.getColumnLogProbability(column, false));
                    pwExon.println(emodelExonic.get(1).getColumnLogProbability(column, false));
                }

                if (Util.containsElement(stateModel.getPlusExon2States(), state)) {
                    pwIntron.println(emodelIntronic.getColumnLogProbability(column, false));
                    pwExon.println(emodelExonic.get(2).getColumnLogProbability(column, false));
                }

                if (Util.containsElement(stateModel.getMinusExon0States(), state)) {
                    pwIntron.println(emodelIntronic.getColumnLogProbability(column, true));
                    pwExon.println(emodelExonic.get(0).getColumnLogProbability(column, true));
                }

                if (Util.containsElement(stateModel.getMinusExon1States(), state)) {
                    pwIntron.println(emodelIntronic.getColumnLogProbability(column, true));
                    pwExon.println(emodelExonic.get(1).getColumnLogProbability(column, true));
                }

                if (Util.containsElement(stateModel.getMinusExon2States(), state)) {
                    pwIntron.println(emodelIntronic.getColumnLogProbability(column, true));
                    pwExon.println(emodelExonic.get(2).getColumnLogProbability(column, true));
                }

                if (Util.containsElement(stateModel.getPlusIntronicStates(), state)) {
                    pwIntron.println(emodelIntronic.getColumnLogProbability(column, false));
                    pwExon.println(emodelExonic.get(0).getColumnLogProbability(column, false));
                }

                if (Util.containsElement(stateModel.getMinusIntronicStates(), state)) {
                    pwIntron.println(emodelIntronic.getColumnLogProbability(column, true));
                    pwExon.println(emodelExonic.get(0).getColumnLogProbability(column, true));
                }
            }
        }
        pwInter.close();
        pwIntron.close();
        pwExon.close();

    }
    
    public static String printStats(int[] statsArray){
        int TP = 0;
        int FP = 1;
        int TN = 2;
        int FN = 3;
        
        double sens = (double)statsArray[TP]/(statsArray[TP]+statsArray[FN]);
        double spec = (double)statsArray[TN]/(statsArray[FP]+statsArray[TN]);
        double prec = (double)statsArray[TP]/(statsArray[TP]+statsArray[FP]);
        DecimalFormat format = new DecimalFormat("#.###");
        return "TP=" + statsArray[TP] + ", FP=" + statsArray[FP] + ", TN=" + statsArray[TN] + ", FN=" + statsArray[FN] + 
               ", sens=" +  format.format(sens)  + ", spec=" + format.format(spec) + 
               ", prec=" +  format.format(prec)+ "\n";
    }
    
    public static String printStats2(int[] statsArray){
            int TP = 0;
            int FP = 1;
            int TN = 2;
            int FN = 3;
            
            double sens = (double)statsArray[TP]/(statsArray[TP]+statsArray[FN]);
            double prec = (double)statsArray[TP]/(statsArray[TP]+statsArray[FP]);
            DecimalFormat format = new DecimalFormat("#.###");
            return "TP=" + statsArray[TP] + ", FP=" + statsArray[FP] +  ", FN=" + statsArray[FN] + 
                   ", sens=" +  format.format(sens)  + ", prec=" +  format.format(prec)+ "\n";
        }
    
    public static String printTabbedStats(int[] statsArray){
        int TP = 0;
        int FP = 1;
        int TN = 2;
        int FN = 3;
        
        double sens = (double)statsArray[TP]/(statsArray[TP]+statsArray[FN]);
        double spec = (double)statsArray[TN]/(statsArray[FP]+statsArray[TN]);
        double prec = (double)statsArray[TP]/(statsArray[TP]+statsArray[FP]);
        DecimalFormat format = new DecimalFormat("#.###");
        return statsArray[TP] + "\t" + statsArray[FP] + "\t" + statsArray[TN] + "\t" + statsArray[FN] + 
               "\t" +  format.format(sens)  + "\t" + format.format(spec) + 
               "\t" +  format.format(prec);
    }
    
    public static String printTabbedStats2(int[] statsArray){
        int TP = 0;
        int FP = 1;
        int TN = 2;
        int FN = 3;
        
        double sens = (double)statsArray[TP]/(statsArray[TP]+statsArray[FN]);
        double prec = (double)statsArray[TP]/(statsArray[TP]+statsArray[FP]);
        DecimalFormat format = new DecimalFormat("#.###");
        return  statsArray[TP] + "\t" + statsArray[FP] +  "\t" + statsArray[FN] + 
               "\t" +  format.format(sens)  + "\t" +  format.format(prec);
    }
    
    public static String printTabbedStats3(int[] statsArray){
        int TP = 0;
        int FP = 1;
        int TN = 2;
        int FN = 3;
        
        double sens = (double)statsArray[TP]/(statsArray[TP]+statsArray[FN]);
        double spec = (double)statsArray[TN]/(statsArray[FP]+statsArray[TN]);
        double prec = (double)statsArray[TP]/(statsArray[TP]+statsArray[FP]);
        DecimalFormat format = new DecimalFormat("#.###");
        return 
               format.format(sens)  + "\t" + format.format(spec) + 
               "\t" +  format.format(prec);
    }
}
