/** If the LINK refers to a stylesheet document, this method loads and parses it. */
  protected void processLink() {
    this.styleSheet = null;
    String rel = this.getAttribute(HtmlAttributeProperties.REL);
    if (rel != null) {
      String cleanRel = rel.trim().toLowerCase();
      boolean isStyleSheet = cleanRel.equals("stylesheet");
      boolean isAltStyleSheet = cleanRel.equals("alternate stylesheet");
      boolean isAppendixStyleSheet = cleanRel.equals("appendix stylesheet");
      if (isStyleSheet || isAltStyleSheet || isAppendixStyleSheet) {
        UserAgentContext uacontext = this.getUserAgentContext();
        if (uacontext.isExternalCSSEnabled()) {
          String media = this.getMedia();
          if (CSSUtilities.matchesMedia(media, uacontext)) {
            HTMLDocumentImpl doc = (HTMLDocumentImpl) this.getOwnerDocument();
            try {

              CSSStyleSheet sheet = CSSUtilities.parse(this.getHref(), doc);
              CSSStyleSheetImpl sheetImpl = null;
              if (sheet != null) {
                doc.addStyleSheet(sheet);
                this.styleSheet = sheet;
                if (sheet instanceof CSSStyleSheetImpl) {
                  sheetImpl = (CSSStyleSheetImpl) sheet;
                  if (isAltStyleSheet) {
                    sheetImpl.setDisabled(true);
                  } else {
                    sheetImpl.setDisabled(disabled);
                  }

                  URL baseURL = new URL(doc.getBaseURI());
                  URL scriptURL = Urls.createURL(baseURL, getHref());
                  if (scriptURL != null) sheetImpl.setHref(scriptURL.toString());
                  doc.addStyleSheet(sheetImpl);
                } else {
                  if (isAltStyleSheet) {
                    sheet.setDisabled(true);
                  } else {
                    sheet.setDisabled(this.disabled);
                  }
                  doc.addStyleSheet(sheet);
                }
              }

            } catch (MalformedURLException mfe) {
              this.warn(
                  "Will not parse CSS. URI=["
                      + this.getHref()
                      + "] with BaseURI=["
                      + doc.getBaseURI()
                      + "] does not appear to be a valid URI.");
            } catch (Throwable err) {
              this.warn("Unable to parse CSS. URI=[" + this.getHref() + "].", err);
            }
          }
        }
      }
    }
  }
 /**
  * Process.
  *
  * @param uri the uri
  */
 private void process(String uri) {
   try {
     URL url;
     try {
       url = new URL(uri);
     } catch (MalformedURLException mfu) {
       int idx = uri.indexOf(':');
       if ((idx == -1) || (idx == 1)) {
         // try file
         url = new URL("file:" + uri);
       } else {
         throw mfu;
       }
     }
     logger.info("process(): Loading URI=[" + uri + "].");
     long time0 = System.currentTimeMillis();
     SSLCertificate.setCertificate();
     URLConnection connection = url.openConnection();
     connection.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible;) Cobra/0.96.1+");
     connection.setRequestProperty("Cookie", "");
     if (connection instanceof HttpURLConnection) {
       HttpURLConnection hc = (HttpURLConnection) connection;
       hc.setInstanceFollowRedirects(true);
       int responseCode = hc.getResponseCode();
       logger.info("process(): HTTP response code: " + responseCode);
     }
     InputStream in = connection.getInputStream();
     byte[] content;
     try {
       content = IORoutines.load(in, 8192);
     } finally {
       in.close();
     }
     String source = new String(content, "UTF-8");
     this.textArea.setText(source);
     long time1 = System.currentTimeMillis();
     CSSOMParser parser = new CSSOMParser();
     InputSource is = CSSUtilities.getCssInputSourceForStyleSheet(source, uri);
     CSSStyleSheet styleSheet = parser.parseStyleSheet(is, null, null);
     long time2 = System.currentTimeMillis();
     logger.info(
         "Parsed URI=["
             + uri
             + "]: Parse elapsed: "
             + (time2 - time1)
             + " ms. Load elapsed: "
             + (time1 - time0)
             + " ms.");
     this.showStyleSheet(styleSheet);
   } catch (Exception err) {
     logger.log(Level.SEVERE, "Error trying to load URI=[" + uri + "].", err);
     this.clearCssOutput();
   }
 }
  /**
   * Adds the rule.
   *
   * @param styleSheet the style sheet
   * @param rule the rule
   * @throws MalformedURLException the malformed url exception
   * @throws UnsupportedEncodingException
   */
  private final void addRule(CSSStyleSheet styleSheet, CSSRule rule)
      throws MalformedURLException, UnsupportedEncodingException {
    HTMLDocumentImpl document = this.document;
    if (rule instanceof CSSStyleRule) {
      CSSStyleRule sr = (CSSStyleRule) rule;
      String selectorList = sr.getSelectorText();
      StringTokenizer commaTok = new StringTokenizer(selectorList, ",");
      while (commaTok.hasMoreTokens()) {
        String selectorPart = commaTok.nextToken().toLowerCase();
        ArrayList<SimpleSelector> simpleSelectors = null;
        String lastSelectorText = null;
        StringTokenizer tok = new StringTokenizer(selectorPart, " \t\r\n");
        if (tok.hasMoreTokens()) {
          simpleSelectors = new ArrayList<SimpleSelector>();
          SimpleSelector prevSelector = null;
          SELECTOR_FOR:
          for (; ; ) {
            String token = tok.nextToken();
            if (">".equals(token)) {
              if (prevSelector != null) {
                prevSelector.setSelectorType(SimpleSelector.PARENT);
              }
              continue SELECTOR_FOR;
            } else if ("+".equals(token)) {
              if (prevSelector != null) {
                prevSelector.setSelectorType(SimpleSelector.PRECEEDING_SIBLING);
              }
              continue SELECTOR_FOR;
            }
            int colonIdx = token.indexOf(':');
            String simpleSelectorText = colonIdx == -1 ? token : token.substring(0, colonIdx);
            String pseudoElement = colonIdx == -1 ? null : token.substring(colonIdx + 1);
            prevSelector = new SimpleSelector(simpleSelectorText, pseudoElement);
            simpleSelectors.add(prevSelector);
            if (!tok.hasMoreTokens()) {
              lastSelectorText = simpleSelectorText;
              break;
            }
          }
        }
        if (lastSelectorText != null) {
          int dotIdx = lastSelectorText.indexOf('.');
          if (dotIdx != -1) {
            String elemtl = lastSelectorText.substring(0, dotIdx);
            String classtl = lastSelectorText.substring(dotIdx + 1);
            this.addClassRule(elemtl, classtl, sr, simpleSelectors);
          } else {
            int poundIdx = lastSelectorText.indexOf('#');
            if (poundIdx != -1) {
              String elemtl = lastSelectorText.substring(0, poundIdx);
              String idtl = lastSelectorText.substring(poundIdx + 1);
              this.addIdRule(elemtl, idtl, sr, simpleSelectors);
            } else {
              String elemtl = lastSelectorText;
              this.addElementRule(elemtl, sr, simpleSelectors);
            }
          }
        }
      }
      // TODO: Attribute selectors
    } else if (rule instanceof CSSImportRule) {
      UserAgentContext uacontext = document.getUserAgentContext();
      if (uacontext.isExternalCSSEnabled()) {
        CSSImportRule importRule = (CSSImportRule) rule;
        if (CSSUtilities.matchesMedia(importRule.getMedia(), uacontext)) {

          String href = importRule.getHref();

          CSSStyleSheet sheet = null;
          try {
            sheet = CSSUtilities.parse(href, document);
          } catch (Exception err) {
            logger.severe("Unable to parse CSS. URI=[" + href + "]." + err);
          }

          if (sheet != null) {
            this.addStyleSheet(sheet);
          }
        }
      }
    } else if (rule instanceof CSSMediaRule) {
      CSSMediaRule mrule = (CSSMediaRule) rule;
      MediaList mediaList = mrule.getMedia();
      if (CSSUtilities.matchesMedia(mediaList, document.getUserAgentContext())) {
        CSSRuleList ruleList = mrule.getCssRules();
        int length = ruleList.getLength();
        for (int i = 0; i < length; i++) {
          CSSRule subRule = ruleList.item(i);
          this.addRule(styleSheet, subRule);
        }
      }
    }
  }