001/*
002 *                    BioJava development code
003 *
004 * This code may be freely distributed and modified under the
005 * terms of the GNU Lesser General Public Licence.  This should
006 * be distributed with the code.  If you do not have a copy,
007 * see:
008 *
009 *      http://www.gnu.org/copyleft/lesser.html
010 *
011 * Copyright for this code is held jointly by the individual
012 * authors.  These should be listed in @author doc comments.
013 *
014 * For more information on the BioJava project and its aims,
015 * or to join the biojava-l mailing list, visit the home page
016 * at:
017 *
018 *      http://www.biojava.org/
019 *
020 */
021
022package org.biojavax.bio.seq;
023import java.util.ArrayList;
024import java.util.Collection;
025import java.util.Iterator;
026import java.util.List;
027
028import org.biojava.bio.symbol.Location;
029import org.biojava.utils.ChangeVetoException;
030import org.biojavax.CrossRef;
031import org.biojavax.ontology.ComparableTerm;
032
033/**
034 * An implementation of RichLocation which possibly covers multiple locations, 
035 * on different strands, different circular lengths, or different sequences.
036 * @author Richard Holland
037 * @author Mark Schreiber
038 * @since 1.5
039 */
040public class MultiSourceCompoundRichLocation extends CompoundRichLocation implements RichLocation {
041    
042    /**
043     * Constructs a MultiSourceCompoundRichLocation from the given set of members, with
044     * the default term of "join". Note that you really shouldn't use this if
045     * you are unsure if your members set contains overlapping members. Use
046     * RichLocation.Tools.construct() instead. The members collection
047     * must only contain Location instances. Any that are not RichLocations will
048     * be converted using RichLocation.Tools.enrich().
049     * @param members the members to put into the compound location.
050     * @see RichLocation.Tools
051     */
052    public MultiSourceCompoundRichLocation(Collection members) { this(getJoinTerm(), members); }
053    
054    /**
055     * Constructs a MultiSourceCompoundRichLocation from the given set of members.
056     * Note that you really shouldn't use this if
057     * you are unsure if your members set contains overlapping members. Use
058     * RichLocation.Tools.construct(members) instead. The members collection
059     * must only contain Location instances. Any that are not RichLocations will
060     * be converted using RichLocation.Tools.enrich().
061     * @param term the term to use when describing the group of members.
062     * @param members the members to put into the compound location.
063     * @see RichLocation.Tools
064     */
065    public MultiSourceCompoundRichLocation(ComparableTerm term, Collection members) {
066        if (term==null) throw new IllegalArgumentException("Term cannot be null");
067        if (members==null || members.size()<2) throw new IllegalArgumentException("Must have at least two members");        
068        this.term = term;
069        this.members = new ArrayList();   
070        for (Iterator i = members.iterator(); i.hasNext(); ) {
071            // Convert each member into a RichLocation
072            Object o = i.next();
073            if (!(o instanceof RichLocation)) o = RichLocation.Tools.enrich((Location)o);
074            // Convert
075            RichLocation rl = (RichLocation)o;
076            // Add in member
077            this.members.add(rl);
078            // Update our size
079            this.size += Math.max(rl.getMin(),rl.getMax())-Math.min(rl.getMin(),rl.getMax());
080        }
081    }
082                   
083    /**
084     * {@inheritDoc}
085     * ALWAYS RETURNS NULL
086     */
087    public CrossRef getCrossRef() { return null; }
088            
089    /**
090     * {@inheritDoc}
091     * ALWAYS RETURNS ZERO
092     */
093    public int getCircularLength() { return 0; }
094    
095    /**
096     * {@inheritDoc}
097     * NOT IMPLEMENTED
098     * @throws ChangeVetoException ALWAYS
099     */
100    public void setCircularLength(int sourceSeqLength) throws ChangeVetoException {
101        if (sourceSeqLength>0) throw new ChangeVetoException("MultiSourceCompoundRichLocations cannot be circular");
102    }
103    
104    /**
105     * {@inheritDoc}
106     */
107    public Strand getStrand() { return Strand.UNKNOWN_STRAND; }
108    
109    /**
110     * {@inheritDoc}
111     * ALWAYS RETURNS ONE
112     */
113    public int getMin() { return 1; }
114    
115    /**
116     * {@inheritDoc}
117     * ALWAYS RETURNS COMBINED LENGTH OF MEMBERS
118     */
119    public int getMax() { return this.size; }
120    
121    /**
122     * {@inheritDoc}
123     * ALWAYS RETURNS A POINT POSITION AT POINT 1
124     */
125    public Position getMinPosition() { return new SimplePosition(false,false,1); }
126    
127    /**
128     * {@inheritDoc}
129     * ALWAYS RETURNS A POINT POSITION AT POINT EQUIVALENT TO COMBINED LENGTH OF MEMBERS
130     */
131    public Position getMaxPosition() { return new SimplePosition(false,false,this.size); }
132    
133    /**
134     * {@inheritDoc}
135     * Recursively translates all members of this location.
136     */
137    public Location translate(int dist) {
138        if (this.members.isEmpty()) return this;
139        List newmembers = new ArrayList();
140        for (Iterator i = this.members.iterator(); i.hasNext(); ) {
141            RichLocation rl = (RichLocation)i.next();
142            newmembers.add(rl.translate(dist));
143        }
144        return new MultiSourceCompoundRichLocation(this.getTerm(),newmembers);
145    }    
146}
147