package org.webpieces.data.impl;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import org.webpieces.data.api.BufferPool;
import org.webpieces.data.api.DataWrapper;
public class ChainedDataWrapper extends AbstractDataWrapper {
private List<SliceableDataWrapper> wrappers = new ArrayList<>();
ChainedDataWrapper(SliceableDataWrapper wrapper1, SliceableDataWrapper wrapper2) {
wrappers.add(wrapper1);
wrappers.add(wrapper2);
}
ChainedDataWrapper(List<SliceableDataWrapper> wrappers) {
this.wrappers = wrappers;
}
public ChainedDataWrapper(SliceableDataWrapper wrapper) {
this.wrappers = new ArrayList<>();
wrappers.add(wrapper);
}
@Override
public int getReadableSize() {
int size = 0;
for(DataWrapper wrapper : wrappers) {
size += wrapper.getReadableSize();
}
return size;
}
@Override
public byte readByteAt(int i) {
int j = i;
for(DataWrapper wrapper : wrappers) {
int size = wrapper.getReadableSize();
if(j < size) {
return wrapper.readByteAt(j);
}
j = j - size;
}
throw new IndexOutOfBoundsException("i="+i+" is out of bounds of size="+getReadableSize());
}
@Override
public String createStringFrom(int initialOffset, int length, Charset charSet) {
if(length == 0)
return "";
String result = "";
int lengthLeftToRead = length;
int offset = initialOffset;
for(DataWrapper wrapper : wrappers) {
int size = wrapper.getReadableSize();
if(offset < size) {
if(offset + lengthLeftToRead <= size) {
result += wrapper.createStringFrom(offset, lengthLeftToRead, charSet);
return result;
}
int leftInBuffer = size - offset;
result += wrapper.createStringFrom(offset, leftInBuffer, charSet);
offset = 0; //since we read in this data, offset for next datawrapper is 0
lengthLeftToRead -= leftInBuffer;
} else {
offset -= size;
}
}
throw new IndexOutOfBoundsException("offset="+offset+" length="+length+" is larger than size="+getReadableSize());
}
@Override
public byte[] createByteArray() {
byte[] copy = new byte[getReadableSize()];
int offset = 0;
for(DataWrapper wrapper : wrappers) {
byte[] data = wrapper.createByteArray();
int size = wrapper.getReadableSize();
System.arraycopy(data, 0, copy, offset, size);
offset += size;
}
return copy;
}
void addMoreData(DataWrapper secondData) {
if(secondData instanceof ChainedDataWrapper) {
ChainedDataWrapper wrap = (ChainedDataWrapper) secondData;
wrappers.addAll(wrap.getAllWrappers());
return;
} else if(!(secondData instanceof SliceableDataWrapper)) {
throw new IllegalArgumentException("Only SliceableDataWrappers or ChainedDataWrappers are allowed to be chained");
}
SliceableDataWrapper wrap = (SliceableDataWrapper) secondData;
wrappers.add(wrap);
}
private List<SliceableDataWrapper> getAllWrappers() {
return wrappers;
}
@Override
public int getNumLayers() {
int max = 0;
for(DataWrapper wrapper: wrappers) {
@SuppressWarnings("deprecation")
int num = wrapper.getNumLayers();
if(num > max)
max = num;
}
return max+1;
}
@Override
public void addUnderlyingBuffersToList(List<ByteBuffer> buffers) {
for(SliceableDataWrapper wrapper : wrappers) {
wrapper.addUnderlyingBuffersToList(buffers);
}
}
List<SliceableDataWrapper> getWrappers() {
return wrappers;
}
@Override
public void releaseUnderlyingBuffers(BufferPool pool) {
for(DataWrapper wrapper : wrappers) {
wrapper.releaseUnderlyingBuffers(pool);
}
}
@Override
public String createStringFromUtf8(int offset, int length) {
return createStringFrom(offset, length, StandardCharsets.UTF_8);
}
}