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 javax.vecmath.Matrix4d;
028
029/**
030 * A general implementation of a BlockSet to store a flexible part of a multiple
031 * alignment.
032 *
033 * @author Aleix Lafita
034 * @since 4.1.0
035 *
036 */
037public class BlockSetImpl extends AbstractScoresCache implements Serializable,
038                BlockSet, Cloneable {
039
040        private static final long serialVersionUID = -1015791986000076089L;
041
042        // Member variables
043        private MultipleAlignment parent;
044        private List<Block> blocks;
045
046        // Cache variables (can be updated)
047        private List<Matrix4d> pose; // Transformation matrices
048        private int length;
049        private int coreLength;
050        private List<Integer> alignResCounts;
051
052        /**
053         * Constructor. Links also the parent to this instance by adding the
054         * BlockSet to the parent's List.
055         *
056         * @param alignment
057         *            MultipleAlignment parent of the BlockSet.
058         */
059        public BlockSetImpl(MultipleAlignment alignment) {
060
061                parent = alignment;
062                if (parent != null)
063                        parent.getBlockSets().add(this);
064                blocks = null;
065
066                pose = null;
067                length = -1; // Value -1 reserved to indicate that has to be calculated
068                coreLength = -1;
069                alignResCounts = null; // Value null means not yet calculated
070        }
071
072        /**
073         * Copy constructor. Makes also a deep copy of all constituent {@link Block}
074         * s.
075         *
076         * @param bs
077         *            BlockSet object to be copied.
078         */
079        public BlockSetImpl(BlockSetImpl bs) {
080
081                super(bs); // This copies the cached scores
082                this.parent = bs.parent;
083                this.length = bs.length;
084                this.coreLength = bs.coreLength;
085
086                this.pose = null;
087                if (bs.pose != null) {
088                        // Make a deep copy of everything
089                        this.pose = new ArrayList<Matrix4d>();
090                        for (Matrix4d trans : bs.pose) {
091                                Matrix4d newTrans = (Matrix4d) trans.clone();
092                                pose.add(newTrans);
093                        }
094                }
095
096                blocks = null;
097                if (bs.blocks != null) {
098                        // Make a deep copy of everything
099                        this.blocks = new ArrayList<>();
100                        for (Block b : bs.blocks) {
101                                Block newB = b.clone();
102                                newB.setBlockSet(this);
103                                this.blocks.add(newB);
104                        }
105                }
106        }
107
108        @Override
109        public void clear() {
110                super.clear();
111                length = -1;
112                coreLength = -1;
113                alignResCounts = null;
114                pose = null;
115                for (Block a : getBlocks()) {
116                        a.clear();
117                }
118        }
119
120        @Override
121        public BlockSetImpl clone() {
122                return new BlockSetImpl(this);
123        }
124
125        @Override
126        public String toString() {
127                return "BlockSetImpl [blocks=" + blocks + ", pose=" + pose
128                                + ", length=" + length + ", coreLength=" + coreLength + "]";
129        }
130
131        @Override
132        public MultipleAlignment getMultipleAlignment() {
133                return parent;
134        }
135
136        @Override
137        public void setMultipleAlignment(MultipleAlignment parent) {
138                this.parent = parent;
139        }
140
141        @Override
142        public List<Block> getBlocks() {
143                if (blocks == null)
144                        blocks = new ArrayList<>();
145                return blocks;
146        }
147
148        @Override
149        public void setBlocks(List<Block> blocks) {
150                this.blocks = blocks;
151                for (Block b : blocks) {
152                        b.setBlockSet(this);
153                }
154        }
155
156        @Override
157        public List<Matrix4d> getTransformations() {
158                return pose;
159        }
160
161        @Override
162        public void setTransformations(List<Matrix4d> transformations) {
163                if (size() != transformations.size()) {
164                        throw new IllegalArgumentException(
165                                        "Wrong number of structures for this alignment");
166                }
167                pose = transformations;
168        }
169
170        @Override
171        public int length() {
172                if (length == -1)
173                        updateLength();
174                return length;
175        }
176
177        @Override
178        public int size() {
179                // Get the size from the variables that can contain the information
180                if (parent != null)
181                        return parent.size();
182                else if (getBlocks().size() == 0) {
183                        throw new IndexOutOfBoundsException(
184                                        "Empty BlockSet: number of Blocks == 0.");
185                } else
186                        return blocks.get(0).size();
187        }
188
189        @Override
190        public int getCoreLength() {
191                if (coreLength == -1)
192                        updateCoreLength();
193                return coreLength;
194        }
195
196        protected void updateLength() {
197                if (getBlocks().size() == 0) {
198                        throw new IndexOutOfBoundsException(
199                                        "Empty BlockSet: number of Blocks == 0.");
200                }
201                // Try to calculate it from the Block information
202                else {
203                        length = 0;
204                        for (Block block : blocks)
205                                length += block.length();
206                }
207        }
208
209        protected void updateCoreLength() {
210                if (getBlocks().size() == 0) {
211                        throw new IndexOutOfBoundsException(
212                                        "Empty BlockSet: number of Blocks == 0.");
213                }
214                // Try to calculate it from the Block information
215                else {
216                        coreLength = 0;
217                        for (Block block : blocks)
218                                coreLength += block.getCoreLength();
219                }
220        }
221
222        protected void updateCache() {
223                updateCoreLength();
224                updateLength();
225        }
226
227        @Override
228        public List<Integer> getAlignResCounts() {
229
230                if (alignResCounts != null)
231                        return alignResCounts;
232
233                alignResCounts = new ArrayList<>(size());
234                for (int s = 0; s < size(); s++)
235                        alignResCounts.add(0);
236
237                for (Block b : blocks) {
238                        List<Integer> bcounts = b.getAlignResCounts();
239                        for (int s = 0; s < size(); s++)
240                                alignResCounts.set(s, alignResCounts.get(s) + bcounts.get(s));
241                }
242                return alignResCounts;
243        }
244
245}