public virtual void test_isSwitchOn()
 {
     for (int i = 0; i < 7; ++i)
     {
         Assert.True(ProtocolSwitch.isOn(i, 1 << i));
     }
     Assert.True(ProtocolSwitch.isOn(0, 1));
     Assert.True(ProtocolSwitch.isOn(1, 2));
     Assert.True(ProtocolSwitch.isOn(2, 4));
     Assert.True(ProtocolSwitch.isOn(3, 8));
     Assert.True(ProtocolSwitch.isOn(0, 3));
     Assert.True(ProtocolSwitch.isOn(1, 3));
     Assert.False(ProtocolSwitch.isOn(2, 3));
     Assert.True(ProtocolSwitch.isOn(6, 64));
     Assert.False(ProtocolSwitch.isOn(0, 64));
     Assert.True(ProtocolSwitch.isOn(0, 127));
     Assert.True(ProtocolSwitch.isOn(1, 127));
     Assert.False(ProtocolSwitch.isOn(7, 127));
     Assert.True(ProtocolSwitch.isOn(0, 255));
     Assert.True(ProtocolSwitch.isOn(1, 255));
     Assert.True(ProtocolSwitch.isOn(7, 255));
     try
     {
         ProtocolSwitch.isOn(7, 511);
         Assert.Null("Should not reach here!");
     }
     catch (System.ArgumentOutOfRangeException)
     {
     }
 }
        public virtual void test_createUsingIndex()
        {
            for (int i = 0; i < 7; ++i)
            {
                Assert.True(ProtocolSwitch.create(new int[] { i }).isOn(i));
            }

            int size = 7;

            int[] a = new int[size];
            for (int i = 0; i < size; ++i)
            {
                a[i] = i;
            }
            ProtocolSwitch status = ProtocolSwitch.create(a);

            for (int i = 0; i < size; ++i)
            {
                Assert.True(status.isOn(i));
            }
        }
        /// <seealso cref= CommandDecoder#decode(IChannelHandlerContext, IByteBuffer, List<object>) </seealso>
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
//ORIGINAL LINE: @Override public void decode(io.netty.channel.IChannelHandlerContext ctx, io.netty.buffer.IByteBuffer in, java.util.List<object><Object> out) throws Exception
        public virtual void decode(IChannelHandlerContext ctx, IByteBuffer @in, List <object> @out)
        {
            // the less length between response header and request header
            if (@in.ReadableBytes >= lessLen)
            {
                @in.MarkReaderIndex();
                byte protocol = @in.ReadByte();
                @in.ResetReaderIndex();
                if (protocol == RpcProtocolV2.PROTOCOL_CODE)
                {
                    /*
                     * ver: version for protocol
                     * type: request/response/request oneway
                     * cmdcode: code for remoting command
                     * ver2:version for remoting command
                     * requestId: id of request
                     * codec: code for codec
                     * switch: function switch
                     * (req)timeout: request timeout
                     * (resp)respStatus: response status
                     * classLen: length of request or response class name
                     * headerLen: length of header
                     * contentLen: length of content
                     * className
                     * header
                     * content
                     */
                    if (@in.ReadableBytes > 2 + 1)
                    {
                        int startIndex = @in.ReaderIndex;
                        @in.MarkReaderIndex();
                        @in.ReadByte();                         //protocol code
                        byte version = @in.ReadByte();          //protocol version
                        byte type    = @in.ReadByte();          //type
                        if (type == RpcCommandType.REQUEST || type == RpcCommandType.REQUEST_ONEWAY)
                        {
                            //decode request
                            if (@in.ReadableBytes >= RpcProtocolV2.RequestHeaderLength - 3)
                            {
                                short  cmdCode             = @in.ReadShort();
                                byte   ver2                = @in.ReadByte();
                                int    requestId           = @in.ReadInt();
                                byte   serializer          = @in.ReadByte();
                                byte   protocolSwitchValue = @in.ReadByte();
                                int    timeout             = @in.ReadInt();
                                short  classLen            = @in.ReadShort();
                                short  headerLen           = @in.ReadShort();
                                int    contentLen          = @in.ReadInt();
                                byte[] clazz               = null;
                                byte[] header              = null;
                                byte[] content             = null;

                                // decide the at-least bytes length for each version
                                int  lengthAtLeastForV1 = classLen + headerLen + contentLen;
                                bool crcSwitchOn        = ProtocolSwitch.isOn(ProtocolSwitch.CRC_SWITCH_INDEX, protocolSwitchValue);
                                int  lengthAtLeastForV2 = classLen + headerLen + contentLen;
                                if (crcSwitchOn)
                                {
                                    lengthAtLeastForV2 += 4;                                     // crc int
                                }

                                // continue read
                                if ((version == RpcProtocolV2.PROTOCOL_VERSION_1 && @in.ReadableBytes >= lengthAtLeastForV1) || (version == RpcProtocolV2.PROTOCOL_VERSION_2 && @in.ReadableBytes >= lengthAtLeastForV2))
                                {
                                    if (classLen > 0)
                                    {
                                        clazz = new byte[classLen];
                                        @in.ReadBytes(clazz);
                                    }
                                    if (headerLen > 0)
                                    {
                                        header = new byte[headerLen];
                                        @in.ReadBytes(header);
                                    }
                                    if (contentLen > 0)
                                    {
                                        content = new byte[contentLen];
                                        @in.ReadBytes(content);
                                    }
                                    if (version == RpcProtocolV2.PROTOCOL_VERSION_2 && crcSwitchOn)
                                    {
                                        checkCRC(@in, startIndex);
                                    }
                                }
                                else
                                {                                 // not enough data
                                    @in.ResetReaderIndex();
                                    return;
                                }
                                RequestCommand command;
                                if (cmdCode == CommandCode_Fields.HEARTBEAT_VALUE)
                                {
                                    command = new HeartbeatCommand();
                                }
                                else
                                {
                                    command = createRequestCommand(cmdCode);
                                }
                                command.Type           = type;
                                command.Version        = ver2;
                                command.Id             = requestId;
                                command.Serializer     = serializer;
                                command.ProtocolSwitch = ProtocolSwitch.create(protocolSwitchValue);
                                command.Timeout        = timeout;
                                command.Clazz          = clazz;
                                command.Header         = header;
                                command.Content        = content;

                                @out.Add(command);
                            }
                            else
                            {
                                @in.ResetReaderIndex();
                            }
                        }
                        else if (type == RpcCommandType.RESPONSE)
                        {
                            //decode response
                            if (@in.ReadableBytes >= RpcProtocolV2.ResponseHeaderLength - 3)
                            {
                                short  cmdCode             = @in.ReadShort();
                                byte   ver2                = @in.ReadByte();
                                int    requestId           = @in.ReadInt();
                                byte   serializer          = @in.ReadByte();
                                byte   protocolSwitchValue = @in.ReadByte();
                                short  status              = @in.ReadShort();
                                short  classLen            = @in.ReadShort();
                                short  headerLen           = @in.ReadShort();
                                int    contentLen          = @in.ReadInt();
                                byte[] clazz               = null;
                                byte[] header              = null;
                                byte[] content             = null;

                                // decide the at-least bytes length for each version
                                int  lengthAtLeastForV1 = classLen + headerLen + contentLen;
                                bool crcSwitchOn        = ProtocolSwitch.isOn(ProtocolSwitch.CRC_SWITCH_INDEX, protocolSwitchValue);
                                int  lengthAtLeastForV2 = classLen + headerLen + contentLen;
                                if (crcSwitchOn)
                                {
                                    lengthAtLeastForV2 += 4;                                     // crc int
                                }

                                // continue read
                                if ((version == RpcProtocolV2.PROTOCOL_VERSION_1 && @in.ReadableBytes >= lengthAtLeastForV1) || (version == RpcProtocolV2.PROTOCOL_VERSION_2 && @in.ReadableBytes >= lengthAtLeastForV2))
                                {
                                    if (classLen > 0)
                                    {
                                        clazz = new byte[classLen];
                                        @in.ReadBytes(clazz);
                                    }
                                    if (headerLen > 0)
                                    {
                                        header = new byte[headerLen];
                                        @in.ReadBytes(header);
                                    }
                                    if (contentLen > 0)
                                    {
                                        content = new byte[contentLen];
                                        @in.ReadBytes(content);
                                    }
                                    if (version == RpcProtocolV2.PROTOCOL_VERSION_2 && crcSwitchOn)
                                    {
                                        checkCRC(@in, startIndex);
                                    }
                                }
                                else
                                {                                 // not enough data
                                    @in.ResetReaderIndex();
                                    return;
                                }
                                ResponseCommand command;
                                if (cmdCode == CommandCode_Fields.HEARTBEAT_VALUE)
                                {
                                    command = new HeartbeatAckCommand();
                                }
                                else
                                {
                                    command = createResponseCommand(cmdCode);
                                }
                                command.Type               = type;
                                command.Version            = ver2;
                                command.Id                 = requestId;
                                command.Serializer         = serializer;
                                command.ProtocolSwitch     = ProtocolSwitch.create(protocolSwitchValue);
                                command.ResponseStatus     = (ResponseStatus)status;
                                command.Clazz              = clazz;
                                command.Header             = header;
                                command.Content            = content;
                                command.ResponseTimeMillis = new DateTimeOffset(DateTime.UtcNow).ToUnixTimeMilliseconds();
                                command.ResponseHost       = (IPEndPoint)ctx.Channel.RemoteAddress;

                                @out.Add(command);
                            }
                            else
                            {
                                @in.ResetReaderIndex();
                            }
                        }
                        else
                        {
                            string emsg = "Unknown command type: " + type;
                            logger.LogError(emsg);
                            throw new Exception(emsg);
                        }
                    }
                }
                else
                {
                    string emsg = "Unknown protocol: " + protocol;
                    logger.LogError(emsg);
                    throw new Exception(emsg);
                }
            }
        }