/**
   * Parses {@link #input} by extracting URL without schema and parameters and than encodes this
   * URL.
   *
   * <p>Expected {@link #input} format is (schema):(//)URL(?|#)(parameters)
   *
   * @return Either encoded string or unchanged if it does not match format.
   */
  String parse() {
    int n = input.length();

    // Scheme.
    int p = scan(0, n, "/?#", ":");

    if (p > 0 && at(p, n, ':')) {
      p++; // Skip ':'

      if (at(p, n, '/')) {
        if (at(p, n, '/') == true && at(p + 1, n, '/')) {
          p += 2;

          // Seek authority.
          int q = scan(p, n, "", "/?#");

          if (q > p) {
            p = q;
          }
        }

        int q = scan(p, n, "", "?#");

        StringBuilder buf = new StringBuilder(input.substring(0, p));

        buf.append(encodePath(input.substring(p, q)));
        buf.append(input.substring(q, n));

        encoded = buf.toString();
      }
    }

    return encoded;
  }
  /**
   * Encodes given path by replacing all occurrences of space with '%20', percent sign with '%25'
   * and semicolon with '%3B'.
   *
   * @param path Path to be encoded.
   * @return Encoded path.
   */
  private String encodePath(String path) {
    StringBuilder buf = new StringBuilder(path.length());

    for (int i = 0; i < path.length(); i++) {
      char c = path.charAt(i);

      switch (c) {
        case ' ':
          {
            buf.append("%20");
            break;
          }

        case '%':
          {
            buf.append("%25");
            break;
          }
        case ';':
          {
            buf.append("%3B");
            break;
          }

        default:
          {
            buf.append(c);
          }
      }
    }

    return buf.toString();
  }