// Copyright (C) 2011-2012 CRS4. // // This file is part of Seal. // // Seal is free software: you can redistribute it and/or modify it // under the terms of the GNU General Public License as published by the Free // Software Foundation, either version 3 of the License, or (at your option) // any later version. // // Seal is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License // for more details. // // You should have received a copy of the GNU General Public License along // with Seal. If not, see <http://www.gnu.org/licenses/>. package it.crs4.seal.common; import java.util.List; import java.util.Set; import java.nio.ByteBuffer; import java.io.UnsupportedEncodingException; /** * Simple in-memory mapping */ public class WritableMapping extends AbstractTaggedMapping { //////////////////////////////////////////////// // variables //////////////////////////////////////////////// protected String name; protected int flag = 0x4; // unmapped bit set. All the rest at 0 protected String contig; protected int pos = 0; protected int mapq = 255; protected List<AlignOp> alignment; protected ByteBuffer sequence; protected ByteBuffer quality; protected int insertSize = 0; public WritableMapping() { } /** * Construct a simple mapping from ASCII-encoded sequence and base quality scores. */ public WritableMapping(String name, String seq, String qual) { if (seq.length() != qual.length()) throw new IllegalArgumentException(String.format("sequence and quality strings have different lengths! (%d and %d)", seq.length(), qual.length())); this.name = name; setSequence(seq); setBaseQualities(qual); } public WritableMapping(String name, ByteBuffer seq, ByteBuffer qual) { this.name = name; this.sequence = seq; this.quality = qual; } //////////////////////////////////////////////// // methods //////////////////////////////////////////////// public String getName() { return name; } public void setName(String name) { this.name = name; } public int getFlag() { return flag; } public void setFlag(int flag) { this.flag = flag; if (isUnmapped()) mapq = 0; if (isUnmapped() || !isPaired() || isMateUnmapped()) insertSize = 0; } public String getContig() throws IllegalStateException { if (isUnmapped()) throw new IllegalStateException(); return contig; } public void setContig(String contig) { this.contig = contig; } public int get5Position() throws IllegalStateException { if (isUnmapped()) throw new IllegalStateException(); return pos; } public void set5Position(int p) { pos = p; } public int getMapQ() { if (isUnmapped()) throw new IllegalStateException(); return mapq; } public void setMapQ(int q) { if (q < 0 || q > 255) throw new IllegalArgumentException("mapq must be between 0 and 255 (got " + q + ")"); mapq = q; } public List<AlignOp> getAlignment() throws IllegalStateException { if (isUnmapped()) throw new IllegalStateException(); return alignment; } public void setAlignment(List<AlignOp> align) { alignment = align; } public ByteBuffer getSequence() { return sequence; } /** * Set buf as this mapping's sequence. * * A reference to buf is kept by this object. */ public void setSequence(ByteBuffer buf) { sequence = buf; } /** * Set this mapping's sequence to the contents of seq. * * The byte array seq is copied to this object's internal ByteBuffer. */ public void setSequence(byte[] seq, int offset, int length) { sequence = ByteBuffer.allocate(length); sequence.put(seq, offset, length).rewind().mark(); } public void setSequence(byte[] seq) { setSequence(seq, 0, seq.length); } /** * Set this mapping's sequence to the contents of seq. * * A new ByteBuffer is created from the contents of the seq string and * it is set as this mapping's sequence. */ public void setSequence(String seq) { try { sequence = ByteBuffer.wrap(seq.getBytes("US-ASCII")); sequence.mark(); } catch (UnsupportedEncodingException e) { throw new RuntimeException("Can't get US-ASCII charset!"); } } public ByteBuffer getBaseQualities() { return quality; } /** * Set buf as this mapping's base qualities. * * A reference to buf is kept by this object. */ public void setBaseQualities(ByteBuffer buf) { quality = buf; } /** * Set this mapping's base qualities to the contents of seq. * * The byte array seq is copied to this object's internal ByteBuffer. */ public void setBaseQualities(byte[] seq, int offset, int length) { quality = ByteBuffer.allocate(length); quality.put(seq, offset, length).rewind().mark(); } /** * Set this mapping's base qualities to the contents of seq. * * The byte array seq is copied to this object's internal ByteBuffer. */ public void setBaseQualities(byte[] seq) { setBaseQualities(seq, 0, seq.length); } /** * Set this mapping's base qualities to the contents of seq. * * A new ByteBuffer is created from the contents of the seq string and * it is set as this mapping's base qualities. */ public void setBaseQualities(String seq) { try { quality = ByteBuffer.wrap(seq.getBytes("US-ASCII")); quality.mark(); } catch (UnsupportedEncodingException e) { throw new RuntimeException("Can't get US-ASCII charset!"); } } public int getLength() { return sequence.limit() - sequence.position(); } /** * Clear this mapping. * * Returns it to the state of a new mapping allocated with the default constructor. */ public void clear() { name = null; flag = 0x4; contig = null; pos = 0; mapq = 255; alignment = null; sequence = null; quality = null; insertSize = 0; tagCache.clear(); } protected TagCacheItem makeTagItem(String name) throws NoSuchFieldException { throw new NoSuchFieldException("no field named " + name); } public void setTag(String name, TagDataType type, String value) { tagCache.put(name, new TagCacheItem(type, value)); } public Set<String> getTagNames() { return tagCache.keySet(); } //////////////////////// template/insert size methods //////////////////////// public void setTemplateLength(int isize) { if (isize != 0) { if (isUnmapped() || !isPaired() || isMateUnmapped()) throw new IllegalStateException("Setting non-zero template size for read in incompatible state"); } insertSize = isize; } public boolean isTemplateLengthAvailable() { return insertSize != 0; } public int getTemplateLength() throws IllegalStateException { if (!isTemplateLengthAvailable()) throw new IllegalStateException(); return insertSize; } //////////////////////// flag set methods //////////////////////// public void setIsPaired(boolean v) { setFlag(v, AlignFlags.Paired); } public void setIsProperlyPaired(boolean v) { setFlag(v, AlignFlags.ProperlyPaired); } public void setIsMapped(boolean v) { setFlag(!v, AlignFlags.Unmapped); } public void setIsUnmapped(boolean v) { setFlag(v, AlignFlags.Unmapped); } public void setIsMateMapped(boolean v) { setFlag(!v, AlignFlags.MateUnmapped); } public void setIsMateUnmapped(boolean v) { setFlag(v, AlignFlags.MateUnmapped); } public void setIsOnReverse(boolean v) { setFlag(v, AlignFlags.OnReverse); } public void setIsMateOnReverse(boolean v) { setFlag(v, AlignFlags.MateOnReverse); } public void setIsRead1(boolean v) { setFlag(v, AlignFlags.Read1); } public void setIsRead2(boolean v) { setFlag(v, AlignFlags.Read2); } public void setIsSecondaryAlign(boolean v) { setFlag(v, AlignFlags.SecondaryAlignment); } public void setIsFailedQC(boolean v) { setFlag(v, AlignFlags.FailedQC); } public void setIsDuplicate(boolean v) { setFlag(v, AlignFlags.Duplicate); } protected void setFlag(boolean newValue, AlignFlags f) { if (newValue) flag = f.set(flag); else flag = f.clear(flag); } }