/*
 * Copyright 2009, 2010 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 java.util.HashMap;

/**
 *
 * @author Lari Natri
 */
public final class ProteinHit extends Tuple {
    
    public static final String TABLELABEL = "PROTEINHIT";

    public enum GroupMemberStatus {
        WINNER { // winner (main, representative) protein of a group
            @Override public int getCode() { return 1; }
            @Override public String toString() { return "Winner"; }
        },
        SUBISOFORMWINNER { // sub protein of a group (non-winner); actually this is an alternate winner, but treated as non-winner (each group must have only one representing winner); originates in Paragon
            @Override public int getCode() { return 3; }
            @Override public String toString() { return "Sub (Isoform, Paragon)"; }
        },
        SUBPEPCOMPLETE { // sub protein of a group (non-winner) having exactly same peptides as the main protein; originates in Mascot
            @Override public int getCode() { return 4; }
            @Override public String toString() { return "Sub (Peptides-Full, Mascot)"; }
        },
        SUBPEPSUBSET { // sub protein of a group (non-winner) having subset of the main protein's peptides; Paragon/Mascot
            @Override public int getCode() { return 5; }
            @Override public String toString() { return "Sub (Peptides-Subset)"; }
        },
        SUBSEQSUBSET { // sub protein of a group (non-winner) with a subset of the main protein's protein sequence
            @Override public int getCode() { return 6; }
            @Override public String toString() { return "Sub (Sequence-Subset, Paragon)"; }
        },
        SUBUNKNOWN { // sub protein of a group (non-winner), unknown reason
            @Override public int getCode() { return 2; }
            @Override public String toString() { return "Sub (Unknown)"; }
        };


        public static GroupMemberStatus getInstanceByCode(int statusCode) 
                throws IllegalArgumentException
        {
            switch(statusCode) {
                case 1 : return GroupMemberStatus.WINNER;
                case 2 : return GroupMemberStatus.SUBUNKNOWN;
                case 3 : return GroupMemberStatus.SUBISOFORMWINNER;
                case 4 : return GroupMemberStatus.SUBPEPCOMPLETE;
                case 5 : return GroupMemberStatus.SUBPEPSUBSET;
                case 6 : return GroupMemberStatus.SUBSEQSUBSET;
                default :
                    throw new IllegalArgumentException("Trying to create " +
                            "group member status from illegal code="+statusCode);
            }
        }
        public abstract int getCode();
    }

    private final DatasetInfo.AlgType algorithm;
    private Protein protein;
    private DatasetInfo dataset;
    private final int groupId;
    private final GroupMemberStatus groupMemberStatus;
    private double mascotScore = -1.0d;
//    private int paragonRank = -1;
    private double paragonUnused = -1.0d;
    private double paragonTotal = -1.0d;
//    private double paragonCov = -1.0d;
    
    public ProteinHit(Protein protein, DatasetInfo dataset, int groupId,
                      GroupMemberStatus groupMemberStatus, double mascotScore) {
        this.algorithm = DatasetInfo.AlgType.MASCOT;
        this.protein = protein;
        this.dataset = dataset;
        this.groupId = groupId;
        this.groupMemberStatus = groupMemberStatus;
        this.mascotScore = mascotScore;
        if (this.protein==null)
            throw new NullPointerException("Protein must be set.");        
    }
    
    public ProteinHit(Protein protein, DatasetInfo dataset, int groupId,
                      GroupMemberStatus groupMemberStatus)
    {
        this.algorithm = DatasetInfo.AlgType.UNKNOWN;
        this.protein = protein;
        this.dataset = dataset;
        this.groupId = groupId;
        this.groupMemberStatus = groupMemberStatus;
        if (this.protein==null)
            throw new NullPointerException("Protein must be set.");
    }
    
    public ProteinHit(Protein protein, DatasetInfo dataset, int groupId, 
                      GroupMemberStatus groupMemberStatus,
                      double paragonUnused, double paragonTotal)
    {
        this.algorithm = DatasetInfo.AlgType.PARAGON;
        this.protein = protein;
        this.dataset = dataset;
        this.groupId = groupId;
        this.groupMemberStatus = groupMemberStatus;
//        this.paragonRank = paragonRank;
        this.paragonUnused = paragonUnused;
        this.paragonTotal = paragonTotal;
//        this.paragonCov = paragonCov;
        if (this.protein==null)
            throw new NullPointerException("Protein must be set.");
    }

    
    public DatasetInfo.AlgType getAlgType() { return this.algorithm; }
    
    public Protein getProtein() { return this.protein; }

    public DatasetInfo getDataset() { return this.dataset; }

    public int getGroupId() { return this.groupId; }

    public GroupMemberStatus getGroupMemberStatus() { return this.groupMemberStatus; }
    
    public double getMascotScore() { return this.mascotScore; }
    
//    public int getParagonRank() { return this.paragonRank; }
    
    public double getParagonUnused() { return this.paragonUnused; }
    
    public double getParagonTotal() { return this.paragonTotal; }
    
//    public double getParagonCov() { return this.paragonCov; }
    
    public void setProtein(Protein prot) {
        if (prot==null) return;
        this.protein = prot;
    }

    public void setDataset(DatasetInfo dataset) {
        if (dataset==null) return;
        this.dataset = dataset;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final ProteinHit other = (ProteinHit) obj;
        if (this.algorithm != other.algorithm && (this.algorithm == null || !this.algorithm.equals(other.algorithm))) {
            return false;
        }
        if (this.protein != other.protein && (this.protein == null || !this.protein.equals(other.protein))) {
            return false;
        }
        if (this.dataset != other.dataset && (this.dataset == null || !this.dataset.equals(other.dataset))) {
            return false;
        }
        if (this.groupId != other.groupId) {
            return false;
        }
        if (this.groupMemberStatus != other.groupMemberStatus && (this.groupMemberStatus == null || !this.groupMemberStatus.equals(other.groupMemberStatus))) {
            return false;
        }
        if (this.mascotScore != other.mascotScore) {
            return false;
        }
        if (this.paragonUnused != other.paragonUnused) {
            return false;
        }
        if (this.paragonTotal != other.paragonTotal) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 97 * hash + (this.algorithm != null ? this.algorithm.hashCode() : 0);
        hash = 97 * hash + (this.protein != null ? this.protein.hashCode() : 0);
        hash = 97 * hash + (this.dataset != null ? this.dataset.hashCode() : 0);
        hash = 97 * hash + this.groupId;
        hash = 97 * hash + (this.groupMemberStatus != null ? this.groupMemberStatus.hashCode() : 0);
        hash = 97 * hash + (int) (Double.doubleToLongBits(this.mascotScore) ^ (Double.doubleToLongBits(this.mascotScore) >>> 32));
        hash = 97 * hash + (int) (Double.doubleToLongBits(this.paragonUnused) ^ (Double.doubleToLongBits(this.paragonUnused) >>> 32));
        hash = 97 * hash + (int) (Double.doubleToLongBits(this.paragonTotal) ^ (Double.doubleToLongBits(this.paragonTotal) >>> 32));
        return hash;
    }



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

    @Override
    public HashMap<String,Object> getColsAndValues() {
        HashMap<String,Object> map = new HashMap<String,Object>(5,1);
        map.put("GROUPID", this.groupId);
        map.put("GROUPMEMBERSTATUS", this.groupMemberStatus.getCode());
        map.put("MS_PROTSCORE", this.mascotScore);
//        map.put("PG_RANK", this.paragonRank);
        map.put("PG_UNUSED", this.paragonUnused);
        map.put("PG_TOTAL", this.paragonTotal);
//        map.put("PG_COV", this.paragonCov);
        return map;
    }    

}
