@Override
  protected MarkupElement onComponentTag(final ComponentTag tag) throws ParseException {
    // We only need ComponentTags
    if (tag instanceof WicketTag) {
      return tag;
    }

    // Has wicket:enclosure attribute?
    String enclosureAttr = getAttribute(tag, null);
    if (enclosureAttr != null) {
      if (tag.isOpen()) {
        // Make sure 'wicket:id' and 'id' are consistent
        String htmlId = tag.getAttribute("id");
        if ((tag.getId() != null) && !Strings.isEmpty(htmlId) && !htmlId.equals(tag.getId())) {
          throw new ParseException(
              "Make sure that 'id' and 'wicket:id' are the same if both are provided. Tag:"
                  + tag.toString(),
              tag.getPos());
        }

        // if it doesn't have a wicket-id already, then assign one now.
        if (Strings.isEmpty(tag.getId())) {
          if (Strings.isEmpty(htmlId)) {
            String id =
                getWicketNamespace() + "_" + INLINE_ENCLOSURE_ID_PREFIX + getRequestUniqueId();
            tag.setId(id);
          } else {
            tag.setId(htmlId);
          }

          tag.setAutoComponentTag(true);
          tag.setAutoComponentFactory(
              new ComponentTag.IAutoComponentFactory() {
                @Override
                public Component newComponent(MarkupContainer container, ComponentTag tag) {
                  String attributeName = getInlineEnclosureAttributeName(null);
                  String childId = tag.getAttribute(attributeName);
                  return new InlineEnclosure(tag.getId(), childId);
                }
              });
          tag.setModified(true);
        }

        // Put the enclosure on the stack. The most current one will be on top
        if (enclosures == null) {
          enclosures = new ArrayDeque<>();
        }
        enclosures.push(tag);
      } else {
        throw new ParseException(
            "Open-close tags don't make sense for InlineEnclosure. Tag:" + tag.toString(),
            tag.getPos());
      }
    }
    // Are we within an enclosure?
    else if ((enclosures != null) && (enclosures.size() > 0)) {
      // In case the enclosure tag did not provide a child component id, then assign the
      // first ComponentTag's id found as the controlling child to the enclosure.
      if (tag.isOpen()
          && (tag.getId() != null)
          && !(tag instanceof WicketTag)
          && !tag.isAutoComponentTag()) {
        Iterator<ComponentTag> componentTagIterator = enclosures.descendingIterator();
        while (componentTagIterator.hasNext()) {
          ComponentTag lastEnclosure = componentTagIterator.next();
          String attr = getAttribute(lastEnclosure, null);
          if (Strings.isEmpty(attr) == true) {
            lastEnclosure.getAttributes().put(getInlineEnclosureAttributeName(null), tag.getId());
            lastEnclosure.setModified(true);
          }
        }
      } else if (tag.isClose() && tag.closes(enclosures.peek())) {
        ComponentTag lastEnclosure = enclosures.pop();
        String attr = getAttribute(lastEnclosure, null);
        if (Strings.isEmpty(attr) == true) {
          throw new ParseException(
              "Did not find any child for InlineEnclosure. Tag:" + lastEnclosure.toString(),
              tag.getPos());
        }
      }
    }

    return tag;
  }
  /** Scans the given markup and extracts balancing tags. */
  private void parseMarkup() {
    try {
      // always remember the latest index (size)
      int size = markup.size();

      // Loop through tags
      MarkupElement elem;
      while (null != (elem = getNextTag())) {
        if (elem instanceof HtmlSpecialTag) {
          elem = new ComponentTag(((HtmlSpecialTag) elem).getXmlTag());
        }

        if (elem instanceof ComponentTag) {
          ComponentTag tag = (ComponentTag) elem;

          boolean add = (tag.getId() != null);
          if (!add && tag.isClose()) {
            add = ((tag.getOpenTag() != null) && (tag.getOpenTag().getId() != null));
          }

          // Add tag to list?
          if (add || /*tag.isModified() ||*/ (markup.size() != size)) {
            // Add text from last position to the current tag position
            CharSequence text = xmlParser.getInputFromPositionMarker(tag.getPos());
            if (text.length() > 0) {
              text = handleRawText(text.toString());

              // Make sure you add it at the correct location.
              // IMarkupFilters might have added elements as well.
              markup.addMarkupElement(size, new RawMarkup(text));
            }

            xmlParser.setPositionMarker();

            if (add) {
              // Add to the markup unless the tag has been flagged as
              // to be removed from the markup. (e.g. <wicket:remove>
              if (tag.isIgnore() == false) {
                markup.addMarkupElement(tag);
              }
            }
            /*else if (tag.isModified())
            {
            	markup.addMarkupElement(new RawMarkup(tag.toCharSequence()));
            }*/
            else {
              xmlParser.setPositionMarker(tag.getPos());
            }
          }

          // always remember the latest index (size)
          size = markup.size();
        }
      }
    } catch (final ParseException ex) {
      // Add remaining input string
      final CharSequence text = xmlParser.getInputFromPositionMarker(-1);
      if (text.length() > 0) {
        markup.addMarkupElement(new RawMarkup(text));
      }

      // markup.getMarkupResourceStream().setEncoding(xmlParser.getEncoding());
      markup.getMarkupResourceStream().setDoctype(xmlParser.getDoctype());

      final MarkupStream markupStream = new MarkupStream(markup);
      markupStream.setCurrentIndex(markup.size() - 1);
      throw new MarkupException(markupStream, ex.getMessage(), ex);
    }

    // Add tail?
    CharSequence text = xmlParser.getInputFromPositionMarker(-1);
    if (text.length() > 0) {
      text = handleRawText(text.toString());

      // Make sure you add it at the correct location.
      // IMarkupFilters might have added elements as well.
      markup.addMarkupElement(new RawMarkup(text));
    }

    postProcess(markup);

    // Make all tags immutable and the list of elements unmodifiable
    markup.makeImmutable();
  }