public function encode($payload, $type = Protocol::TYPE_TEXT, $masked = false)
    {
        if (!is_int($type) || !in_array($type, Protocol::FRAME_TYPES)) {
            throw new InvalidArgumentException('Invalid frame type');
        }

        $this->type = $type;
        $this->masked = $masked;
        $this->payload = $payload;
        $this->length = strlen($this->payload);
        $this->offset_mask = null;
        $this->offset_payload = null;

        $this->buffer = "\x00\x00";

        $this->buffer[self::BYTE_HEADER] = chr(
            (self::BITFIELD_TYPE & $this->type)
            | (self::BITFIELD_FINAL & PHP_INT_MAX)
        );

        $masked_bit = (self::BITFIELD_MASKED & ($this->masked ? PHP_INT_MAX : 0));

        if ($this->length <= 125) {
            $this->buffer[self::BYTE_INITIAL_LENGTH] = chr(
                (self::BITFIELD_INITIAL_LENGTH & $this->length) | $masked_bit
            );
        } elseif ($this->length <= 65536) {
            $this->buffer[self::BYTE_INITIAL_LENGTH] = chr(
                (self::BITFIELD_INITIAL_LENGTH & 126) | $masked_bit
            );
            $this->buffer .= pack('n', $this->length);
        } else {
            $this->buffer[self::BYTE_INITIAL_LENGTH] = chr(
                (self::BITFIELD_INITIAL_LENGTH & 127) | $masked_bit
            );

            if (PHP_INT_MAX > 2147483647) {
                $this->buffer .= pack('NN', $this->length >> 32, $this->length);
                // $this->buffer .= pack('I', $this->length);
            } else {
                $this->buffer .= pack('NN', 0, $this->length);
            }
        }

        if ($this->masked) {
            $this->mask = $this->generateMask();
            $this->buffer .= $this->mask;
            $this->buffer .= $this->mask($this->payload);
        } else {
            $this->buffer .= $this->payload;
        }

        $this->offset_mask = $this->getMaskOffset();
        $this->offset_payload = $this->getPayloadOffset();

        return $this;
    }