/*******************************************************************************
* Copyright 2013 EMBL-EBI
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package net.sf.cram.ref;
import java.util.Arrays;
import htsjdk.samtools.util.SequenceUtil;
public class ReferenceRegion {
public int index;
public String name;
// alignment start of the first element in the 'array':
public long alignmentStart;
public byte[] array;
/**
* @param bases
* @param sequenceIndex
* @param sequenceName
* @param alignmentStart
* 1-based inclusive
*/
public ReferenceRegion(byte[] bases, int sequenceIndex, String sequenceName, long alignmentStart) {
this.array = bases;
this.index = sequenceIndex;
this.name = sequenceName;
if (alignmentStart < 1)
throw new IllegalArgumentException(String.format("Invalid reference region1: %s, %d, %d.", sequenceName,
alignmentStart, bases.length));
this.alignmentStart = alignmentStart;
}
public static ReferenceRegion wrap(byte[] bases, int sequenceIndex, String sequenceName) {
return new ReferenceRegion(bases, sequenceIndex, sequenceName, 1);
}
public static ReferenceRegion copyRegion(byte[] bases, int sequenceIndex, String sequenceName, long alignmentStart,
long alignmentEnd) {
byte[] copy = copySafe(bases, 1, (int) alignmentStart, (int) (alignmentEnd - alignmentStart + 1));
return new ReferenceRegion(copy, sequenceIndex, sequenceName, alignmentStart);
}
public int arrayPosition(long alignmentPosition) {
int arrayPosition = (int) (alignmentPosition - alignmentStart);
if (arrayPosition < 0 || arrayPosition > array.length - 1) {
System.err.println(toString());
throw new IllegalArgumentException(
String.format("The alignment position is out of the region: %d, %d, %d, %d", alignmentStart,
alignmentPosition, 0, arrayPosition));
}
return arrayPosition;
}
public byte base(long alignmentPosition) {
return array[arrayPosition(alignmentPosition)];
}
public byte[] copy(long alignmentStart, int alignmentSpan) {
int from = arrayPosition(alignmentStart);
int to = arrayPosition(alignmentStart + alignmentSpan);
return Arrays.copyOfRange(array, from, to);
}
public byte[] copySafe(long alignmentStart, int alignmentSpan) {
return ReferenceRegion.copySafe(array, (int) this.alignmentStart, (int) alignmentStart, alignmentSpan);
}
/**
* Copies a byte array into a new array. If the requested region is out of
* the source array then the new array size is adjusted accordingly. An
* empty array is return if there requested region is completely outside of
* the source array.
*
* @param ref
* array of bases to copy from
* @param refAlStart
* a 1-based alignment start of the 1st element in the source
* array, default is 1
* @param alignmentStart
* a 1-based alignment start of the region to be copied
* @param alignmentSpan
* alignment span of the region to be copied
* @return a copy of the bases from ref array trimmed if the ref array is
* not long enough. An empty array is return if the requested region
* is beyond the ref array.
*/
public static byte[] copySafe(byte[] ref, long refAlStart, int alignmentStart, int alignmentSpan) {
int from = (int) (alignmentStart - refAlStart);
if (from > ref.length - 1)
return new byte[0];
int to = (int) (alignmentStart + alignmentSpan - refAlStart);
if (to > ref.length)
to = ref.length;
return Arrays.copyOfRange(ref, from, to);
}
public String md5(int alignmentStart, int alignmentSpan) {
int from = (int) (alignmentStart - this.alignmentStart);
if (from >= array.length)
return SequenceUtil.calculateMD5String(new byte[0], 0, 0);
// allow for hanging end:
int to = (int) (alignmentStart + alignmentSpan - this.alignmentStart);
return SequenceUtil.calculateMD5String(array, from, Math.min(to - from, array.length - from));
}
@Override
public String toString() {
return "ReferenceRegion [index=" + index + ", name=" + name + ", alignmentStart=" + alignmentStart
+ ", array length=" + array.length + "]";
}
}