/*
 * Copyright 2009 Lari Natri <lari.natri@gmail.com>
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 * 
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 * 
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */


package compid.report;

import compid.data.DAOException;
import compid.data.DAOFactory;
import compid.data.QueryHandler;
import compid.report.GeneralStatsReporter.GeneralStatsReporterParams;
import net.aavalla.utils.jobpool.parameters.FieldAnnotations;
import net.aavalla.utils.jobpool.parameters.validators.StringValidator;
import net.aavalla.utils.general.BasicStatNumbers;
import net.aavalla.utils.jobpool.JobCategory;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collection;

/**
 *
 * @author Lari Natri
 */
public class GeneralStatsReporter extends Reporter<GeneralStatsReporterParams> {

    public final class GeneralStatsReporterParams extends ReporterParams {
        @FieldAnnotations(name="Report Title",validator=StringValidator.class,validatorSettings={"1","64",FieldAnnotations.NULL})
        private String reportTitle = "General Statistics";
        @FieldAnnotations(name="Datasets",validator=DatasetCollectionNotEmptyValidator.class,description="Datasets to include")
        private DatasetCollection dataSets;
        @FieldAnnotations(name="Include 'per Protein' Stats",description="Includes statistics for the amount of \nqueries and peptides per protein")
        private boolean includePerProteinStats = true;

        public GeneralStatsReporterParams() {
            this.setDescription("Generates general statistical information about the amounts <br/>" +
                                "of queries and peptides in relation to the matched proteins <br/>" +
                                "in the given dataset (union). ");
            this.setHelpID("statistics");
        }
    }

    public GeneralStatsReporter() {
        super();
        this.addCategory(JobCategory.DB_READ);
        this.addConflictingCategory(JobCategory.DB_WRITE);
        this.setName("General Statistics Reporter");
    }


    @Override
    protected GeneralStatsReporterParams getNonfinalEditableParameters() {
        return new GeneralStatsReporterParams();
    }


    @Override
    public ReportModel createReport(GeneralStatsReporterParams p) throws DAOException {

        QueryHandler qh = DAOFactory.getInstance().getQueryHandler();
        
        String subTitle;
        if (p.dataSets.getCollection().size() > 1) {
            subTitle = "Datasets: {"+p.dataSets.getName()+"}";
        } else {
            subTitle = "Dataset: "+p.dataSets.getName();
        }

        ReportPageModel page = new ReportPageModel(p.reportTitle,subTitle);
        page.addColumn("Property");
        page.addColumn("Value");

        ArrayList<Object> row = new ArrayList<Object>(2);
        row.add("Queries resulting in Peptide hit");
        row.add(qh.getQueriesWhichFoundPeptidesInDatasetsCount(p.dataSets.getCollection()));
        page.addRow(row);
        row = new ArrayList<Object>(2);
        row.add("Queries resulting in Peptide hit assigned to Protein");
        row.add(qh.getQueriesWhichFoundPeptidesInProteinsInDatasetsCount(p.dataSets.getCollection()));
        page.addRow(row);
        row = new ArrayList<Object>(2);
        row.add("Distinct Peptides");
        row.add(qh.getDistinctPeptidesInDataSetsCount(p.dataSets.getCollection()));
        page.addRow(row);
        row = new ArrayList<Object>(2);
        row.add("Distinct Peptides assigned to Proteins");
        row.add(qh.getDistinctPepsUsedInProtsByDataSetsCount(p.dataSets.getCollection()));
        page.addRow(row);
        row = new ArrayList<Object>(2);
        row.add("Distinct Proteins by accession");
        row.add(qh.getDistinctProteinCount(p.dataSets.getCollection()));
        page.addRow(row);


        if (p.includePerProteinStats) {

            DecimalFormat twoDigit = new DecimalFormat("###############0.00"); //NOI18N

            Collection<Integer> countSet = qh.getQueryHitCountsPerProtein(p.dataSets.getCollection());
            BasicStatNumbers stats = new BasicStatNumbers<Integer>(countSet);
            row = new ArrayList<Object>(2);
            row.add("Queries per Protein, min");
            row.add(stats.min);
            page.addRow(row);
            row = new ArrayList<Object>(2);
            row.add("Queries per Protein, median");
            row.add(stats.median);
            page.addRow(row);
            row = new ArrayList<Object>(2);
            row.add("Queries per Protein, max");
            row.add(stats.max);
            page.addRow(row);
            row = new ArrayList<Object>(2);
            row.add("Queries per Protein, SD");
            row.add(twoDigit.format(stats.sd));
            page.addRow(row);

            countSet.clear();

            countSet = qh.getDistinctPeptideCountsPerProtein(p.dataSets.getCollection());
            stats = new BasicStatNumbers<Integer>(countSet);

            row = new ArrayList<Object>(2);
            row.add("Peptides per Protein, min");
            row.add(stats.min);
            page.addRow(row);
            row = new ArrayList<Object>(2);
            row.add("Peptides per Protein, median");
            row.add(stats.median);
            page.addRow(row);
            row = new ArrayList<Object>(2);
            row.add("Peptides per Protein, max");
            row.add(stats.max);
            page.addRow(row);
            row = new ArrayList<Object>(2);
            row.add("Peptides per Protein, SD");
            row.add(twoDigit.format(stats.sd));
            page.addRow(row);

            countSet.clear();
        }


        page.setPageIsFinal();

        ReportModel report = new ReportModel(p.reportTitle,subTitle,p);
        report.addPage(page);

        return report;

    }

}
