package org.voovan.tools.serialize;

import io.protostuff.LinkedBuffer;
import io.protostuff.ProtostuffIOUtil;
import io.protostuff.Schema;
import io.protostuff.runtime.RuntimeSchema;
import org.voovan.tools.TByte;
import org.voovan.tools.collection.ObjectThreadPool;
import org.voovan.tools.reflect.TReflect;

import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * ProtoStuff 的序列化实现
 *
 * @author: helyho
 * ignite-test Framework.
 * WebSite: https://github.com/helyho/ignite-test
 * Licence: Apache v2 License
 */
public class ProtoStuffSerialize implements Serialize {

    ObjectThreadPool<LinkedBuffer> objectThreadPool = new ObjectThreadPool<LinkedBuffer>(128);

    Map<Class, Schema> SCHEMAS = new ConcurrentHashMap<Class, Schema>();

    public Schema getSchema(Class clazz) {
        Schema schema = SCHEMAS.get(clazz);
        if(schema == null) {
            schema = RuntimeSchema.getSchema(clazz);
        }

        return schema;
    }

    @Override
    public byte[] serialize(Object obj) {

        byte[] buf = null;
        buf = TByte.toBytes(obj);
        if(buf==null) {
            Schema schema = getSchema(obj.getClass());
            LinkedBuffer buffer =objectThreadPool .get(()->LinkedBuffer.allocate(512));
            try {
                buf = ProtostuffIOUtil.toByteArray(obj, schema, buffer);
            } finally {
                buffer.clear();
            }
        }

        byte[] type = TByte.getBytes(TSerialize.getHashByClass(obj.getClass()));
        type = TByte.byteArrayConcat(type, type.length, new byte[]{0}, 1);
        buf = TByte.byteArrayConcat(type, type.length, buf, buf.length);

        return buf;
    }

    @Override
    public <T> T unserialize(byte[] bytes) {
        if(bytes.length == 0) {
            return (T)bytes;
        }

        byte[] type = new byte[32];

        int index = 0;
        for(index=0;index<type.length; index++) {
            if(bytes[index]!='\0') {
                type[index] = bytes[index];
            } else {
                break;
            }
        }
        try {

            int hashcode = TByte.getInt(type);

            Class innerClazz = TSerialize.getClassByHash(hashcode);

            byte[] valueBytes = Arrays.copyOfRange(bytes, index+1, bytes.length);

            Object obj = TByte.toObject(valueBytes, innerClazz);
            if(obj==null) {
                Schema schema = getSchema(innerClazz);
                obj = TReflect.newInstance(innerClazz);
                ProtostuffIOUtil.mergeFrom(valueBytes, 0, valueBytes.length, obj, schema);
            }
            return (T) obj;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }
}

@@ -1535,83 +1535,8 @@
 ));%0A
-        type = TByte.byteArrayConcat(type, type.length, new byte%5B%5D%7B0%7D, 1);%0A
     
@@ -1765,268 +1765,8 @@
    %7D
-%0A%0A        byte%5B%5D type = new byte%5B32%5D;%0A%0A        int index = 0;%0A        for(index=0;index%3Ctype.length; index++) %7B%0A            if(bytes%5Bindex%5D!='%5C0') %7B%0A                type%5Bindex%5D = bytes%5Bindex%5D;%0A            %7D else %7B%0A                break;%0A            %7D%0A        %7D
 %0A   
@@ -1817,20 +1817,21 @@
 .getInt(
-type
+bytes
 );%0A%0A    
@@ -1957,15 +1957,9 @@
 es, 
-index+1
+4
 , by

修复 ProtoStuffSerialize 的 bug