/*
 * Created on Jan 15, 2004
 *
 * To change the template for this generated file go to
 * Window&gt;Preferences&gt;Java&gt;Code Generation&gt;Code and Comments
 */

/*
 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.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import calhoun.gebo.db.EditManager;
import calhoun.gebo.model.CompoundFeature;
import calhoun.gebo.model.CurationFlag;
import calhoun.gebo.model.Feature;
import calhoun.gebo.model.FeatureTrack;
import calhoun.gebo.model.Property;
import calhoun.gebo.model.Segment;
import calhoun.gebo.model.Sequence;
import calhoun.gebo.model.SimpleSegment;
import calhoun.gebo.model.Strand;
import calhoun.gebo.util.Informer;
import calhoun.gebo.util.Q;

/**
 * @author reinhard
 * 
 * CalhounDB specific stuff must go in here from now on. calhoun.model.Feature
 * is too crowded as is.
 */
public class CalhounFeature extends CompoundFeature {

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

    /**
     * @param sequence
     * @param label
     * @param id
     * @param start
     * @param stop
     * @param track
     * @param strand
     * @param updatable
     * @param deletable
     * @param editFlag
     */
    public CalhounFeature(Sequence sequence, FeatureTrack track,
            ResultSet resultSet, boolean updatable, boolean deletable,
            int editFlag) throws SQLException {
        super(sequence, buildLabel(resultSet.getString("AP_NAME"), resultSet
                .getString("AP_ASSIGNED_ID")), resultSet
                .getString("AP_FEATURE_ID"), resultSet.getInt("AP_START"),
                resultSet.getInt("AP_STOP"), track, Strand
                        .parseStrand(resultSet.getString("AP_STRAND")),
                updatable, deletable, editFlag);
        // CalhounTrackManager.getInstance().addResultSetProperties(
        // resultSet,
        // this);
    }

    private static String buildLabel(String name, String assignedId) {
        if (name == null) {
            return assignedId;
        } else if (assignedId == null) {
            return name;
        }
        return name + " (" + assignedId + ")";
    }

    public CalhounFeature(Sequence sequence, String label, String id,
            int start, int stop, FeatureTrack track, Strand strand,
            boolean updateable, boolean deletable, int editFlag) {
        super(sequence, label, id, start, stop, track, strand, updateable,
                deletable, editFlag);

    }

    public Property[] getProperties() {
        List propertyList = new ArrayList();
        Property[] superProperties = super.getProperties();
        for (int i = 0; i < superProperties.length; i++) {
            propertyList.add(superProperties[i]);
        }
        return (Property[]) propertyList.toArray(new Property[0]);
    }

    public Property getProperty(String key) {

        if (key.equals("ALIGNMENT") || key.equals("CONSENSUS")) {
            return new Property(key, CalhounTrackManager.getInstance().getClob(
                    this, key));
        } else if (key.equals(AP.FEATURE_ID)) {
            if (getEditFlag() == EditManager.INSERT_FLAG) {
                return new Property(key, "");
            } else {
                return new Property(key, getId());
            }
        }
        return super.getProperty(key);
    }

    public CalhounTrack getCalhounTrack() {
        return (CalhounTrack) getTrack();
    }

    /**
     * Override because SimpleSegment logic doesn't cut it.
     * 
     * @return a <code>String</code> value
     */
    public String getLabel() {
        if (m_track.getDesignerLabelComponents() == null) {
            return m_label == null ? "" : m_label;
        } else {
            String[] components = m_track.getDesignerLabelComponents();
            StringBuffer labelBuffer = new StringBuffer();
            for (int i = 0; i < components.length; i++) {
                if (m_track.hasCriterion(components[i])) {
                    if (components[i].equals(AP.LENGTH)) {
                        labelBuffer.append(this.getLength() + "");
                    } else if (hasProperty(components[i])) {
                        labelBuffer
                                .append((String) getPropertyValue(components[i]));
                    } else {
                        // U.println("REINOS: this field of feature " + getId()
                        // + " bypassed the cache: " + components[i]);
                        labelBuffer.append(getPropertyValue(components[i]));
                    }
                } else {
                    labelBuffer.append(components[i]);
                }
            }
            return labelBuffer.toString();
        }
    }

    public CurationFlag[] getCurationFlags() {
        if (m_curationFlags == null && existsInDB()) {
            setCurationFlags(getCurationFlagsFromDB());
        }
        return m_curationFlags;
    }

    public void setCurationFlags(CurationFlag[] curationFlags) {
        m_curationFlags = curationFlags;
        StringBuffer joinedCurationFlags = new StringBuffer();
        StringBuffer joinedCurationFlagIds = new StringBuffer();
        for (int i = 0; i < m_curationFlags.length; i++) {
            joinedCurationFlags.append(m_curationFlags[i].getLabel());
            joinedCurationFlagIds.append(m_curationFlags[i].getId());
            if (i + 1 < m_curationFlags.length) {
                joinedCurationFlags.append("; ");
                joinedCurationFlagIds.append("#");
            }
        }
        setProperty("CURATION_FLAGS", joinedCurationFlags.toString());
        setProperty(AP.CURATION_FLAG_IDS, joinedCurationFlagIds.toString());
    }

    protected void restoreCurationFlags() {
        String value = getPropertyValue(AP.CURATION_FLAG_IDS);
        if (value == null) {
            value = "";
        }
        String[] curationFlagIds = value.split("\\#");
        CurationFlag[] curationFlags = getTM().getCurationFlags(getCellType());
        List curationFlagList = new ArrayList();
        // I.warn("restoreCurationFlags: " +
        // getPropertyValue(AP.CURATION_FLAG_IDS));
        // I.warn("length: " + curationFlagIds.length);
        for (int i = 0; i < curationFlagIds.length; i++) {
            for (int j = 0; j < curationFlags.length; j++) {
                if (curationFlagIds[i].equals(curationFlags[j].getId())) {
                    curationFlagList.add(curationFlags[j]);
                }
            }
        }
        setCurationFlags((CurationFlag[]) curationFlagList
                .toArray(new CurationFlag[0]));
    }

    protected CurationFlag[] getCurationFlagsFromDB() {
        List curationFlagList = new ArrayList();
        String sql = " select F.ap_curation_flag_group_name,F.ap_curation_flag_name,F.ap_id "
                + " from"
                + " ap_curation_flag_view F,"
                + " ap_transcript_curation T"
                + " where "
                + " T.ap_curation_flag_id = F.ap_id "
                + " and "
                + " T.ap_transcript_feature_id = ?"
                + " order by ap_curation_flag_group_name,ap_curation_flag_name";
        try {
            Q.startStopWatch(sql);
            PreparedStatement statement = getConnection().prepareStatement(sql);
            statement.setLong(1, Long.parseLong(getId()));
            ResultSet resultSet = statement.executeQuery();
            StringBuffer cosmeticBuffer = new StringBuffer();
            StringBuffer idBuffer = new StringBuffer();
            int i = 0;
            while (resultSet.next()) {
                String group = resultSet.getString(1);
                String flag = resultSet.getString(2);
                String id = resultSet.getString(3);
                String label = flag.equals(" ") ? group : group + ": " + flag;
                curationFlagList.add(new CurationFlag(id, label));
            }
            statement.close();
            resultSet.close();
        } catch (SQLException e) {
            I
                    .error("Unable to get curation flags for feature!\nsql: "
                            + sql, e);
        } finally {
            Q.stopStopWatch(sql);
        }
        return (CurationFlag[]) curationFlagList.toArray(new CurationFlag[0]);
    }

    public boolean hasAltSegment() {
        return hasProperty(AP.ALT_SEQUENCE_ID)
                && getPropertyValue(AP.ALT_SEQUENCE_ID) != null;
    }

    public Segment getAltSegment() {
        if (hasAltSegment()) {
            Sequence altSequence = CalhounSequenceManager.getInstance()
                    .getSequence(getPropertyValue(AP.ALT_SEQUENCE_ID));
            int altStart = Integer.parseInt(getPropertyValue(AP.ALT_START));
            int altStop = Integer.parseInt(getPropertyValue(AP.ALT_STOP));
            Segment segment = new SimpleSegment(altSequence, altStart, altStop);
            return segment;
        }
        return null;
    }

    public boolean hasAltFeature() {
        return hasProperty(AP.ALT_FEATURE_ID)
                && getPropertyValue(AP.ALT_FEATURE_ID) != null;
    }

    public Feature getAltFeature() {
        if (hasAltFeature()) {
            Feature altFeature = CalhounFeatureFinder.getInstance()
                    .getFeature(getPropertyValue(AP.ALT_FEATURE_ID));
            return altFeature;
        }
        return null;
    }

    public String getCellType() {
        return "?";
    }
    
    protected CalhounTrackManager getTM() {
        return CalhounTrackManager.getInstance();
    }

    protected boolean existsInDB() {
        return getEditFlag() != EditManager.INSERT_FLAG;
    }

    protected Connection getConnection() {
        return CalhounConnectionManager.getInstance().getConnection();
    }

    private CurationFlag[] m_curationFlags;
}
