package aliview.sequences;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Arrays;
import org.apache.commons.lang.ArrayUtils;
import org.apache.log4j.Logger;
import aliview.NucleotideUtilities;
import aliview.utils.ArrayUtilities;
public class DefaultBases implements Bases {
private static final Logger logger = Logger.getLogger(DefaultBases.class);
private static final String TEXT_FILE_BYTE_ENCODING = "ASCII";
byte[] backend;
public DefaultBases(byte[] bytes) {
this.backend = bytes;
}
public DefaultBases getCopy(){
return new DefaultBases(ArrayUtils.clone(backend));
}
public int getLength(){
// or translated
return backend.length;
}
public byte get(int n) {
// or translated
return backend[n];
}
public char charAt(int n) {
// or translated
return (char) backend[n];
}
public byte[] toByteArray() {
// or translated
return backend;
}
public byte[] toByteArray(int startIndexInclusive, int endIndexInclusive) {
byte[] subArray = ArrayUtils.subarray(backend, startIndexInclusive, endIndexInclusive + 1);
return subArray;
}
@Override
public String toString() {
String asString = null;
// or translated
try {
asString = new String(backend, TEXT_FILE_BYTE_ENCODING);
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return asString;
}
public void writeBasesBetween(int start, int end, Writer out) throws IOException {
String outString = new String(toByteArray(start, end), TEXT_FILE_BYTE_ENCODING);
out.write(outString);
}
public void set(int n, byte newBase) {
assureSize(n);
backend[n] = newBase;
}
private void assureSize(int n) {
// logger.info("backend.length" + backend.length);
// logger.info("n" + n);
if(n >= backend.length){
resize(n + 1);
}
}
private void resize(int n) {
logger.info("resize=" + n);
int additionalCount = n - backend.length;
byte[] additional = new byte[additionalCount];
Arrays.fill(additional, SequenceUtils.GAP_SYMBOL);
backend = ArrayUtils.addAll(backend, additional);
logger.info("backend.length=" + backend.length);
}
// convenience
public void append(byte[] newBytes) {
// logger.info("backend.length" + backend.length);
// logger.info("newBytes.length" + newBytes.length);
backend = ArrayUtils.addAll(backend, newBytes);
// logger.info("backend.length" + backend.length);
}
public void moveBaseLeft(int n) {
set(n - 1, get(n));
}
public void moveBaseRight(int n) {
set(n + 1, get(n));
}
public void insertAt(int n, byte[] newBytes) {
assureSize(n - 1);
// logger.info("newBytes.length" + newBytes.length);
// logger.info("backend.length" + backend.length);
byte[] newArray = ArrayUtilities.insertAt(backend, n, newBytes);
// logger.info("newArray.length" + newArray.length);
backend = newArray;
}
public void replace(int startReplaceIndex, int stopReplaceIndex, byte[] insertBases) {
// or translated
// translate start stop and insert
int newLength = backend.length - (stopReplaceIndex + 1 - startReplaceIndex) + insertBases.length;
// TODO could check if length is less - then just clear and insert
byte[] newBases = new byte[newLength];
// copy first untouched part of sequence
System.arraycopy(backend, 0, newBases, 0, startReplaceIndex);
// copy insert bases
System.arraycopy(insertBases, 0, newBases, startReplaceIndex, insertBases.length);
// copy last untouched part of sequence - if there is one
if(stopReplaceIndex < backend.length - 1){
System.arraycopy(backend, stopReplaceIndex + 1, newBases, startReplaceIndex + insertBases.length, backend.length - (stopReplaceIndex + 1));
}
backend = newBases;
}
public void deleteAll(byte target) {
// how many to delete so we can create a new array right size
int count = 0;
for(int n = 0; n < backend.length; n++){
if(backend[n] == target){
count ++;
}
}
// copy all bytes not to delete into new array
if(count > 0){
byte[] newBackend = new byte[backend.length - count];
int index = 0;
for(byte next : backend){
if(next != target){
newBackend[index] = next;
index ++;
}
}
backend = newBackend;
}
}
public void delete(int[] toDelete) {
if(toDelete == null || toDelete.length == 0){
return;
}
Arrays.sort(toDelete);
// translate toDelete
int nOutOfBounds = 0;
for(int n = 0; n < toDelete.length; n++){
if(toDelete[n] < 0 || toDelete[n] >= backend.length){
nOutOfBounds ++;
}
}
// create new array size removed selected bases
byte[] newBases = new byte[backend.length - toDelete.length + nOutOfBounds];
int newIndex = 0;
int deleteCount = 0;
int nextToDelete = toDelete[deleteCount];
for(int n = 0;n < backend.length ;n++){
if(n == nextToDelete){
// dont copy this one
deleteCount ++;
if(deleteCount < toDelete.length){
nextToDelete = toDelete[deleteCount];
}else{
nextToDelete = -1;
}
}
else{
newBases[newIndex] = backend[n];
newIndex ++;
}
}
backend = newBases;
}
// ?????
public void complement() {
NucleotideUtilities.complement(backend);
}
// ?????
public void reverse() {
ArrayUtils.reverse(backend);
}
// convenience method
public void set(int n, char c) {
set(n, (byte) c);
}
// convenience
public void delete(int pos) {
delete(new int[]{pos});
}
// convenience
public void insertAt(int n, byte newByte) {
insertAt(n, new byte[]{newByte});
}
}