/*
 The Broad Institute
 SOFTWARE COPYRIGHT NOTICE AGREEMENT
 This software and its documentation are copyright (2006) by the
 Broad Institute/Massachusetts Institute of Technology. All rights are
 reserved.

 This software is supplied without any warranty or guaranteed support
 whatsoever. Neither the Broad Institute nor MIT can be responsible for its
 use, misuse, or functionality.
 */

package calhoun.gebo.internal.db;

import java.awt.Color;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import calhoun.gebo.api.TrackManager;
import calhoun.gebo.model.FeatureLink;
import calhoun.gebo.model.FeatureTrack;
import calhoun.gebo.model.Identified;
import calhoun.gebo.ui.TrackStyle;
import calhoun.gebo.util.Informer;

/**
 * Subclass of TrackModel with extra fields for storing info about tables and
 * views.
 * 
 * @author Reinhard Engels
 */

public class CalhounTrack extends FeatureTrack {

    private static Informer I = new Informer(CalhounTrack.class);

    // //////////////////////////////////////////////////////////////////////////
    // Constructors.
    // //////////////////////////////////////////////////////////////////////////

    private CalhounTrack(CalhounTrackType trackType, String analysisEventId,
            String label, int version, String notes) {
        this(trackType, trackType.getSubclass(), trackType.getOntologyTerm(),
                analysisEventId, label, version, notes);
    }

    CalhounTrack(TrackManager trackManager, String id, String label,
            Color color, boolean updatable, boolean deletable,
            boolean defaultVisible, int sortKey, String prefNode) {
        super(trackManager, id, label, color, updatable, deletable,
                defaultVisible, sortKey, prefNode, true);
    }

    private CalhounTrack(CalhounTrackType trackType, String subclass,
            Identified ontologyTerm, String analysisEventId, String label,
            int version, String notes) {
        super(trackType.getTrackManager(), buildId(trackType, analysisEventId),
                label, trackType.getColor(), false, false, true, trackType
                        .getSortKey(), buildId(trackType, analysisEventId),
                true);
        m_version = version;
        m_trackType = trackType;
        m_analysisEventId = analysisEventId;
        m_notes = notes;
        // annoying that we need these here as well, but necessary for generic
        // track type.
        m_ontologyTerm = ontologyTerm;
        m_subclass = subclass;
        if (m_subclass != null) {
            if (m_subclass.equals("VF")) {
                m_style = TrackStyle.LINE;
            } else if (m_subclass.equals("MALSPN")) {
                m_style = TrackStyle.ALIGNED_SEQUENCE;
            }
        }
        loadDensityAndComboPrefs();
    }

    public static CalhounTrack intern(CalhounTrackType trackType,
            String subclass, Identified ontologyTerm, String analysisEventId) {
        // this is a hack.
        return intern(trackType, subclass, ontologyTerm, analysisEventId, null,
                0, null);
    }

    public static CalhounTrack intern(CalhounTrackType trackType,
            String subclass, Identified ontologyTerm, String analysisEventId,
            String label, int version, String notes) {
        String id = buildId(trackType, analysisEventId);
      //  I.warn("Interning track  id: " + id + " subclass: " + subclass);
        if (!INTERN_MAP.containsKey(id)) {
            INTERN_MAP.put(id, new CalhounTrack(trackType, subclass,
                    ontologyTerm, analysisEventId, label, version, notes));
        }
        CalhounTrack track = (CalhounTrack) INTERN_MAP.get(id);
        if (label != null && !label.equals("")) {
            track.setLabel(label);
            track.m_version = version;
            track.m_notes = notes;
        }
        return track;
    }

    public CalhounTrackManager getCalhounTrackManager() {
        return (CalhounTrackManager) getTrackManager();
    }

    public static String buildId(CalhounTrackType trackType,
            String analysisEventId) {
        if (trackType == null) {
            I.error("null trackType for analysisEventId " + analysisEventId);
            return null;
        }
        return trackType.getId() + "_" + analysisEventId;
    }

    public String getSubclass() {
        return m_subclass;
    }

    public Identified getOntologyTerm() {
        return m_ontologyTerm;
    }

    public void loadPrefs() {
        super.loadPrefs();
        loadDensityAndComboPrefs();
    }

    // //////////////////////////////////////////////////////////////////////////
    // Cloneable Interface. is this necessary for density stuff?
    // //////////////////////////////////////////////////////////////////////////

    // public Object clone() {
    // Object clone = null;
    // // try {
    // clone = super.clone();
    // // } catch (CloneNotSupportedException e) {
    // // I.error("This can't happen, right?");
    // // }
    // return clone;
    // }



    public static String getDbSubclass(String beanSubclass) {
        if (SUBCLASS_MAP == null) {
            SUBCLASS_MAP = new HashMap();
            SUBCLASS_MAP.put("AlignmentSegment", "ALSEG");
            SUBCLASS_MAP.put("AlignmentSpan", "ALSPN");
            SUBCLASS_MAP.put("AnnotatedTranscript", "ANTRS");
            SUBCLASS_MAP.put("BlastAlignment", "BALGN");
            SUBCLASS_MAP.put("BlastCluster", "BCLUST");
            SUBCLASS_MAP.put("CovariantModelHit", "CMHIT");
            SUBCLASS_MAP.put("ContigFeature", "CTG");
            SUBCLASS_MAP.put("EndRead", "ENDRD");
            SUBCLASS_MAP.put("Exon", "EXON");
            SUBCLASS_MAP.put("Feature", "FTRE");
            SUBCLASS_MAP.put("Gene", "EGENE");
            SUBCLASS_MAP.put("GenericFeature", "GFTR");
            SUBCLASS_MAP.put("GlimmerOrf", "GLMORF");
            SUBCLASS_MAP.put("HmmerHit", "HMMHIT");
            SUBCLASS_MAP.put("HQD", "HQD");
            SUBCLASS_MAP.put("MissingPartner", "MSP");
            SUBCLASS_MAP.put("MultiAlignmentSpan", "MALSPN");
            SUBCLASS_MAP.put("Nqs", "NQS");
            SUBCLASS_MAP.put("NqsBitmap", "NQSB");
            SUBCLASS_MAP.put("PolymorphicSite", "POLYS");
            SUBCLASS_MAP.put("ProGene", "PGENE");
            SUBCLASS_MAP.put("Repeat", "RPT");
            SUBCLASS_MAP.put("RepeatCluster", "RepeatCluster");
            SUBCLASS_MAP.put("RepeatElement", "RPTELT");
            SUBCLASS_MAP.put("RepeatRegion", "RPTREG");
            SUBCLASS_MAP.put("Snp", "SNP");
            SUBCLASS_MAP.put("TandemRepeat", "TNDM");
            SUBCLASS_MAP.put("Transcript", "TRNSCR");
            SUBCLASS_MAP.put("TranscriptAdjustment","TRNSCRADJ");
            SUBCLASS_MAP.put("TrnascanHit", "TRNAH");
            SUBCLASS_MAP.put("ValuedFeature", "VF");
            SUBCLASS_MAP.put("UtrElement", "UTR");
        }
        if (SUBCLASS_MAP.containsKey(beanSubclass)) {
            return (String) SUBCLASS_MAP.get(beanSubclass);
        }
        I.error("Uanable to find discriminator value for subclass '"
                + beanSubclass + "' Defaulting to '"
                + calhoun.bean.Feature.DISCRIMINATOR_VALUE + "'");
        return calhoun.bean.Feature.DISCRIMINATOR_VALUE;
    }

    // //////////////////////////////////////////////////////////////////////////
    // Track Interface.
    // //////////////////////////////////////////////////////////////////////////

    /**
     * See getCompement in parent.
     * 
     * @param label
     *            a <code>String</code> value
     * @return a <code>TrackModel</code> value
     */
    public FeatureTrack getComponentTrack(String label) {
        if (m_componentTrack == null) {
            if (label == null) {
                label = m_id;
            }
            m_componentTrack = new CalhounTrack(m_trackType
                    .getComponentTrackType(), getId() + "_COMPONENT",
                    getLabel() + "_COMPONENT", 0, null);
            m_componentTrack.setSuperTrack(this);
            if (this.getTrackType() != null
                    && this.getTrackType().getSubclass() != null
                    && this.getTrackType().getSubclass().equals("BCLUST")) {
                // I.warn("REINOS: adding featurelink to BCLUST component
                // track");
                if (this.getFeatureLink() != null) {
                    m_componentTrack.setFeatureLink(new FeatureLink(
                            m_componentTrack, this.getFeatureLink()
                                    .getTemplate()));
                }
            } else {
                // I.warn("REINOS: *");
            }
        }
        m_componentTrack.setPrefsEnabled(false);
        return m_componentTrack;
    }

    public void setDesignerLabelComponents(String[] components) {
        super.setDesignerLabelComponents(components);
        buildDesignerLabelColumnNames();
    }

    // //////////////////////////////////////////////////////////////////////////
    // Other Public Methods.
    // //////////////////////////////////////////////////////////////////////////

    public int getVersion() {
        return m_version;
    }

    protected String[] getExtraDesignerLabelColumnNames() {
        if (m_extraDesignerLabelColumnNames == null) {
            buildDesignerLabelColumnNames();
        }
        return m_extraDesignerLabelColumnNames;
    }

    protected String[] getCommonDesignerLabelColumnNames() {
        if (m_commonDesignerLabelColumnNames == null) {
            buildDesignerLabelColumnNames();
        }
        return m_commonDesignerLabelColumnNames;
    }

    private void buildDesignerLabelColumnNames() {
        List extraList = new ArrayList();
        List commonList = new ArrayList();
        String[] designerLabelComponents = getDesignerLabelComponents();
        if (designerLabelComponents != null) {
            for (int i = 0; i < designerLabelComponents.length; i++) {
                if (hasCriterion(designerLabelComponents[i])) {
                    if (designerLabelComponents[i]
                            .matches("FEATURE_ID|START|STOP|LABEL|STRAND")) {
                        commonList.add(designerLabelComponents[i]);
                    } else {
                        extraList.add(designerLabelComponents[i]);
                    }

                }
            }
        }
        m_commonDesignerLabelColumnNames = (String[]) commonList
                .toArray(new String[0]);
        m_extraDesignerLabelColumnNames = (String[]) extraList
                .toArray(new String[0]);
    }

    public String getNotes() {
        return m_notes;
    }

    public String getAnalysisEventId() {
        return m_analysisEventId;
    }

    public CalhounTrackType getTrackType() {
        return m_trackType;
    }

    // MutliAlignment stuff.

    public boolean isExplodedMultiAlignmentSpanTrack() {
        return m_explodedMultiAlignmentSpanTrack;
    }

    public void setExplodedMultiAlignmentSpanTrack(
            boolean explodedMultiAlignmentSpan) {
        m_explodedMultiAlignmentSpanTrack = explodedMultiAlignmentSpan;
    }

    // RangeTrack Methods

    public CalhounRangeTrack getRangeTrack() {
        if (m_rangeTrack == null) {
            m_rangeTrack = new CalhounRangeTrack(this);
        }
        return m_rangeTrack;
    }




    public void setTemplateTrack(CalhounTrack templateTrack) {
        m_templateTrack = templateTrack;
    }

    public CalhounTrack getTemplateTrack() {
        return m_templateTrack;
    }

    public String getBioSampleId() {
        return m_bioSampleId;
    }

    public void setBioSampleId(String bioSampleId) {
        m_bioSampleId = bioSampleId;
    }

    public boolean isBioSampleTrack() {
        return m_isBioSampleTrack;
    }

    public void setBioSampleTrack(boolean b) {
        m_isBioSampleTrack = b;
    }

    public void setParentAnalysisEventId(String parentAnalysisEventId) {
        m_parentAnalysisEventId = parentAnalysisEventId;
    }

    public String getParentAnalysisEventId() {
        return m_parentAnalysisEventId;
    }

    // //////////////////////////////////////////////////////////////////////////
    // Data.
    // //////////////////////////////////////////////////////////////////////////

    private String m_parentAnalysisEventId;
    private CalhounTrack m_templateTrack;
    private boolean m_explodedMultiAlignmentSpanTrack;
    private String m_bioSampleId;
    private boolean m_isBioSampleTrack;
    private CalhounRangeTrack m_rangeTrack;

    private static Map SUBCLASS_MAP;

    protected String m_subclass;
    protected Identified m_ontologyTerm;
    protected String m_notes;
    protected int m_version;
    private static Map INTERN_MAP = new HashMap();
    protected String m_analysisEventId;
    protected CalhounTrackType m_trackType;
    private String[] m_extraDesignerLabelColumnNames;
    private String[] m_commonDesignerLabelColumnNames;
}