package org.fda.evaluator;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.List;
import org.fda.data.ReferenceSet;
import org.fda.data.Utilities;
import org.fda.data.Enums;
import org.fda.data.QUAL;
//import org.fda.data.Enums.QUALITYLEVEL;
import org.fda.graphdrawing.chart.TwoDCategoryLinePlot;
import org.fda.graphdrawing.data.CategoryLineChartDataset;
import org.fda.graphdrawing.data.CategoryLineChartDatasetSeries;
import org.fda.graphdrawing.data.CustomHistogramDataset;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.statistics.HistogramType;
import org.jfree.chart.title.TextTitle;
import org.jfree.ui.RectangleEdge;

/**
 *
 * @author Gokhan.Yavas
 */
public abstract class EvaluatorBase {

    
    protected File contigfile;
    protected File alignmentfile;
    protected File outfile;
    protected File missassemblyFile;
    protected File outdir;     
    protected final ReferenceSet chrset;
    protected File sourceFolder;
    protected BufferedWriter bw;
    protected BufferedWriter bwc;
    protected BufferedWriter misassemblyBw;
    
    protected boolean writeToDest=true;
    protected Processor p; 
    protected final RectangleEdge aucPosition= RectangleEdge.BOTTOM;
    public EvaluatorBase(File sourceFolder,  File outdir, ReferenceSet chrset) throws IOException{        
        this.sourceFolder = sourceFolder;
        this.outdir = outdir;
        this.chrset = chrset;        
    }

    public boolean processFiles(){
        double[] quals=null;
        try {
            bw = new BufferedWriter(new FileWriter(outfile));
            bw.append("Scaffold ID\tScaffold Size\tAligned Scaffold Size\tAlignment Percentage\tGC Ratio\tAmbiguous Base (N) Ratio\tQuality Score");
            for(Enums.Inconsistency nci: Enums.Inconsistency.values())
                bw.append("\t"+nci);
            bw.append("\tTotal Misassembly");
            bw.append(Utilities.ls);
            
            bwc = new BufferedWriter(new FileWriter(alignmentfile));
            bwc.append("Scaffold ID\tChromosome ID\tChromosome Start\tChromosomeEnd\tChromosome Frame\tScaffold Start\tScaffold End\tScaffold Frame\tIdentity%\tStartTrimmed\tEndTrimmed"+Utilities.ls);
            
            misassemblyBw = new BufferedWriter(new FileWriter(missassemblyFile));
            misassemblyBw.append("Scaffold ID\tMisassembly Type\tScaffoldCoordinates1\tScaffoldCoordinates2\tAlignmentCoords1\tAlignmentCoords2"+Utilities.ls);
            
            QLPair[] quallist=process();
            drawQualityScoreHistogram(quallist, false);
            drawQualityScoreHistogram(quallist, true);
            
            bw.close();
            bwc.close();
            misassemblyBw.close();
            p.finalizeProcess();

            double covArea= calculateAreaUnderCurve(p.getCoverageRatio());
            double validityArea= calculateAreaUnderCurve(p.getValidityRatio());            
            //double invDupArea = calculateAreaUnderCurve(p.getInvDupRatio());            
            List<Double> tmplist=p.getInvDupRatio();            
            double invDup = tmplist.get(tmplist.size()-1);
            List<Double> darr = histAlternative(quallist);
            double relFreqArea = calculateAreaUnderCurve(darr);

            //drawGenomeCoverageChart(covArea);            
            drawChart(p.getCoverageRatio(), covArea, "Genome Coverage Ratio at Quality Thresholds", "", 1, "genomecoverageratio@Qthresholds");
            //drawValidityRatioChart(validityArea);            
            drawChart(p.getValidityRatio(), validityArea, "Validity Ratio at Quality Thresholds", "", 1, "validityratio@Qthresholds");
            //drawQualRelativeFreqChart(darr,relFreqArea);            
            drawChart(darr, relFreqArea, "Cumulative size ratio of Contigs/Scaffolds at Quality Thresholds", "", 1, "cumsizeratio@Qthresholds");
            
            //double finalscoreHarm = 3 / ((1/covArea)+(1/invDup)+(1/relFreqArea)+(1/validityArea));
            double finalscoreHarm = 3 / ((1/covArea)+(1/invDup)+(1/relFreqArea));
            //double finalscoreGeo = Math.pow(covArea*invDup*relFreqArea, (double)1/3);
            double finalscoreGeo = Math.cbrt(covArea*invDup*relFreqArea);
            double finalscoreArith = (covArea+invDup+relFreqArea)/3;

            BufferedWriter bo;
            File f1 = new File(this.outdir.getAbsolutePath()+File.separator+Utilities.assemblystatsFile);
            //File tmp = File.createTempFile(this.outdir.getAbsolutePath()+File.separator+Utilities.assemblystatsFile, ".tmp");
            File tmp = new File(this.outdir.getAbsolutePath()+File.separator+Utilities.assemblystatsFile+".tmp");

            bo = new BufferedWriter(new FileWriter(tmp));
            BufferedReader br = new BufferedReader(new FileReader(f1));
            String line;
            while((line=br.readLine())!=null){
                line = line.trim();
                if(line.startsWith("Final quality score for the assembly")){
                    break;
                }
                else{
                    if(!line.isEmpty())
                        bo.append(line+Utilities.ls);                    
                }
            }
            br.close();
            List<Double> coverage = p.getCoverageRatio();
            List<Double> validity = p.getValidityRatio();
            bo.append(Utilities.ls+"Final quality score for the assembly= "+Utilities.numberFormatter.format(finalscoreGeo));
            bo.append(Utilities.ls+"Genome coverage ratio for the assembly= "+Utilities.numberFormatter.format(coverage.get(coverage.size()-1)));
            bo.append(Utilities.ls+"Duplication ratio for the assembly= "+Utilities.numberFormatter.format(1/invDup));
            bo.append(Utilities.ls+"Validity ratio for the assembly= "+Utilities.numberFormatter.format(validity.get(validity.size()-1)));
                            
            bo.close();
            
            Files.copy(tmp.toPath() , f1.toPath(), StandardCopyOption.REPLACE_EXISTING);
            tmp.delete();
            
            
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return writeToDest;
    }
    private List<Double> hist(QLPair[] quals){
        List<Double> d = new ArrayList();
        //QUALITYLEVEL  c = QUALITYLEVEL.maxLevel();
        QUAL  c = Utilities.qlevel.getHighest();
        
        for(;true;){
            if(c==null)
                break;
            d.add(0.0);
            c = c.getPrev() ;
        }        
        int ind;
        
//        for(double q: quals){
        for(QLPair q: quals){
            ind=0;
            //c = QUALITYLEVEL.maxLevel();
            c = Utilities.qlevel.getHighest();
            for(;true;){
                if(c==null)
                    break;
                //if(q.getQuality()>=(double)c.getThreshold())
                if(q.getQuality()>=(double)c.getValue())
                    d.set(ind, d.get(ind)+1);
                c = c.getPrev();
                ind++;
            }
            
        }
        // normalize
        //c = QUALITYLEVEL.maxLevel();
        c = Utilities.qlevel.getHighest();
        ind=0;
        for(;true;){            
            if(c==null)
                break;
            d.set(ind, d.get(ind)/(double)quals.length);
            //System.out.println(d.get(ind));
            c = c.getPrev();
            ind++;
        }
        return d;
    }
    private List<Double> histAlternative(QLPair[] quals){
        List<Double> d = new ArrayList();        
        //QUALITYLEVEL  c = QUALITYLEVEL.maxLevel();
        QUAL  c = Utilities.qlevel.getHighest();
        for(;true;){
            if(c==null)
                break;
            d.add(0.0);
            c = c.getPrev();
        }        
        int ind;
        
        for(QLPair q: quals){
            ind=0;
            //c = QUALITYLEVEL.maxLevel();
            c = Utilities.qlevel.getHighest();
            for(;true;){
                if(c==null)
                    break;
                //if(q.getQuality()>=(double)c.getThreshold())
                if(q.getQuality()>=(double)c.getValue())
                    d.set(ind, d.get(ind)+q.getLength());
                //c = c.prevLevel() ;
                c = c.getPrev();
                ind++;
            }
            
        }
        double maxValue = d.get(d.size()-1);
        // normalize
        //c = QUALITYLEVEL.maxLevel();
        c = Utilities.qlevel.getHighest();
        ind=0;
        for(;true;){            
            if(c==null)
                break;
            //System.out.println(d.get(ind));
            d.set(ind, d.get(ind)/maxValue);
            //System.out.println(d.get(ind));
            //c = c.prevLevel() ;
            c = c.getPrev() ;
            ind++;
        }
        return d;
    }
    
    
    private double calculateAreaUnderCurve(List<Double> d){
        double sum=0;
        //List<Double> d = p.getCoverageRatio();
        for(int i=1; i< d.size(); i++){
            sum+=(d.get(i)+d.get(i-1))*Utilities.difference/2;
        }
        return sum;
    }
    private void drawChart(List<Double> darr, double auc, String chartName, String yaxisname, double maxYvalue, String filename){
        List<String> colNames = new ArrayList();
        
        CategoryLineChartDatasetSeries cd;
        CategoryLineChartDataset data = new CategoryLineChartDataset();
        
        //QUALITYLEVEL  c = QUALITYLEVEL.maxLevel();
        QUAL  c = Utilities.qlevel.getHighest();
        for(;true;){
            if(c==null)
                break;
            colNames.add("Q>="+c.getValue());
            c = c.getPrev();
        }        
        
        cd = new CategoryLineChartDatasetSeries("",colNames,darr);
        data.addSeries(cd);
        TextTitle legendText = new TextTitle("Area Under Curve: "+Utilities.numberFormatter.format(auc));
        legendText.setPosition(aucPosition);        
        
        try{
            File targetFile = new File(outdir.getAbsolutePath()+File.separator+"charts"+File.separator+
                    filename+Utilities.format.getExtension());
            TwoDCategoryLinePlot plot = new TwoDCategoryLinePlot(data, targetFile);
            plot.setYAxisName(yaxisname);
            plot.setXAxisName("");
            plot.setChartName(chartName);  
            plot.setXAxisLabelRotation(3);
            if(maxYvalue>0)
                plot.setYAxisUpperBound(maxYvalue);
            plot.addLegendText(legendText);
            plot.draw();
            
        }
        catch(Exception e){e.printStackTrace();}
    }
    
    public abstract QLPair[] process();
    
    private void drawQualityScoreHistogram(double[] quallist){
        CustomHistogramDataset dataset = new CustomHistogramDataset();
        dataset.setType(HistogramType.FREQUENCY);
        
        //double intlength = Utilities.maxQScore/ (double)Utilities.no_hist_bins ;
        dataset.addSeries("Quality Score Frequency", quallist, Utilities.no_hist_bins, 0, Utilities.maxQScore);
        
        JFreeChart chart = ChartFactory.createHistogram("Quality Score Histogram ", null, null, dataset,PlotOrientation.VERTICAL, true, false, false);
        chart.getXYPlot().setForegroundAlpha(0.75f);
        chart.getXYPlot().getDomainAxis().setRange(0, Utilities.maxQScore);
        File targetFile = new File(outdir.getAbsolutePath()+File.separator+"charts"+File.separator+"qualityScoreHistogram"+Utilities.format.getExtension());

        Utilities.saveAsFile(chart, targetFile, dataset.toTable(Utilities.intervalLength4Histogram));
        
        
    }
    private void drawQualityScoreHistogram(QLPair[] qlpairlist, boolean relFreq){
        double[] quallist = new double[qlpairlist.length];
        
        for(int z =0; z<qlpairlist.length; z++){
            quallist[z]=qlpairlist[z].getQuality();
        }
        if(relFreq){
            CustomHistogramDataset dataset = new CustomHistogramDataset();
            dataset.setType(HistogramType.RELATIVE_FREQUENCY);

            //double intlength = Utilities.maxQScore/ (double)Utilities.no_hist_bins ;
            dataset.addSeries("Quality Score Frequency", quallist, Utilities.no_hist_bins, 0, Utilities.maxQScore);

            JFreeChart chart = ChartFactory.createHistogram("Quality Score Histogram ", null, null, dataset,PlotOrientation.VERTICAL, true, false, false);
            chart.getXYPlot().setForegroundAlpha(0.75f);
            chart.getXYPlot().getDomainAxis().setRange(0, Utilities.maxQScore);
            File targetFile = new File(outdir.getAbsolutePath()+File.separator+"charts"+File.separator+"qualityScoreHistogram_RelativeFreq"+Utilities.format.getExtension());

            Utilities.saveAsFile(chart, targetFile, dataset.toTable(Utilities.intervalLength4Histogram));
        }
        else{
            drawQualityScoreHistogram(quallist);
        }        
    }    
}
