// TODO nick - the same as in PanelMenuGroupRenderer
  public void encodeTdIcon(
      ResponseWriter writer,
      FacesContext context,
      String classPrefix,
      String attrIconValue,
      PanelIcons.State state)
      throws IOException {
    if (!isIconRendered(attrIconValue)) {
      return;
    }

    writer.startElement(TD_ELEM, null);
    try {
      PanelIcons icon = PanelIcons.valueOf(attrIconValue);
      writer.writeAttribute(
          CLASS_ATTRIBUTE, concatClasses(classPrefix, state.getCssClass(icon)), null);
    } catch (IllegalArgumentException e) {
      writer.writeAttribute(CLASS_ATTRIBUTE, classPrefix, null);
      if (attrIconValue != null && attrIconValue.trim().length() != 0) {
        writer.startElement(HtmlConstants.IMG_ELEMENT, null);
        writer.writeAttribute(HtmlConstants.ALT_ATTRIBUTE, "", null);
        writer.writeURIAttribute(
            HtmlConstants.SRC_ATTRIBUTE,
            RenderKitUtils.getResourceURL(attrIconValue, context),
            null);
        writer.endElement(HtmlConstants.IMG_ELEMENT);
      }
    }

    writer.endElement(TD_ELEM);
  }
 public static void encodeImage(
     ResponseWriter writer, FacesContext context, String attrIconValue, String styleClass)
     throws IOException {
   writer.startElement(IMG_ELEMENT, null);
   writer.writeAttribute(ALT_ATTRIBUTE, "", null);
   writer.writeAttribute(CLASS_ATTRIBUTE, styleClass, null);
   writer.writeURIAttribute(
       SRC_ATTRIBUTE, RenderKitUtils.getResourceURL(attrIconValue, context), null);
   writer.endElement(IMG_ELEMENT);
 }
  @Override
  protected void doEncodeChildren(
      ResponseWriter writer, FacesContext facesContext, UIComponent component) throws IOException {
    AbstractDataGrid dataGrid = (AbstractDataGrid) component;
    writer.startElement(HtmlConstants.TABLE_ELEMENT, dataGrid);
    writer.writeAttribute(HtmlConstants.ID_ATTRIBUTE, dataGrid.getClientId(facesContext), null);
    Map<String, Object> attributes = dataGrid.getAttributes();
    String classes = concatClasses("rf-dg", attributes.get(HtmlConstants.STYLE_CLASS_ATTR));
    writer.writeAttribute(HtmlConstants.CLASS_ATTRIBUTE, classes, null);
    RenderKitUtils.renderAttribute(
        facesContext, "style", attributes.get(HtmlConstants.STYLE_ATTRIBUTE));
    RenderKitUtils.renderAttribute(
        facesContext, HtmlConstants.TITLE_ATTRIBUTE, attributes.get(HtmlConstants.TITLE_ATTRIBUTE));
    encodeCaption(writer, facesContext, dataGrid);
    encodeHeader(writer, facesContext, dataGrid, false);
    encodeFooter(writer, facesContext, dataGrid, false);
    encodeTBody(writer, facesContext, dataGrid, false);

    writer.endElement(HtmlConstants.TABLE_ELEMENT);
  }
  protected void encodeCustomIcon(
      FacesContext context, UIComponent component, String styleClass, String iconSource)
      throws IOException {
    ResponseWriter writer = context.getResponseWriter();

    writer.startElement(HtmlConstants.IMG_ELEMENT, component);
    writer.writeAttribute(HtmlConstants.CLASS_ATTRIBUTE, styleClass, null);
    writer.writeAttribute(HtmlConstants.ALT_ATTRIBUTE, "", null);
    writer.writeURIAttribute(
        HtmlConstants.SRC_ATTRIBUTE, RenderKitUtils.getResourceURL(iconSource, context), null);
    writer.endElement(HtmlConstants.IMG_ELEMENT);
  }
  public List<Map<String, Object>> getMenuGroups(FacesContext facesContext, UIComponent component) {
    List<Map<String, Object>> results = new ArrayList<Map<String, Object>>();
    List<AbstractMenuGroup> groups = new ArrayList<AbstractMenuGroup>();
    if (component instanceof AbstractDropDownMenu) {
      if (component.isRendered() && !((AbstractDropDownMenu) component).isDisabled()) {
        getMenuGroups(component, groups);
      }
    }
    for (AbstractMenuGroup group : groups) {
      if (group.isRendered() && !group.isDisabled()) {
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("id", group.getClientId(facesContext));
        RenderKitUtils.addToScriptHash(
            map, "onhide", group.getOnhide(), null, ScriptHashVariableWrapper.eventHandler);
        RenderKitUtils.addToScriptHash(
            map, "onshow", group.getOnshow(), null, ScriptHashVariableWrapper.eventHandler);
        RenderKitUtils.addToScriptHash(map, "verticalOffset", group.getVerticalOffset(), "0");
        RenderKitUtils.addToScriptHash(map, "horizontalOffset", group.getHorizontalOffset(), "0");

        Positioning jointPoint = group.getJointPoint();
        if (jointPoint == null) {
          jointPoint = org.richfaces.component.Positioning.DEFAULT;
        }
        RenderKitUtils.addToScriptHash(
            map,
            "jointPoint",
            jointPoint.getValue(),
            org.richfaces.component.Positioning.DEFAULT.getValue());

        Positioning direction = group.getDirection();
        if (direction == null) {
          direction = org.richfaces.component.Positioning.DEFAULT;
        }
        RenderKitUtils.addToScriptHash(
            map,
            "direction",
            direction.getValue(),
            org.richfaces.component.Positioning.DEFAULT.getValue());

        results.add(map);
      }
    }
    return results;
  }
/**
 * @author akolonitsky
 * @author <a href="http://community.jboss.org/people/bleathem">Brian Leathem</a>
 */
@ResourceDependencies({
  @ResourceDependency(library = "javax.faces", name = "jsf.js"),
  @ResourceDependency(library = "org.richfaces", name = "jquery.js"),
  @ResourceDependency(library = "org.richfaces", name = "richfaces.js"),
  @ResourceDependency(library = "org.richfaces", name = "richfaces-queue.reslib"),
  @ResourceDependency(library = "org.richfaces", name = "common/richfaces-base-component.js"),
  @ResourceDependency(library = "org.richfaces", name = "richfaces-event.js"),
  @ResourceDependency(library = "org.richfaces", name = "toggle/togglePanel/togglePanel.js"),
  @ResourceDependency(library = "org.richfaces", name = "toggle/tabPanel/tabPanel.js"),
  @ResourceDependency(library = "org.richfaces", name = "toggle/tabPanel/tabPanel.ecss")
})
@JsfRenderer(type = "org.richfaces.ui.TabPanelRenderer", family = AbstractTabPanel.COMPONENT_FAMILY)
public class TabPanelRenderer extends TogglePanelRenderer {
  private static final RenderKitUtils.Attributes HEADER_ATTRIBUTES =
      RenderKitUtils.attributes()
          .generic("onclick", "onheaderclick", "headerclick")
          .generic("ondblclick", "onheaderdblclick", "headerdblclick")
          .generic("onmousedown", "onheadermousedown", "headermousedown")
          .generic("onmousemove", "onheadermousemove", "headermousemove")
          .generic("onmouseup", "onheadermouseup", "headermouseup");
  private static final String DIV = DIV_ELEM;
  private static final String STYLE = STYLE_ATTRIBUTE;
  private static final String CLASS = CLASS_ATTRIBUTE;

  @Override
  protected boolean isSubmitted(FacesContext context, AbstractTogglePanel panel) {
    String activePanelName = panel.getSubmittedActiveItem();
    String clientId = panel.getClientIdByName(activePanelName);
    if (clientId == null) {
      return false;
    }
    Map<String, String> parameterMap = context.getExternalContext().getRequestParameterMap();
    return parameterMap.get(clientId) != null;
  }

  @Override
  protected void doEncodeBegin(ResponseWriter w, FacesContext context, UIComponent component)
      throws IOException {
    super.doEncodeBegin(w, context, component);

    AbstractTabPanel tabPanel = (AbstractTabPanel) component;
    if (tabPanel.isHeaderPositionedTop()) {
      writeTabsLine(w, context, component);
      writeTabsLineSeparator(w, component);
    }
  }

  private void writeTabsLineSeparator(ResponseWriter writer, UIComponent component)
      throws IOException {
    writer.startElement(DIV, component);
    writer.writeAttribute(CLASS_ATTRIBUTE, "rf-tab-hdr-brd", null);
    writer.endElement(DIV);
  }

  private void writeTabsLine(ResponseWriter w, FacesContext context, UIComponent comp)
      throws IOException {
    w.startElement(DIV, comp);
    String id = comp.getClientId() + AbstractTabPanel.HEADER_META_COMPONENT;
    w.writeAttribute(ID_ATTRIBUTE, id, null);
    AbstractTabPanel tabPanel = (AbstractTabPanel) comp;
    if (tabPanel.isHeaderPositionedTop()) {
      w.writeAttribute(CLASS, "rf-tab-hdr-tabline-vis rf-tab-hdr-tabline-top", null);
    } else {
      w.writeAttribute(CLASS, "rf-tab-hdr-tabline-vis rf-tab-hdr-tabline-btm", null);
    }
    w.startElement("table", comp);
    w.writeAttribute(CLASS_ATTRIBUTE, "rf-tab-hdr-tabs", null);
    w.writeAttribute("cellspacing", "0", null);
    w.startElement(TBODY_ELEMENT, comp);
    w.startElement(TR_ELEMENT, comp);

    writeTopTabFirstSpacer(w, comp);

    writeTabLine(w, context, tabPanel);

    writeTopTabLastSpacer(w, comp);

    w.endElement(TR_ELEMENT);
    w.endElement(TBODY_ELEMENT);
    w.endElement("table");

    writeTopTabsControl(w, comp, "rf-tab-hdr-scrl-lft rf-tab-hdn", "\u00AB");
    writeTopTabsControl(w, comp, "rf-tab-hdr-tablst rf-tab-hdn", "\u2193");
    writeTopTabsControl(w, comp, "rf-tab-hdr-scrl-rgh rf-tab-hdn", "\u00BB");

    w.endElement(DIV_ELEM);
  }

  private void writeTabLine(
      final ResponseWriter w, final FacesContext context, final AbstractTabPanel panel)
      throws IOException {
    panel.visitTogglePanelItems(
        panel,
        new TogglePanelVisitCallback() {
          @Override
          public VisitResult visit(FacesContext context, TogglePanelVisitState visitState) {
            AbstractTogglePanelItemInterface item = visitState.getItem();
            if (item.isRendered() && item instanceof AbstractTab) {
              try {
                AbstractTab tab = (AbstractTab) item;
                writeTopTabHeader(context, w, tab);
                writeTopTabSpacer(w, panel);
              } catch (IOException e) {
                throw new FacesException(e);
              }
            }
            return VisitResult.ACCEPT;
          }
        });
  }

  @Override
  protected String getStyle(UIComponent component) {
    return attributeAsString(component, "style");
  }

  @Override
  protected String getStyleClass(UIComponent component) {
    return HtmlUtil.concatClasses("rf-tbp", attributeAsString(component, "styleClass"));
  }

  private void writeTopTabHeader(FacesContext context, ResponseWriter writer, AbstractTab tab)
      throws IOException {
    boolean isActive = tab.isActive();
    boolean isDisabled = tab.isDisabled();
    // TODO: Ilya, review. Much HTML because we always encoding all states. Need to optimize
    // somehow.
    encodeTabHeader(context, tab, writer, inactive, !isActive && !isDisabled);
    encodeTabHeader(context, tab, writer, active, isActive && !isDisabled);
    encodeTabHeader(context, tab, writer, disabled, isDisabled);
  }

  private String positionAbbreviation(AbstractTab tab) {
    if (tab.getParentPanel().isHeaderPositionedTop()) {
      return "top";
    } else {
      return "btm";
    }
  }

  @Override
  public void encodeMetaComponent(
      FacesContext context, UIComponent component, String metaComponentId) throws IOException {
    if (AbstractTabPanel.HEADER_META_COMPONENT.equals(metaComponentId)) {
      AbstractTabPanel panel = (AbstractTabPanel) component;
      PartialResponseWriter w = context.getPartialViewContext().getPartialResponseWriter();
      String id = component.getClientId() + AbstractTabPanel.HEADER_META_COMPONENT;
      w.startUpdate(id);
      writeTabsLine(w, context, panel);
      w.endUpdate();
    } else {
      super.encodeMetaComponent(context, component, metaComponentId);
    }
  }

  private void encodeTabHeader(
      FacesContext context,
      AbstractTab tab,
      ResponseWriter writer,
      AbstractTogglePanelTitledItem.HeaderStates state,
      Boolean isDisplay)
      throws IOException {

    String headerStateClass = "rf-tab-hdr-" + state.abbreviation();
    String headerPositionClass = "rf-tab-hdr-" + positionAbbreviation(tab);

    writer.startElement(TD_ELEM, tab);
    writer.writeAttribute(
        ID_ATTRIBUTE, tab.getClientId(context) + ":header:" + state.toString(), null);
    renderPassThroughAttributes(context, tab, HEADER_ATTRIBUTES);
    writer.writeAttribute(
        CLASS_ATTRIBUTE,
        concatClasses(
            "rf-tab-hdr",
            headerStateClass,
            headerPositionClass,
            attributeAsString(tab, "headerClass"),
            attributeAsString(tab, state.headerClass())),
        null);
    writer.writeAttribute(
        STYLE_ATTRIBUTE,
        concatStyles(isDisplay ? "" : "display : none", attributeAsString(tab, "headerStyle")),
        null);

    writer.startElement(SPAN_ELEM, tab);
    writer.writeAttribute(CLASS_ATTRIBUTE, "rf-tab-lbl", null);

    UIComponent headerFacet = tab.getHeaderFacet(state);
    if (headerFacet != null && headerFacet.isRendered()) {
      headerFacet.encodeAll(context);
    } else {
      Object headerText = tab.getAttributes().get("header");
      if (headerText != null && !headerText.equals("")) {
        writer.writeText(headerText, null);
      }
    }

    writer.endElement(SPAN_ELEM);

    writer.endElement(TD_ELEM);
  }

  private void writeTopTabsControl(ResponseWriter w, UIComponent comp, String styles, String text)
      throws IOException {
    w.startElement(DIV_ELEM, comp);
    w.writeAttribute(CLASS_ATTRIBUTE, styles, null);
    w.writeText(text, null);
    w.endElement(DIV_ELEM);
  }

  private void writeTopTabFirstSpacer(ResponseWriter w, UIComponent comp) throws IOException {
    AbstractTabPanel tabPanel = (AbstractTabPanel) comp;
    if (tabPanel.isHeaderAlignedLeft()) {
      writeTopTabSpacer(w, comp, "padding-left: 5px;", "rf-tab-hdr-spcr");
    } else {
      writeTopTabSpacer(w, comp, "padding-left: 5px; width:100%", "rf-tab-hdr-spcr");
    }
  }

  private void writeTopTabSpacer(ResponseWriter w, UIComponent comp) throws IOException {
    writeTopTabSpacer(w, comp, "", "rf-tab-hdr-spcr rf-tab-hortab-tabspcr-wdh");
  }

  private void writeTopTabLastSpacer(ResponseWriter w, UIComponent comp) throws IOException {
    AbstractTabPanel tabPanel = (AbstractTabPanel) comp;
    if (tabPanel.isHeaderAlignedLeft()) {
      writeTopTabSpacer(w, comp, "padding-right: 5px; width: 100%;", "rf-tab-hdr-spcr");
    } else {
      writeTopTabSpacer(w, comp, "padding-right: 5px;", "rf-tab-hdr-spcr");
    }
  }

  private void writeTopTabSpacer(
      ResponseWriter w, UIComponent comp, String style, String styleClass) throws IOException {
    w.startElement(TD_ELEM, comp);
    w.writeAttribute(STYLE, style, null);
    w.writeAttribute(CLASS, styleClass, null);
    w.write("<br />");
    w.endElement(TD_ELEM);
  }

  @Override
  protected void doEncodeEnd(
      final ResponseWriter writer, FacesContext context, UIComponent component) throws IOException {
    AbstractTabPanel panel = (AbstractTabPanel) component;
    if (!panel.isHeaderPositionedTop()) {
      writeTabsLineSeparator(writer, component);
      writeTabsLine(writer, context, component);
    }
    writer.endElement(HtmlConstants.DIV_ELEM);
  }

  @Override
  protected JSObject getScriptObject(FacesContext context, UIComponent component) {
    return new JSObject(
        "RichFaces.ui.TabPanel",
        component.getClientId(context),
        getScriptObjectOptions(context, component));
  }

  @Override
  protected Map<String, Object> getScriptObjectOptions(
      FacesContext context, UIComponent component) {
    Map<String, Object> options = super.getScriptObjectOptions(context, component);

    options.put("isKeepHeight", attributeAsString(component, "height").length() > 0);

    return options;
  }

  @Override
  protected Class<? extends UIComponent> getComponentClass() {
    return AbstractTabPanel.class;
  }
}
  @Override
  protected Map<String, Object> getScriptObjectOptions(
      FacesContext context, UIComponent component) {
    AbstractTooltip tooltip = (AbstractTooltip) component;

    Map<String, Object> options = new HashMap<String, Object>();

    RenderKitUtils.addToScriptHash(
        options, "ajax", getAjaxOptions(context, tooltip), TooltipMode.DEFAULT);

    Positioning jointPoint = tooltip.getJointPoint();
    if (jointPoint == null) {
      jointPoint = org.richfaces.component.Positioning.DEFAULT;
    }
    Positioning direction = tooltip.getDirection();
    if (direction == null) {
      direction = org.richfaces.component.Positioning.DEFAULT;
    }

    RenderKitUtils.addToScriptHash(
        options, "jointPoint", jointPoint.getValue(), Positioning.DEFAULT.getValue());
    RenderKitUtils.addToScriptHash(
        options, "direction", direction.getValue(), Positioning.DEFAULT.getValue());
    RenderKitUtils.addToScriptHash(options, "attached", tooltip.isAttached(), true);
    RenderKitUtils.addToScriptHash(options, "offset", getOffset(tooltip));
    RenderKitUtils.addToScriptHash(options, "mode", tooltip.getMode(), TooltipMode.DEFAULT);
    RenderKitUtils.addToScriptHash(options, "hideDelay", tooltip.getHideDelay(), 0);
    RenderKitUtils.addToScriptHash(options, "hideEvent", tooltip.getHideEvent(), "mouseleave");
    RenderKitUtils.addToScriptHash(options, "showDelay", tooltip.getShowDelay(), 0);
    RenderKitUtils.addToScriptHash(options, "showEvent", tooltip.getShowEvent(), "mouseenter");
    RenderKitUtils.addToScriptHash(options, "followMouse", tooltip.isFollowMouse(), true);
    RenderKitUtils.addToScriptHash(
        options,
        "target",
        RENDERER_UTILS.findComponentFor(component, tooltip.getTarget()).getClientId(context));

    addEventOption(context, tooltip, options, HIDE);
    addEventOption(context, tooltip, options, SHOW);
    addEventOption(context, tooltip, options, BEFORE_HIDE);
    addEventOption(context, tooltip, options, BEFORE_SHOW);

    return options;
  }
 @Override
 public void renderInputHandlers(FacesContext facesContext, UIComponent component)
     throws IOException {
   RenderKitUtils.renderPassThroughAttributesOptimized(
       facesContext, component, INPLACE_INPUT_HANDLER_ATTRIBUTES);
 }
 public void renderListHandlers(FacesContext facesContext, UIComponent component)
     throws IOException {
   RenderKitUtils.renderPassThroughAttributesOptimized(
       facesContext, component, SelectHelper.SELECT_LIST_HANDLER_ATTRIBUTES);
 }
 protected void renderRowHandlers(FacesContext context, UIDataTableBase dataTable)
     throws IOException {
   RenderKitUtils.renderPassThroughAttributesOptimized(context, dataTable, ROW_HANDLER_ATTRIBUTES);
 }