package com.splicemachine.utils;

import com.splicemachine.constants.bytes.BytesUtil;
import org.apache.lucene.util.ArrayUtil;

import java.nio.ByteBuffer;
import java.util.Arrays;

public class ByteSlice {
		private static final byte[] EMPTY_BYTE_ARRAY = new byte[]{};
		private byte[] buffer;
		private int offset;
		private int length;

		private ByteSlice() {  }

		public static ByteSlice empty(){
				return new ByteSlice(null,0,0);
		}

		public static ByteSlice wrap(ByteBuffer buffer){
				byte[] data = new byte[buffer.remaining()];
				buffer.get(data);
				return new ByteSlice(data,0,data.length);
		}

		public static ByteSlice wrap(byte[] data, int offset, int length) {
				return new ByteSlice(data,offset,length);
		}

		public static ByteSlice wrap(byte[] rowKey) {
				if(rowKey==null) return new ByteSlice(null,0,0);
				return new ByteSlice(rowKey,0,rowKey.length);
		}

		private ByteSlice(byte[] buffer, int offset, int length) {
				this.buffer = buffer;
				this.offset = offset;
				this.length = length;
		}

		public int offset() {
				return offset;
		}

		public int length() {
				return length;
		}

		public byte[] getByteCopy() {
				if(length<=0) return EMPTY_BYTE_ARRAY;
				return BytesUtil.slice(buffer, offset, length);
		}

		public ByteBuffer asBuffer(){
				if(length<=0) return null;
				return ByteBuffer.wrap(buffer,offset,length);
		}

		public void get(byte[] destination, int destOffset){
				assert destOffset + length <=destination.length: "Incorrect size to copy!";
				if(length<=0) return; //nothing to do

				System.arraycopy(buffer,offset,destination,destOffset,length);
		}

		public void set(byte[] buffer, int offset, int length) {
				this.buffer = buffer;
				this.offset = offset;
				this.length = length;
		}

		public void updateSlice(ByteSlice slice, boolean reverse){
				byte[] data = slice.array();
				int dOff = slice.offset();
				int dLen = slice.length();
				if(reverse && dLen>0){
						byte[] copy = new byte[dLen];
						System.arraycopy(data,dOff,copy,0,dLen);
						for(int i=0;i<copy.length;i++){
								copy[i] ^=0xff;
						}
						data = copy;
						dOff = 0;
				}
				set(data, dOff, dLen);
		}
		public void set(ByteSlice rowSlice, boolean reverse) {
				byte[] data;
				int offset, length;

				if(reverse){
						data = rowSlice.data(true);
						offset = 0;
						length = data.length;
				}else{
						data = rowSlice.buffer;
						offset = rowSlice.offset;
						length = rowSlice.length;
				}
				set(data,offset,length);
		}

		public byte[] data(boolean reverse){
				if(length<=0) return EMPTY_BYTE_ARRAY;
				byte[] data = BytesUtil.slice(buffer,offset,length);
				if(reverse){
						for(int i=0;i<data.length;i++){
								data[i] ^=0xff;
						}
				}
				return data;
		}

		public byte[] array() {
				return buffer;
		}

		public void reset(){
				length=0;
				buffer =null; //allow GC to collect
		}

		@Override
		public boolean equals(Object o) {
				if (this == o) return true;
				if (!(o instanceof ByteSlice)) return false;

				ByteSlice that = (ByteSlice) o;

				if (length != that.length) return false;
				if (offset != that.offset) return false;
				return ArrayUtil.equals(buffer, offset, that.buffer, that.offset, length);
		}

		@Override
		public int hashCode() {
				int result = buffer != null ? Arrays.hashCode(buffer) : 0;
				result = 31 * result + offset;
				result = 31 * result + length;
				return result;
		}

}

@@ -79,16 +79,17 @@
 esUtil;%0A
+%0A
 import o
@@ -118,24 +118,140 @@
 ArrayUtil;%0A%0A
+import java.io.Externalizable;%0Aimport java.io.IOException;%0Aimport java.io.ObjectInput;%0Aimport java.io.ObjectOutput;%0A
 import java.
@@ -315,16 +315,42 @@
 teSlice 
+implements Externalizable 
 %7B%0A%09%09priv
@@ -475,30 +475,29 @@
 length;%0A%0A%09%09p
-rivate
+ublic
  ByteSlice()
@@ -3581,10 +3581,391 @@
 t;%0A%09%09%7D%0A%0A
+%09%09@Override%0A%09%09public void readExternal(ObjectInput in) throws IOException,ClassNotFoundException %7B%0A%09%09%09offset = in.readInt();%0A%09%09%09length = in.readInt();%0A%09%09%09buffer = new byte%5Blength%5D;%0A%09%09%09in.readFully(buffer);%0A%09%09%7D%0A%0A%09%09@Override%0A%09%09public void writeExternal(ObjectOutput out) throws IOException %7B%0A%09%09%09out.writeInt(offset);%0A%09%09%09out.writeInt(length);%0A%09%09%09out.write(buffer,offset,length);%0A%09%09%7D%0A%0A
 %7D%0A

Implement Externalizable and make instance method public