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 */
021package org.biojava.nbio.structure.align.multiple;
022
023import java.io.Serializable;
024import java.util.ArrayList;
025import java.util.List;
026
027import org.biojava.nbio.structure.align.multiple.util.MultipleAlignmentTools;
028
029/**
030 * General implementation of a {@link Block} that supports any type of
031 * sequential alignment with gaps.
032 *
033 * @author Aleix Lafita
034 * @since 4.1.0
035 *
036 */
037public class BlockImpl extends AbstractScoresCache implements Serializable,
038                Block, Cloneable {
039
040        private static final long serialVersionUID = -5804042669466177641L;
041
042        private BlockSet parent;
043        private List<List<Integer>> alignRes;
044
045        // CACHE
046        private int coreLength;
047        private List<Integer> alignResCounts;
048
049        /**
050         * Constructor. Links also the parent to this instance, by adding the Block
051         * to the parent's list.
052         *
053         * @param blockSet
054         *            the parent BlockSet of the BlockImpl instance.
055         * @return BlockImpl a BlockImpl instance linked to its parent BlockSet.
056         */
057        public BlockImpl(BlockSet blockSet) {
058
059                parent = blockSet;
060                if (parent != null)
061                        parent.getBlocks().add(this);
062                alignRes = null;
063                coreLength = -1; // Value -1 indicates not yet calculated.
064                alignResCounts = null; // Value null not yet calculated
065        }
066
067        /**
068         * Copy constructor.
069         *
070         * @param b
071         *            BlockImpl object to be copied.
072         * @return BlockImpl an identical copy of the input BlockImpl object.
073         */
074        public BlockImpl(BlockImpl b) {
075
076                super(b); // This copies the cached scores
077                this.parent = b.parent;
078                this.coreLength = b.coreLength;
079
080                this.alignRes = null;
081                if (b.alignRes != null) {
082                        // Make a deep copy of everything
083                        alignRes = new ArrayList<List<Integer>>();
084                        for (int k = 0; k < b.size(); k++) {
085                                alignRes.add(new ArrayList<Integer>(b.alignRes.get(k)));
086                        }
087                }
088        }
089
090        @Override
091        public Block clone() {
092                return new BlockImpl(this);
093        }
094
095        @Override
096        public void clear() {
097                super.clear();
098                coreLength = -1;
099                alignResCounts = null;
100        }
101
102        @Override
103        public String toString() {
104                return "BlockImpl [alignRes=" + alignRes + ", coreLength=" + coreLength
105                                + "]";
106        }
107
108        @Override
109        public void setBlockSet(BlockSet parent) {
110                this.parent = parent;
111        }
112
113        @Override
114        public BlockSet getBlockSet() {
115                return parent;
116        }
117
118        @Override
119        public List<List<Integer>> getAlignRes() {
120                return alignRes;
121        }
122
123        @Override
124        public void setAlignRes(List<List<Integer>> alignRes) {
125                this.alignRes = alignRes;
126        }
127
128        @Override
129        public int length() {
130                if (alignRes == null)
131                        return 0;
132                if (alignRes.size() == 0)
133                        return 0;
134                return alignRes.get(0).size();
135        }
136
137        @Override
138        public int size() {
139                return alignRes.size();
140        }
141
142        @Override
143        public int getCoreLength() {
144                if (coreLength == -1)
145                        updateCoreLength();
146                return coreLength;
147        }
148
149        protected void updateCoreLength() {
150                coreLength = MultipleAlignmentTools.getCorePositions(this).size();
151        }
152
153        @Override
154        public int getStartIndex(int str) {
155                int index = -1;
156                Integer start = null;
157                while (start == null && index < alignRes.get(str).size()) {
158                        index++;
159                        start = alignRes.get(str).get(index);
160                }
161                return index;
162        }
163
164        @Override
165        public int getStartResidue(int str) {
166                return alignRes.get(str).get(getStartIndex(str));
167        }
168
169        @Override
170        public int getFinalIndex(int str) {
171                int index = alignRes.get(str).size();
172                Integer end = null;
173                while (end == null && index >= 0) {
174                        index--;
175                        end = alignRes.get(str).get(index);
176                }
177                return index;
178        }
179
180        @Override
181        public int getFinalResidue(int str) {
182                return alignRes.get(str).get(getFinalIndex(str));
183        }
184
185        @Override
186        public List<Integer> getAlignResCounts() {
187
188                if (alignResCounts != null)
189                        return alignResCounts;
190
191                alignResCounts = new ArrayList<Integer>(size());
192                for (int s = 0; s < size(); s++) {
193                        int count = 0;
194                        for (int r = 0; r < length(); r++) {
195                                if (alignRes.get(s).get(r) != null)
196                                        count++;
197                        }
198                        alignResCounts.add(count);
199                }
200                return alignResCounts;
201        }
202
203}