/**
   * Constructor with an extension name.
   *
   * @param name The extension name.
   * @throws IllegalArgumentException The given name is not a valid token.
   */
  public WebSocketExtension(String name) {
    // Check the validity of the name.
    if (Token.isValid(name) == false) {
      // The name is not a valid token.
      throw new IllegalArgumentException("'name' is not a valid token.");
    }

    mName = name;
    mParameters = new LinkedHashMap<String, String>();
  }
  /**
   * Set a value to the specified parameter.
   *
   * @param key The name of the parameter.
   * @param value The value of the parameter. If not {@code null}, it must be a valid token. Note
   *     that <a href="http://tools.ietf.org/html/rfc6455" >RFC 6455</a> says "<i>When using the
   *     quoted-string syntax variant, the value after quoted-string unescaping MUST conform to the
   *     'token' ABNF.</i>"
   * @return {@code this} object.
   * @throws IllegalArgumentException
   *     <ul>
   *       <li>The key is not a valid token.
   *       <li>The value is not {@code null} and it is not a valid token.
   *     </ul>
   */
  public WebSocketExtension setParameter(String key, String value) {
    // Check the validity of the key.
    if (Token.isValid(key) == false) {
      // The key is not a valid token.
      throw new IllegalArgumentException("'key' is not a valid token.");
    }

    // If the value is not null.
    if (value != null) {
      // Check the validity of the value.
      if (Token.isValid(value) == false) {
        // The value is not a valid token.
        throw new IllegalArgumentException("'value' is not a valid token.");
      }
    }

    mParameters.put(key, value);

    return this;
  }
  /**
   * Parse a string as a {@link WebSocketExtesion}. The input string should comply with the format
   * described in <a href= "https://tools.ietf.org/html/rfc6455#section-9.1">9.1. Negotiating
   * Extensions</a> in <a href="https://tools.ietf.org/html/rfc6455" >RFC 6455</a>.
   *
   * @param string A string that represents a WebSocket extension.
   * @return A new {@link WebSocketExtension} instance that represents the given string. If the
   *     input string does not comply with RFC 6455, {@code null} is returned.
   */
  public static WebSocketExtension parse(String string) {
    if (string == null) {
      return null;
    }

    // Split the string by semi-colons.
    String[] elements = string.trim().split("\\s*;\\s*");

    if (elements.length == 0) {
      // Even an extension name is not included.
      return null;
    }

    // The first element is the extension name.
    String name = elements[0];

    if (Token.isValid(name) == false) {
      // The extension name is not a valid token.
      return null;
    }

    // The first element is the extension name.
    WebSocketExtension extension = new WebSocketExtension(name);

    // For each "{key}[={value}]".
    for (int i = 1; i < elements.length; ++i) {
      // Split by '=' to get the key and the value.
      String[] pair = elements[i].split("\\s*=\\s*", 2);

      // If {key} is not contained.
      if (pair.length == 0 || pair[0].length() == 0) {
        // Ignore.
        continue;
      }

      // The name of the parameter.
      String key = pair[0];

      if (Token.isValid(key) == false) {
        // The parameter name is not a valid token.
        // Ignore this parameter.
        continue;
      }

      // The value of the parameter.
      String value = extractValue(pair);

      if (value != null) {
        if (Token.isValid(value) == false) {
          // The parameter value is not a valid token.
          // Ignore this parameter.
          continue;
        }
      }

      // Add the pair of the key and the value.
      extension.setParameter(key, value);
    }

    return extension;
  }