package org.genemania.dw.entity;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.TreeMap;
import org.genemania.dw.db.EntrezMirrorTables;
import org.genemania.dw.util.DWUtil;
import org.genemania.dw.util.GenUtil;

/**
 * DW view for an Entrez gene. Encapsulates the attributes of interest
 * for an Entrez gene.
 * Overriden toString () method lists Ensembl X-ref (but all possible syns),
 * and it can represent an entry in the ID mapping tables. Other toString () 
 * flavors are good for Entrez based ID mapping. toStringLeftOver () method
 * is good for the Entrez left overs in an X-Entrez ID mapping file.
 * GI list not currently part of any toString () methods.
 * @author rashadbadrawi
 */

public class EntrezGene extends ExtResourceGene {
    
    private ArrayList <String> refSeqRNAList = new ArrayList <String> ();
    private ArrayList <String> refSeqProList = new ArrayList <String> ();
    
    public EntrezGene () {
    
        setSource(ExtResourceGene.RES_ENTREZ);
    }
    
    public static TreeMap <String, ExtResource> loadAllExt (String speciesName)
            throws SQLException {

        TreeMap <String, ExtResource> entMap =
                                        EntrezMirrorTables.loadAll(speciesName);

        return entMap;
    }

    public static ArrayList <ExtResourceGene> replaceGene 
                  (ExtResourceGene oldEntGene) throws RuntimeException {

        try {
            return EntrezMirrorTables.replaceGene(oldEntGene);
        } catch (SQLException sqlEx) {
            throw new RuntimeException (sqlEx);
        }
    }

    public static ArrayList <String> replaceGeneID
                  (ExtResourceGene oldEntGene) throws RuntimeException {

        try {
            return EntrezMirrorTables.replaceGeneID (oldEntGene);
        } catch (SQLException sqlEx) {
            throw new RuntimeException (sqlEx);
        }
    }
        
    public void addRefSeqRNAID (String refSeqRNAID) {
    
        GenUtil.validateString (refSeqRNAID);
        if (!refSeqRNAList.contains (refSeqRNAID)) {
            refSeqRNAList.add (refSeqRNAID);
        }
    }

    public void removeRefSeqRNAID (String refSeqRNAID) {

        GenUtil.validateString(refSeqRNAID);
        if (refSeqRNAList.contains (refSeqRNAID)) {
            refSeqRNAList.remove (refSeqRNAID);
        } else {
            System.out.println ("removeRefSeqRNAID: No such ID: " + refSeqRNAID);
        }
    }
    
    public void addRefSeqProID (String refSeqProID) {
    
        GenUtil.validateString (refSeqProID);
        if (!refSeqProList.contains (refSeqProID)) {
            refSeqProList.add (refSeqProID);
        }
    }

    public void removeRefSeqProID (String refSeqProID) {

        GenUtil.validateString(refSeqProID);
        if (refSeqProList.contains (refSeqProID)) {
            refSeqProList.remove (refSeqProID);
        } else {
            System.out.println ("removeRefSeqProID: No such ID: " + refSeqProID);
        }
    }

    public ArrayList <String> getRefSeqRNAList () { return refSeqRNAList; }
    
    public ArrayList <String> getRefSeqProList () { return refSeqProList; }
    
    @Override
    public String toString () {
        
        String tempStr = getDBID() + "";
        tempStr += GenUtil.TAB;
        
        tempStr += getID();
        tempStr += GenUtil.TAB;
        
        if (TYPE_PROTEIN_CODING_ENTREZ.equals (getType ())) {
            tempStr += "True";
        } else {
            tempStr += "False";
        }
        tempStr += GenUtil.TAB;
        
        if (getName() != null) {
            tempStr += getName ();
        } else {
            tempStr += GenUtil.NA;
        }
        tempStr += GenUtil.TAB;
        
        tempStr = GenUtil.addList (tempStr, getUniprotList());
        tempStr += GenUtil.TAB;

        if (DWUtil.SP_MOUSE.equals (speciesName)) {
            tempStr = GenUtil.addList (tempStr, getMGDList());
            tempStr += GenUtil.TAB;
        }
        
        TreeMap <String, ExtResource> xRefEnsemblMap = 
                getXRef (ExtResource.RES_ENSEMBL);
        if (xRefEnsemblMap == null || xRefEnsemblMap.size () == 0) {
            tempStr += GenUtil.NA;
        } else {
            Iterator iterator = xRefEnsemblMap.keySet().iterator();
            boolean firstTime = true;
            while (iterator.hasNext ()) {
                String ensGeneID = (String)iterator.next ();
                tempStr += ensGeneID;
                if (firstTime) {
                    firstTime = false;
                } else {
                    tempStr += GenUtil.SEMICOLON; 
                }
            }
        }
        tempStr += GenUtil.TAB;
        
        tempStr = GenUtil.addList (tempStr, getRefSeqRNAList());
        tempStr += GenUtil.TAB;
        
        tempStr = GenUtil.addList (tempStr, getRefSeqProList());
        tempStr += GenUtil.TAB;
       
        tempStr = GenUtil.addList (tempStr, getRefinedSynList());
        tempStr += GenUtil.TAB;
        
        if (getDefinition() != null) {
            tempStr += getDefinition();
        } else {
            tempStr += GenUtil.NA;
        }
        
        return tempStr;
    }

    public String toStringTAIR () {
        
        return toStringBuild (true);
    }
    
    public String toStringEcoli () {
     
        return toStringBuild (false);
    }
    
    //helper method
    private String toStringBuild (boolean xRefTair) {
        
        String tempStr = getDBID() + "";
        tempStr += GenUtil.TAB;
        
        tempStr += getID();
        tempStr += GenUtil.TAB;
        
        if (TYPE_PROTEIN_CODING_ENTREZ.equals (getType ())) {
            tempStr += "True";
        } else {
            tempStr += "False";
        }
        tempStr += GenUtil.TAB;
        
        if (getName() != null) {
            tempStr += getName ();
        } else {
            tempStr += GenUtil.NA;
        }
        tempStr += GenUtil.TAB;
        
        tempStr = GenUtil.addList (tempStr, getUniprotList());
        tempStr += GenUtil.TAB;

        //not needed for now, since method is only used for TAIR & Ecoli
        /*if (DWUtil.SP_MOUSE.equals (speciesName)) {
            tempStr = GenUtil.addList (tempStr, getMGDList());
            tempStr += GenUtil.TAB;
        }*/
        
        if (xRefTair == true) {
            TreeMap <String, ExtResource> xRefTAIRMap = 
                    getXRef (ExtResource.RES_TAIR);
            if (xRefTAIRMap == null || xRefTAIRMap.size () == 0) {
                tempStr += GenUtil.NA;
            } else {
                Iterator iterator = xRefTAIRMap.keySet().iterator();
                boolean firstTime = true;
                while (iterator.hasNext ()) {
                    String tGeneID = (String)iterator.next ();
                    tempStr += tGeneID;
                    if (firstTime) {
                        firstTime = false;
                    } else {
                        tempStr += GenUtil.SEMICOLON; 
                    }
                }
            }
            tempStr += GenUtil.TAB;
        }
        
        tempStr = GenUtil.addList (tempStr, getRefSeqRNAList());
        tempStr += GenUtil.TAB;
        
        tempStr = GenUtil.addList (tempStr, getRefSeqProList());
        tempStr += GenUtil.TAB;
        
        tempStr = GenUtil.addList (tempStr, getRefinedSynList());
        tempStr += GenUtil.TAB;
        
        if (getDefinition() != null) {
            tempStr += getDefinition();
        } else {
            tempStr += GenUtil.NA;
        }
                
        return tempStr;
    }

    public String toStringLeftOver (String xRefType) {

        if (ExtResourceGene.RES_ENSEMBL.equals (xRefType)) {
            return toStringLeftOverEns ();
        } else if (ExtResourceGene.RES_TAIR.equals (xRefType)) {
            return toStringLeftOverTAIR ();
        } else {
            throw new IllegalArgumentException ("No support for leftovers for: "
                    + xRefType);
        }
    }

    private String toStringLeftOverEns () {

        String tempStr = getDBID() + "";
        tempStr += GenUtil.TAB;

        tempStr += GenUtil.NA;                //Ensembl Gene ID col
        tempStr += GenUtil.TAB;

        if (TYPE_PROTEIN_CODING_ENTREZ.equals (getType ())) {
            tempStr += "True";
        } else {
            tempStr += "False";
        }
        tempStr += GenUtil.TAB;

        if (getName() != null) {
            tempStr += getName ();
        } else {
            tempStr += GenUtil.NA;
        }
        tempStr += GenUtil.TAB;

        tempStr += GenUtil.NA;                //Ensembl Transcript IDs col
        tempStr += GenUtil.TAB;

        tempStr += GenUtil.NA;                //Ensembl Protein IDs col
        tempStr += GenUtil.TAB;

        tempStr = GenUtil.addList (tempStr, getUniprotList());
        tempStr += GenUtil.TAB;

        if (DWUtil.SP_MOUSE.equals (speciesName)) {
            tempStr = GenUtil.addList (tempStr, getMGDList());
            tempStr += GenUtil.TAB;
        }

        tempStr += getID();
        tempStr += GenUtil.TAB;

        tempStr = GenUtil.addList (tempStr, getRefSeqRNAList());
        tempStr += GenUtil.TAB;

        tempStr = GenUtil.addList (tempStr, getRefSeqProList());
        tempStr += GenUtil.TAB;

        //tempStr = GenUtil.addList (tempStr, getRefinedSynList());
        tempStr = GenUtil.addList (tempStr, getSynList());
        tempStr += GenUtil.TAB;

        if (getDefinition() != null) {
            tempStr += getDefinition();
        } else {
            tempStr += GenUtil.NA;
        }

        return tempStr;
    }

    private String toStringLeftOverTAIR () {

        String tempStr = getDBID() + "";
        tempStr += GenUtil.TAB;

        tempStr += GenUtil.NA;
        tempStr += GenUtil.TAB;

        if (TYPE_PROTEIN_CODING_ENTREZ.equals (getType ())) {
            tempStr += "True";
        } else {
            tempStr += "False";
        }
        tempStr += GenUtil.TAB;

        if (getName() != null) {
            tempStr += getName ();
        } else {
            tempStr += GenUtil.NA;
        }
        tempStr += GenUtil.TAB;

        tempStr = GenUtil.addList (tempStr, getUniprotList());
        tempStr += GenUtil.TAB;

        tempStr += getID();
        tempStr += GenUtil.TAB;

        tempStr = GenUtil.addList (tempStr, getRefSeqRNAList());
        tempStr += GenUtil.TAB;

        tempStr = GenUtil.addList (tempStr, getRefSeqProList());
        tempStr += GenUtil.TAB;

        tempStr = GenUtil.addList (tempStr, getRefinedSynList());
        tempStr += GenUtil.TAB;

        if (getDefinition() != null) {
            tempStr += getDefinition();
        } else {
            tempStr += GenUtil.NA;
        }

        return tempStr;
    }
}
