package com.splicemachine.encoding;

import org.apache.hadoop.hbase.util.Bytes;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.UnicodeUtil;

import java.nio.ByteBuffer;

/**
 * UTF-8 encodes Strings in such a way that NULL < "" < Character.MIN_CODE_POINT < aa < aaa < b< ba<...<
 * Character.MAX_CODE_POINT < ..., and does not use 0x00 (reserved for separators).
 *
 * Note that UTF-8 encoding is already lexicographically sorted in bytes, by design. Hence, all we
 * really have to do is remove 0x00 elements. Since UTF-8 never uses the values 0xff or 0xfe, so adding
 * 2 to every byte will suffice.
 *
 * To distinguish between empty strings and {@code null}, we use 0x01 to denote an empty string, but an empty byte[]
 * denotes {@code null}.
 *
 * @author Scott Fines
 * Created on: 6/7/13
 */
public class StringEncoding {

	/**
	 * 
	 * Wraps the Lucene UnicodeUtil.UTF16toUTF8 bytes serializatiom...
	 * 
	 * @param value
	 * @param desc
	 * @return
	 */
    public static byte[] toBytes(String value, boolean desc){
        if(value==null) return new byte[0];
        if(value.length()==0) return new byte[]{0x01};

        //convert to UTF-8 encoding
        BytesRef result = new BytesRef();
        UnicodeUtil.UTF16toUTF8(value, 0, value.length(), result);        
        for(int i=0;i<result.length;i++){
            byte newD = (byte)(result.bytes[i] + 2);
            if(desc)
                newD ^= 0xff; //reverse the sign bit so that data is reversed in 2's complement
            result.bytes[i] = newD;
        }
        return result.bytes;
    }

    /* Way Slower....
    public static byte[] toBytes(String value, boolean desc){
        if(value==null) return new byte[0];
        if(value.length()==0) return new byte[]{0x01};

        //convert to UTF-8 encoding
        byte[] data = Bytes.toBytes(value);
        for(int i=0;i<data.length;i++){
            byte newD = (byte)(data[i] + 2);
            if(desc)
                newD ^= 0xff; //reverse the sign bit so that data is reversed in 2's complement
            data[i] = newD;
        }
        return data;
    }
    */
    /**
     * SIDE EFFECT WARNING: Transforms the passed in byte[] in place!
     *
     * @param data the string data to deserialize
     * @param desc
     * @return
     */
    public static String getString(byte[] data, boolean desc){
        if(data.length==0) return null;
        if(data.length>0 && data[0] == 0x01) return "";

        for(int i=0;i<data.length;i++){
            byte datum = data[i];
            if(desc)
                datum ^= 0xff;
            data[i] = (byte)(datum-2);
        }
        return Bytes.toString(data);
    }

    public static String getStringCopy(byte[] data,int offset,int length, boolean desc){
        byte[] dataToCopy = new byte[length];
        System.arraycopy(data,offset,dataToCopy,0,length);
        return getString(dataToCopy,desc);
    }

    public static String getStringCopy(ByteBuffer buffer,boolean desc){
        byte[] dataToCopy = new byte[buffer.remaining()];
        buffer.get(dataToCopy);
        return getString(dataToCopy,desc);
    }

}

@@ -1288,21 +1288,70 @@
 ult);   
+%0A
      
+   byte%5B%5D returnArray = new byte%5Bresult.length%5D;
 %0A       
@@ -1430,16 +1430,30 @@
 .bytes%5Bi
++result.offset
 %5D + 2);%0A
@@ -1583,26 +1583,25 @@
       re
-sult.bytes
+turnArray
 %5Bi%5D = ne
@@ -1635,26 +1635,25 @@
 n re
-sult.bytes
+turnArray
 ;%0A    %7D%0A
 %0A   
@@ -1652,30 +1652,23 @@
   %7D%0A
-%0A
     
-/* Way Slower....
+@Deprecated
 %0A   
@@ -1688,32 +1688,35 @@
 c byte%5B%5D toBytes
+Old
 (String value, b
@@ -2176,23 +2176,16 @@
 ;%0A    %7D%0A
-    */%0A
     /**%0A

Realized this is a variable length array