private ODocument Deserialize(BinaryReader reader, ODocument document)
        {
            var serializerVersion = reader.ReadByte();
            var classNameLength = readAsInteger(reader);
            var className = Encoding.UTF8.GetString(reader.ReadBytesRequired(classNameLength));
            document.OClassName = className;

            return parseDocument(reader, document);
        }
        internal byte[] ReadToken(BinaryReader reader)
        {
            var size = reader.ReadInt32EndianAware();
            var token = reader.ReadBytesRequired(size);
            
            // if token renewed
            if (token.Length > 0)
                _database.GetConnection().Token = token;

            return token;
        }
        private ODocument parseDocument(BinaryReader reader, ODocument document)
        {
            List<FieldDefinition> fd = new List<FieldDefinition>();
            var prop = String.Empty;

            while (true)
            {
                int len = readAsInteger(reader);
                if (len == 0)
                    break;

                if (len > 0)
                {
                    prop = Encoding.UTF8.GetString(reader.ReadBytesRequired(len));
                    int valuePos = reader.ReadInt32EndianAware();
                    OType valuetype = (OType)reader.ReadByte();
                    fd.Add(new FieldDefinition { FieldName = prop, Pointer = valuePos, DataType = valuetype });
                }
                else
                {
                    //TODO: Implement schema aware read
                    var propid = (len * -1) - 1;
                    prop = "no_schema";
                    int valuePos = reader.ReadInt32EndianAware();
                    fd.Add(new FieldDefinition { FieldName = prop, Pointer = valuePos, DataType = OType.Date });
                }
            }

            foreach (var f in fd)
            {
                if (f.Pointer != 0)
                {
                    readOType(reader, f.FieldName, document, f.DataType);
                }
                else
                {
                    document[f.FieldName] = null;
                }
            }

            return document;
        }
        private void readOType(BinaryReader reader, string fieldName, ODocument document, OType type)
        {
            switch (type)
            {
                case OType.Integer:
                    document.SetField<int>(fieldName, readAsInteger(reader));
                    break;
                case OType.Long:
                    document.SetField<long>(fieldName, readAsLong(reader));
                    break;
                case OType.Short:
                    document.SetField<short>(fieldName, readAsShort(reader));
                    break;
                case OType.String:
                    document.SetField<string>(fieldName, readString(reader));
                    break;
                case OType.Double:
                    document.SetField<double>(fieldName, BitConverter.Int64BitsToDouble(readLong(reader)));
                    break;
                case OType.Float:
                    document.SetField<float>(fieldName, readFloat(reader));
                    break;
                case OType.Decimal:
                    var scale = reader.ReadInt32EndianAware();

                    var valueSize = reader.ReadInt32EndianAware();

                    // read Fine the value
                    var valuex = reader.ReadBytesRequired(valueSize);

                    Int64 x1 = 0;

                    if ((valuex[0] & 0x80) == 0x80)
                        x1 = (sbyte)valuex[0];
                    else
                        x1 = valuex[0];

                    for (int i = 1; i < valuex.Length; i++)
                    {
                        x1 = (x1 << 8) | valuex[i];
                    }

                    try
                    {
                        document.SetField(fieldName, new Decimal(x1 * Math.Pow(10, (-1) * scale)));
                    }
                    catch (OverflowException)
                    {
                        document.SetField(fieldName, x1 * Math.Pow(10, (-1) * scale));
                    }
                    break;
                case OType.Byte:
                    document.SetField<byte>(fieldName, reader.ReadByte());
                    break;
                case OType.Boolean:
                    document.SetField<bool>(fieldName, reader.ReadByte() == 1 ? true : false);
                    break;
                case OType.DateTime:
                    document.SetField<DateTime>(fieldName, readDateTime(reader));
                    break;
                case OType.Date:
                    document.SetField<DateTime>(fieldName, readDate(reader));
                    break;
                case OType.EmbeddedList:
                    var listLength = readAsInteger(reader);
                    OType embeddedListRecorType = (OType)reader.ReadByte();
                    List<Object> embeddedList = new List<Object>();
                    for (int i = 0; i < listLength; i++)
                    {
                        var d = new ODocument();
                        OType dataType = (OType)reader.ReadByte();
                        readOType(reader, i.ToString(), d, dataType);
                        embeddedList.AddRange(d.Values);
                    }
                    document.SetField(fieldName, embeddedList);
                    break;
                case OType.EmbeddedSet:
                    var embeddedSetLen = readAsInteger(reader);
                    OType embeddedSetRecorType = (OType)reader.ReadByte();
                    HashSet<ODocument> embeddedSet = new HashSet<ODocument>();
                    for (int i = 0; i < embeddedSetLen; i++)
                    {
                        var d = new ODocument();
                        OType dataType = (OType)reader.ReadByte();
                        readOType(reader, "", d, dataType);
                        embeddedSet.Add(d);
                    }
                    document.SetField(fieldName, embeddedSet);
                    break;
                case OType.EmbeddedMap:
                    /* 
                     * header:headerStructure | values:valueStructure
                     * headerStructure
                     * ===============
                     * keyType:byte | keyValue:byte[]
                     * 
                     * valueStructure
                     * ==============
                     * valueType:byte | value:byte[]
                    */
                    var size = readAsInteger(reader);

                    var fd = new FieldDefinition[size];
                    Dictionary<string, Object> map = new Dictionary<string, object>();
                    for (int i = 0; i < size; i++)
                    {
                        fd[i] = new FieldDefinition();

                        var d = new ODocument();
                        var keyType = (OType)reader.ReadByte();
                        if (keyType != OType.String)
                            throw new NotImplementedException("key type " + keyType + " not implemented for EmbededMap");
                        readOType(reader, "key", d, keyType);

                        fd[i].FieldName = d.GetField<string>("key");
                        fd[i].Pointer = reader.ReadInt32EndianAware();
                        fd[i].DataType = (OType)reader.ReadByte();
                    }
                    for (int i = 0; i < size; i++)
                    {
                        var d = new ODocument();
                        if (fd[i].Pointer > 0)
                        {
                            readOType(reader, "value", d, fd[i].DataType);
                            map.Add(fd[i].FieldName, d.GetField<object>("value"));
                        }
                        else
                        {
                            map.Add(fd[i].FieldName, null);
                        }
                    }
                    document.SetField<Dictionary<string, Object>>(fieldName, map);
                    break;
                case OType.Embedded:
                    var version = reader.ReadByte();
                    parseDocument(reader, document);
                    break;
                case OType.Link:
                    var claster = readAsLong(reader);
                    var record = readAsLong(reader);
                    document.SetField(fieldName, new ORID((short)claster, record));
                    break;
                case OType.LinkBag:
                    var rids = new HashSet<ORID>();
                    var config = reader.ReadByte();
                    if ((config & 2) == 2)
                    {
                        // uuid parsing is not implemented
                        config += 16;
                    }

                    if ((config & 1) == 1) // 1 - embedded,0 - tree-based 
                    {
                        var entriesSize = reader.ReadInt32EndianAware();
                        for (int j = 0; j < entriesSize; j++)
                        {
                            var clusterid = reader.ReadInt16EndianAware();
                            var clusterposition = reader.ReadInt64EndianAware();
                            rids.Add(new ORID(clusterid, clusterposition));
                        }
                    }
                    else
                    {
                        throw new NotImplementedException("tree based ridbag");
                    }
                    document.SetField(fieldName, rids);
                    break;
                case OType.LinkList:
                    var linkList = readLinkCollection(reader);
                    document.SetField(fieldName, linkList);
                    break;
                case OType.LinkSet:
                    var linkSet = new HashSet<ORID>(readLinkCollection(reader));
                    document.SetField(fieldName, linkSet);
                    break;
                case OType.Any:
                    break;
                default:
                    throw new OException(OExceptionType.Deserialization, "The field type: " + type.ToString() + "not implemented");
            }
        }
 private float readFloat(BinaryReader reader)
 {
     return BitConverter.ToSingle(reader.ReadBytesRequired(sizeof(Int32)).CheckEndianess(), 0);
 }
 private string readString(BinaryReader reader)
 {
     int len = readAsInteger(reader);
     return Encoding.UTF8.GetString(reader.ReadBytesRequired(len));
 }