/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package edu.umbc.combio.erilllab.jfitom.gui;

import edu.umbc.combio.erilllab.jfitom.core.AnnotationStrategy;
import edu.umbc.combio.erilllab.jfitom.core.FilterStrategy;
import edu.umbc.combio.erilllab.jfitom.core.Genome;
import edu.umbc.combio.erilllab.jfitom.core.Motif;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.Logger;

/**
 *
 * @author Shehab
 */
public class JFitomWrapper {

    private final static Logger LOGGER = Logger.getLogger(MainView.class.getName());
    static private FileHandler logFileHandler;
    private static LogManager lm = LogManager.getLogManager();

    // We load all the options with default values. So, if any value is missing in the provided or
    // default options file it will be automatically carry the factory settings.
    private String latestGenomeFile = Options.DEFAULT_LATEST_GENOME_FILE;
    private String latestSitesFile = Options.DEFAULT_LATEST_SITES_FILE;
    private boolean areSitesPalindromic = Options.DEFAULT_IS_PALINDROME.equals("Y") ? true : false;
    private String outputFilePath = Options.DEFAULT_OUTPUT_FILE;
    private int scoreMethod = Integer.parseInt(Options.DEFAULT_SCORE_METHOD);
    private int maxHysteresisLimit = Integer.parseInt(Options.DEFAULT_MAX_HYSTERESIS_LIMIT);
    private int maxIntergenicDistance = Integer.parseInt(Options.DEFAULT_MAX_INTERGENIC_DISTANCE);
    private int maxOperatorDistanceIn = Integer.parseInt(Options.DEFAULT_MAX_OPERATOR_DISTANCE_IN);
    private int maxOperatorDistanceOut = Integer.parseInt(Options.DEFAULT_MAX_OPERATOR_DISTANCE_OUT);
    private int listSizeMethod = Integer.parseInt(Options.DEFAULT_RESULT_SIZE_METHOD);
    private int listSize = Integer.parseInt(Options.DEFAULT_RESULT_SIZE_METHOD_VALUE);
    private int thresholdMethod = Integer.parseInt(Options.DEFAULT_THRESHOLD_SCORE_METHOD);
    private double threshold = Double.parseDouble(Options.DEFAULT_THRESHOLD_SCORE_VALUE);
    private boolean generateLog = Options.DEFAULT_GENERATE_LOGS.equals("Y") ? true : false;
    private boolean viewResult = Options.DEFAULT_VIEW_RESULT.equals("Y") ? true : false;

    BufferedReader optionsFileReader;

    MainView mainView = null;

    public MainView getMainView() {
        return mainView;
    }

    public void setMainView(MainView mainView) {
        this.mainView = mainView;
    }

    /**
        This method is only for the command line operations.
     */
    public void loadOptionsFromFile(String optionsFile){
        try {
            if(optionsFile != null){
                System.out.println("Reading options file...");
                optionsFileReader = new BufferedReader(new FileReader(optionsFile));
            } else {
                // If no options file specified we look up in the default location
                System.out.println("Reading options file from the default location <same direcotry of JFitom>.");
                optionsFileReader = new BufferedReader(new FileReader("jfitom.opt"));
            }


            // Reading line by line
            String currentLine = null;
            try {
                log(Level.INFO, "Started reading options file.");
                while ((currentLine = optionsFileReader.readLine()) != null) {
                    if(!currentLine.startsWith("#")){
                        // Now we check which property, this line corresponds to
                        String[] optionValuePair = currentLine.split("=");
                        String option = optionValuePair[0].trim();
                        String value = optionValuePair[1].trim();

                        if(Options.OPTION_IS_PALINDROME.equals(option)){
                            if("Y".equals(value)){
                                areSitesPalindromic = true;
                            } else {
                                areSitesPalindromic = false;
                            }
                        }

                        if(Options.OPTION_OUTPUT_FILE.equals(option)){
                            outputFilePath = value;
                        }

                        if(Options.OPTION_SCORE_METHOD.equals(option)){
                            scoreMethod = Integer.parseInt(value);
                        }

                        if(Options.OPTION_MAX_HYSTERESIS_LIMIT.equals(option)){
                            maxHysteresisLimit = Integer.parseInt(value);
                        }

                        if(Options.OPTION_MAX_INTERGENIC_DISTANCE.equals(option)){
                            maxIntergenicDistance = Integer.parseInt(value);
                        }

                        if(Options.OPTION_MAX_OPERATOR_DISTANCE_OUT.equals(option)){
                            maxOperatorDistanceOut = Integer.parseInt(value);
                        }

                        if(Options.OPTION_MAX_OPERATOR_DISTANCE_IN.equals(option)){
                            maxOperatorDistanceIn = Integer.parseInt(value);
                        }

                        if(Options.OPTION_RESULT_SIZE_METHOD.equals(option)){
                            listSizeMethod = Integer.parseInt(value);
                        }

                        if(Options.OPTION_RESULT_SIZE_METHOD_VALUE.equals(option)){
                            listSize = Integer.parseInt(value);
                        }

                        if(Options.OPTION_THRESHOLD_SCORE_METHOD.equals(option)){
                            thresholdMethod = Integer.parseInt(value);
                        }

                        if(Options.OPTION_THRESHOLD_SCORE_VALUE.equals(option)){
                            threshold = Double.parseDouble(value);
                        }

                        System.out.println("Reading options file complete.");
                    } // If not a commented line

                }// while
            } catch (IOException ex) {
                log(Level.SEVERE, "I/O exception in reading options file.");
                System.out.println("I/O Exception during reading the options file.\nTerminating...");
                System.exit(1);

            }

        } catch (FileNotFoundException ex) {
            log(Level.SEVERE, "No options file found.");
            System.out.println("Options file not found.\nTerminating...");
            System.exit(1);

        }
    }

    public void printStatus(String statusMessage){
        if(mainView != null){
            mainView.setStatusBarText(statusMessage);
        } else {
            System.out.println(statusMessage);
        }
    }

    /*
     * This method takes all the required information as input and performs the computation.
     * This method is designed specially for the command line operation. We are not using this method
     * from MainView.java because we need to show progress through status bar messages.
     *
     * This method is only invoked in command line mode.
     *
     **/
    public String computeResult(String genomeFilePath, String sitesFilePath) {
        // Now we start real business.
            log(Level.INFO, "Opening genome file.");
            System.out.println("Opening genome file.");
            Genome g = new Genome(genomeFilePath);

            log(Level.INFO, "Opening motif file.");
            System.out.println("Opening motif file.");
            Motif m = new Motif(sitesFilePath);

            log(Level.INFO, "Generating PSFM.");
            System.out.println("Generating PSFM.");
            m.createPSFM(areSitesPalindromic);

            log(Level.INFO, "Setting apriory entropy.");
            System.out.println("Setting apriory entropy.");
            m.setaPrioryEntropy(g.getAprioriEntropy());

            log(Level.INFO, "Setting genome base frequency to motif.");
            System.out.println("Setting genome base frequency to motif.");
            m.setBaseFrequenciesOfGenome(g.getFreqAInDouble(),
				g.getFreqCInDouble(), g.getFreqGInDouble(),
				g.getFreqTInDouble());

            log(Level.INFO, "Generating ISeq matrix.");
            System.out.println("Generating ISeq matrix.");
            m.generateISeqMatrix();

            log(Level.INFO, "Generating Ri matrix.");
            System.out.println("Generating Ri matrix.");
            m.generateRIMatrix();

            log(Level.INFO, "Generating ISeqRE matrix.");
            System.out.println("Generating ISeqRE matrix.");
            m.generateISeqXREMatrix();

            log(Level.INFO, "Generating RiRSeq matrix.");
            System.out.println("Generating RiRSeq matrix.");
            m.generateRiXRSeqMatrix();

            log(Level.INFO, "Setting score method.");
            System.out.println("Setting score method.");
            int method = scoreMethod;

            log(Level.INFO, "Computing motif scores and stats.");
            System.out.println("Computing motif scores and stats.");
            m.computeSiteScoresAndStat(method);

            log(Level.INFO, "Setting filter strategy.");
            System.out.println("Setting filter strategy.");
            FilterStrategy fs = new FilterStrategy();
            log(Level.INFO, "Setting list size.");
            System.out.println("Setting list size.");
            if(listSizeMethod == FilterStrategy.LIST_SIZE_IN_NUMBER){
                fs.setLimitAsAbsoluteNumber(listSize);
            } else {
                fs.setLimitAsTopXPercentOfTotalSites(listSize);
            }

            log(Level.INFO, "Setting threshold.");
            System.out.println("Setting threshold.");
            if(thresholdMethod == FilterStrategy.THRESHOLD_METHOD_NORMALIZED){
                fs.setNormalizedThreshold(threshold);
            } else {
                fs.setThresholdSDBand(threshold);
            }

            log(Level.INFO, "Scoring genome with sites.");
            System.out.println("Scoring genome with sites.");
            m.scoreGenomeWithSites(g, method, fs, areSitesPalindromic);

            AnnotationStrategy as = new AnnotationStrategy();
            log(Level.INFO, "Setting annotation strategy.");
            System.out.println("Setting annotation strategy.");
            as.setMaxHysteresisLimit(maxHysteresisLimit + maxOperatorDistanceOut);
            as.setMaxInterGenicDistance(maxIntergenicDistance);
            as.setMaxOperatorDistanceOut(maxOperatorDistanceOut);
            as.setMaxOperatorDistanceIn(maxOperatorDistanceIn);

            log(Level.INFO, "Annonating result.");
            System.out.println("Annonating result.");
            m.getResultList().annotateResultList(g, as);
            log(Level.INFO, "Exporting result list to CSV.");
            System.out.println("Exporting result list to CSV.");
            m.getResultList().exportScoreToCSV(outputFilePath);
        return outputFilePath;
    }

    private void log(Level level, String logMessage){
            LOGGER.log(level, logMessage);
    }
}
