/*
 * 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.data.tuples;

import compid.data.tuples.DatasetInfo.AlgType;
import java.util.HashMap;

/**
 *
 * @author Lari Natri
 */
public final class PeptideHit extends Tuple {
    
    public static final String TABLELABEL = "PEPTIDEHIT";
    private static final double NONEXISTINGSCORE = -1d;

    private Peptide peptide = null;
    private Query query = null;
    private final double pgConfidence;
    private final double msIonsScore;
    
    public PeptideHit(Peptide peptide, Query query, 
                      double ionscoreOrConf) {
        this.peptide = peptide;
        this.query = query;
        if (query.getDataSetInfo().getAlgorithm()==DatasetInfo.AlgType.MASCOT) {
            this.msIonsScore = ionscoreOrConf;
            this.pgConfidence = NONEXISTINGSCORE;
        } else if (query.getDataSetInfo().getAlgorithm()==DatasetInfo.AlgType.PARAGON) {
            this.pgConfidence = ionscoreOrConf;
            this.msIonsScore = NONEXISTINGSCORE;
        } else { // UNKNOWN
            this.pgConfidence = NONEXISTINGSCORE;
            this.msIonsScore = NONEXISTINGSCORE;
        }
    }
    
    public Peptide getPeptide() { return this.peptide; }
    
    public Query getQuery() { return this.query; }

    public double getCorrectScore() {
        if (this.pgConfidence>=0) return this.pgConfidence;
        else return this.msIonsScore;
    }

    public double getMascotIonsScore() {
        return this.msIonsScore;
    }

    public double getParagonConfidence() {
        return this.pgConfidence;
    }
    
    public final double getComparableConfidence() {
        if (this.pgConfidence > this.msIonsScore) {
            return getComparableConfidence(this.pgConfidence, AlgType.PARAGON);
        } else {
            return getComparableConfidence(this.msIonsScore, AlgType.MASCOT);
        }
    }

    
    public void setQuery(Query query) {
        if (query==null) return;
        this.query = query;
    }
    
    public void setPeptide(Peptide peptide) {
        if (peptide==null) return;
        this.peptide = peptide;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final PeptideHit other = (PeptideHit) obj;
        if (this.peptide != other.peptide && (this.peptide == null || !this.peptide.equals(other.peptide))) {
            return false;
        }
        if (this.query != other.query && (this.query == null || !this.query.equals(other.query))) {
            return false;
        }
        if (this.pgConfidence != other.pgConfidence) {
            return false;
        }
        if (this.msIonsScore != other.msIonsScore) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        int hash = 3;
        hash = 41 * hash + (this.peptide != null ? this.peptide.hashCode() : 0);
        hash = 41 * hash + (this.query != null ? this.query.hashCode() : 0);
        hash = 41 * hash + (int) (Double.doubleToLongBits(this.pgConfidence) ^ (Double.doubleToLongBits(this.pgConfidence) >>> 32));
        hash = 41 * hash + (int) (Double.doubleToLongBits(this.msIonsScore) ^ (Double.doubleToLongBits(this.msIonsScore) >>> 32));
        return hash;
    }


    @Override
    public String getTableLabel() {
        return TABLELABEL;
    }

    @Override
    public HashMap<String,Object> getColsAndValues() {
        HashMap<String,Object> map = new HashMap<String,Object>(2,1);
        map.put("MS_IONSSCORE", msIonsScore);
        map.put("PG_CONF", pgConfidence);
        return map;
    }

    /**
     * Returns a comparable confidence.
     * @param score peptide score given by source software ('ions score' for
     *              Mascot, 'confidence' [0..1] for Paragon
     * @param alg   source software
     * @return comparable confidence, but -1 if algorithm is unknown or score
     *         is otherwise incomputable for some reason
     */
    public static double getComparableConfidence(double score, AlgType alg) {
        switch(alg) {
            case PARAGON:
                // Database should hold confidences in form 0..1, but Paragon
                // reports them in excel reports (not in xml) as a percentage.
                // So, check just in case -- though this should be taken care
                // of by importers
                if (score>1) {
                    score = score/100d;
                }
                break;
            case MASCOT:
                score = 1 - Math.pow(Math.E, -(score/10d));
                break;
            case UNKNOWN:
            default:
                return -1; // don't know how to handle
        }
        if (score<0 || score>1) {
            return -1;
        }
        return score;
     }

  
    
}
