public ChannelBuffer encode() throws TooLongFrameException {
        int b0 = 0;
        if (fin) {
            b0 |= (1 << 7);
        }
        b0 |= (rsv % 8) << 4;
        b0 |= opcode % 128;

        int b1 = maskingKey != null ? 0x80 : 0x00;

        int headerLength = maskingKey != null ? 6 : 2;

        ChannelBuffer header;
        int length = data.readableBytes();

        if (opcode == Opcodes.OPCODE_PING && length > 125) {
            throw new TooLongFrameException("invalid payload for PING (payload length must be <= 125, was " + length);
        }

        if (length <= 125) {
            b1 |= length & 0x7F;
            header = createBuffer(headerLength + length);
            header.writeByte(b0);
            header.writeByte(b1);
        } else if (length <= 0xFFFF) {
            b1 |= 126;
            headerLength += 2;
            header = createBuffer(headerLength + length);
            header.writeByte(b0);
            header.writeByte(b1);
            header.writeByte((length >>> 8) & 0xFF);
            header.writeByte((length) & 0xFF);
        } else {
            b1 |= 127;
            headerLength += 8;
            header = createBuffer(headerLength + length);
            header.writeByte(b0);
            header.writeByte(b1);
            header.writeLong(length);
        }

        if (maskingKey != null) {
            header.writeBytes(maskingKey);
            applyMask(data, maskingKey);
        }

        return ChannelBuffers.wrappedBuffer(header, data);
    }