/**
   * Renders head for embedded component, i.e. those who are not added directly to this container
   * but have the markup inside it.
   *
   * @param container The HtmlHeaderContainer
   */
  private void renderHeadForInnerSiblings(HtmlHeaderContainer container) {
    MarkupStream stream = new MarkupStream(getMarkup());

    while (stream.hasMore()) {
      MarkupElement childOpenTag = stream.nextOpenTag();

      if ((childOpenTag instanceof ComponentTag) && !stream.atCloseTag()) {
        // Get element as tag
        final ComponentTag tag = (ComponentTag) childOpenTag;

        // Get component id
        final String id = tag.getId();

        Component component = null;

        if (get(id) == null) {
          component = ComponentResolvers.resolveByComponentHierarchy(this, stream, tag);
        }

        if (component != null) {
          component.internalRenderHead(container);
        }

        // consider just direct children
        stream.skipToMatchingCloseTag(tag);
      }
    }
  }
 @Override
 public void onComponentTagBody(MarkupStream markup, ComponentTag tag) {
   // We assume the body of the component is raw HTML
   // (i.e. not nested wicket components or wicket tags).
   RawMarkup raw = (RawMarkup) markup.get();
   getResponse().write(getTruncateHelper().truncate(raw.toString(), this.length));
   markup.next();
 }
  /**
   * @param container
   * @param markupStream
   * @return The header id
   */
  private String getHeaderId(final Component container, final MarkupStream markupStream) {
    Class<?> markupClass = markupStream.getTag().getMarkupClass();
    if (markupClass == null) {
      markupClass = markupStream.getContainerClass();
    }

    // create a unique id for the HtmlHeaderContainer
    StringBuilder builder = new StringBuilder(100);
    builder.append('_');
    builder.append(Classes.simpleName(markupClass));
    if (container.getVariation() != null) {
      builder.append(container.getVariation());
    }
    builder.append("Header");
    builder.append(markupStream.getCurrentIndex());
    return builder.toString();
  }
  /**
   * Search the child's markup in the header section of the markup
   *
   * @param container
   * @param child
   * @return Null, if not found
   */
  public IMarkupFragment findMarkupInAssociatedFileHeader(
      final MarkupContainer container, final Component child) {
    // Get the associated markup
    IMarkupFragment markup = container.getAssociatedMarkup();
    IMarkupFragment childMarkup = null;

    // MarkupStream is good at searching markup
    MarkupStream stream = new MarkupStream(markup);
    while (stream.skipUntil(ComponentTag.class) && (childMarkup == null)) {
      ComponentTag tag = stream.getTag();
      if (TagUtils.isWicketHeadTag(tag)) {
        if (tag.getMarkupClass() == null) {
          // find() can still fail an return null => continue the search
          childMarkup = stream.getMarkupFragment().find(child.getId());
        }
      } else if (TagUtils.isHeadTag(tag)) {
        // find() can still fail an return null => continue the search
        childMarkup = stream.getMarkupFragment().find(child.getId());
      }

      // Must be a direct child. We are not interested in grand children
      if (tag.isOpen() && !tag.hasNoCloseTag()) {
        stream.skipToMatchingCloseTag(tag);
      }
      stream.next();
    }

    return childMarkup;
  }
  /**
   * Process next header markup fragment.
   *
   * @param associatedMarkupStream
   * @return index or -1 when done
   */
  private int nextHeaderMarkup(final MarkupStream associatedMarkupStream) {
    // No associated markup => no header section
    if (associatedMarkupStream == null) {
      return -1;
    }

    // Scan the markup for <wicket:head>.
    MarkupElement elem = associatedMarkupStream.get();
    while (elem != null) {
      if (elem instanceof WicketTag) {
        WicketTag tag = (WicketTag) elem;
        if (tag.isOpen() && tag.isHeadTag()) {
          if (noMoreWicketHeadTagsAllowed == true) {
            throw new MarkupException(
                "<wicket:head> tags are only allowed before <body>, </head>, <wicket:panel> etc. tag");
          }
          return associatedMarkupStream.getCurrentIndex();
        }
        // wicket:head must be before border, panel or extend
        // @TODO why is that? Why can't it be anywhere? (except inside wicket:fragment)
        else if (tag.isOpen() && (tag.isPanelTag() || tag.isBorderTag() || tag.isExtendTag())) {
          noMoreWicketHeadTagsAllowed = true;
        }
      } else if (elem instanceof ComponentTag) {
        ComponentTag tag = (ComponentTag) elem;
        // wicket:head must be before </head>
        // @TODO why??
        if (tag.isClose() && TagUtils.isHeadTag(tag)) {
          noMoreWicketHeadTagsAllowed = true;
        }
        // wicket:head must be before <body>
        // @TODO why??
        else if (tag.isOpen() && TagUtils.isBodyTag(tag)) {
          noMoreWicketHeadTagsAllowed = true;
        }
      }
      elem = associatedMarkupStream.next();
    }

    // No (more) wicket:head found
    return -1;
  }
  /**
   * Called by components like Panel and Border which have associated Markup and which may have a
   * &lt;wicket:head&gt; tag.
   *
   * <p>Whereas 'this' might be a Panel or Border, the HtmlHeaderContainer parameter has been added
   * to the Page as a container for all headers any of its components might wish to contribute to.
   *
   * <p>The headers contributed are rendered in the standard way.
   *
   * @param container
   * @param htmlContainer The HtmlHeaderContainer added to the Page
   */
  public final void renderHeadFromAssociatedMarkupFile(
      final WebMarkupContainer container, final HtmlHeaderContainer htmlContainer) {
    // reset for each render in case the strategy is re-used
    noMoreWicketHeadTagsAllowed = false;

    // Gracefully getAssociateMarkupStream. Throws no exception in case
    // markup is not found
    final MarkupStream markupStream = container.getAssociatedMarkupStream(false);
    if (markupStream == null) {
      return;
    }

    // Position pointer at current (first) header
    noMoreWicketHeadTagsAllowed = false;
    while (nextHeaderMarkup(markupStream) != -1) {
      // found <wicket:head>
      String headerId = getHeaderId(container, markupStream);

      // Create a HeaderPartContainer and associate the markup
      HeaderPartContainer headerPart =
          getHeaderPart(container, headerId, markupStream.getMarkupFragment());
      if (headerPart != null) {
        // A component's header section must only be added once,
        // no matter how often the same Component has been added
        // to the page or any other container in the hierarchy.
        if (htmlContainer.okToRenderComponent(headerPart.getScope(), headerPart.getId())) {
          // make sure the Page is accessible
          headerPart.setParent(htmlContainer);
          headerPart.render();
        }
      }

      // Position the stream after <wicket:head>
      markupStream.skipComponent();
    }
  }
  /**
   * Resolves the child component which is the controller of this Enclosure
   *
   * @param markupStream the markup stream of this Enclosure
   * @param enclosureParent the non-auto parent component of this Enclosure
   * @return The component associated with the {@linkplain #childId}
   */
  private Component getChildComponent(
      final MarkupStream markupStream, MarkupContainer enclosureParent) {
    String fullChildId = getChildId();

    Component controller = enclosureParent.get(fullChildId);
    if (controller == null) {
      int orgIndex = markupStream.getCurrentIndex();
      try {
        while (markupStream.hasMore()) {
          markupStream.next();
          if (markupStream.skipUntil(ComponentTag.class)) {
            ComponentTag tag = markupStream.getTag();
            if ((tag != null) && (tag.isOpen() || tag.isOpenClose())) {
              String tagId = tag.getId();

              if (fullChildId.equals(tagId)) {
                ComponentTag fullComponentTag = new ComponentTag(tag);
                fullComponentTag.setId(childId.toString());

                controller =
                    ComponentResolvers.resolve(
                        enclosureParent,
                        markupStream,
                        fullComponentTag,
                        new ResolverFilter() {
                          @Override
                          public boolean ignoreResolver(final IComponentResolver resolver) {
                            return resolver instanceof EnclosureHandler;
                          }
                        });
                break;
              } else if (fullChildId.startsWith(tagId + PATH_SEPARATOR)) {
                fullChildId = Strings.afterFirst(fullChildId, PATH_SEPARATOR);
              }
            }
          }
        }
      } finally {
        markupStream.setCurrentIndex(orgIndex);
      }
    }

    checkChildComponent(controller);
    return controller;
  }
  /**
   * Search for &lt;wicket:panel ...&gt; on the same level.
   *
   * @param markup
   * @return null, if not found
   */
  private final IMarkupFragment findStartTag(final IMarkupFragment markup) {
    MarkupStream stream = new MarkupStream(markup);

    while (stream.skipUntil(ComponentTag.class)) {
      ComponentTag tag = stream.getTag();
      if (tag.isOpen() || tag.isOpenClose()) {
        if (tag instanceof WicketTag) {
          WicketTag wtag = (WicketTag) tag;
          if (tagName.equalsIgnoreCase(wtag.getName())) {
            return stream.getMarkupFragment();
          }
        }

        stream.skipToMatchingCloseTag(tag);
      }

      stream.next();
    }

    return null;
  }
  @Override
  public IMarkupFragment getMarkup() {
    if (getParent() == null) {
      throw new WicketRuntimeException(
          "Bug: The Wicket internal instance of HtmlHeaderContainer is not connected to a parent");
    }

    // Get the page markup
    IMarkupFragment markup = getPage().getMarkup();
    if (markup == null) {
      throw new MarkupException("Unable to get page markup: " + getPage().toString());
    }

    // Find the markup fragment
    MarkupStream stream = new MarkupStream(markup);
    IMarkupFragment headerMarkup = null;
    while (stream.skipUntil(ComponentTag.class) && (headerMarkup == null)) {
      ComponentTag tag = stream.getTag();
      if (tag.isOpen() || tag.isOpenClose()) {
        if (tag instanceof WicketTag) {
          WicketTag wtag = (WicketTag) tag;
          if (wtag.isHeadTag()) {
            if (tag.getMarkupClass() == null) {
              headerMarkup = stream.getMarkupFragment();
            }
          }
        } else if (tag.getName().equalsIgnoreCase("head")) {
          headerMarkup = stream.getMarkupFragment();
        }
      }

      stream.next();
    }

    setMarkup(headerMarkup);
    return headerMarkup;
  }
 /** {@inheritDoc} */
 @Override
 public ComponentTag getComponentTag(Component c) {
   IMarkupFragment markup = c.getMarkup();
   MarkupStream stream = new MarkupStream(markup);
   return stream.getTag();
 }
  /** 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();
  }
 private static void render(BootstrapRadioChoice<String> choice, String initialMarkup) {
   MarkupStream stream = new MarkupStream(Markup.of(initialMarkup));
   stream.setCurrentIndex(1);
   choice.onComponentTagBody(stream, new ComponentTag("div", TagType.OPEN));
 }