private static String getSubmitHandler(
      FacesContext context,
      UIComponent component,
      Collection<ClientBehaviorContext.Parameter> params,
      boolean preventDefault) {

    StringBuilder builder = new StringBuilder(256);

    String formClientId = getFormClientId(component, context);
    String componentClientId = component.getClientId(context);

    builder.append("qab.sf(document.getElementById('");
    builder.append(formClientId);
    builder.append("'),{");

    appendProperty(builder, componentClientId, componentClientId);

    if ((null != params) && (!params.isEmpty())) {
      for (ClientBehaviorContext.Parameter param : params) {
        appendProperty(builder, param.getName(), param.getValue());
      }
    }

    builder.append("})");

    if (preventDefault) {
      builder.append(";return false");
    }

    return builder.toString();
  }
  private static void renderPassThruAttributesUnoptimized(
      FacesContext context,
      ResponseWriter writer,
      UIComponent component,
      Attribute[] knownAttributes,
      Map<String, List<ClientBehavior>> behaviors)
      throws IOException {

    boolean isXhtml = XHTML_CONTENT_TYPE.equals(writer.getContentType());

    Map<String, Object> attrMap = component.getAttributes();

    for (Attribute attribute : knownAttributes) {
      String attrName = attribute.getName();
      String[] events = attribute.getEvents();
      boolean hasBehavior =
          ((events != null) && (events.length > 0) && (behaviors.containsKey(events[0])));

      Object value = attrMap.get(attrName);

      if (value != null && shouldRenderAttribute(value) && !hasBehavior) {
        writer.writeAttribute(prefixAttribute(attrName, isXhtml), value, attrName);
      } else if (hasBehavior) {

        renderHandler(context, component, null, attrName, value, events[0]);
      }
    }
  }
  public static String getFormClientId(UIComponent component, FacesContext context) {

    UIComponent parent = component.getParent();
    while (parent != null) {
      if (parent instanceof UIForm) {
        break;
      }
      parent = parent.getParent();
    }

    UIForm form = (UIForm) parent;
    if (form != null) {
      return form.getClientId(context);
    }

    return null;
  }
  @SuppressWarnings("unchecked")
  public static void renderPassThruAttributes(
      FacesContext context,
      ResponseWriter writer,
      UIComponent component,
      Attribute[] attributes,
      Map<String, List<ClientBehavior>> behaviors)
      throws IOException {

    if (behaviors == null) {
      behaviors = Collections.emptyMap();
    }

    if ((behaviors.size() < 2)) {
      List<String> setAttributes =
          (List<String>) component.getAttributes().get(ATTRIBUTES_THAT_ARE_SET_KEY);
      if (setAttributes != null) {
        renderPassThruAttributesOptimized(
            context, writer, component, attributes, setAttributes, behaviors);
      }
    } else {
      renderPassThruAttributesUnoptimized(context, writer, component, attributes, behaviors);
    }

    List<String> html5PassThru =
        (List<String>) component.getAttributes().get(HTML5DataRule.HTML5DATAATTRIBUTES);
    if (html5PassThru != null) {
      for (String attribute : html5PassThru) {
        String value;
        if (component.getValueExpression(attribute) != null) {
          Object valueObject =
              component.getValueExpression(attribute).getValue(context.getELContext());
          value = valueObject != null ? valueObject.toString() : null;
        } else {
          value = (String) component.getAttributes().get(attribute);
        }

        if (value != null) {
          writer.writeAttribute(attribute, value, null);
        }
      }
    }
  }
  public static String findClientIds(String ids, UIComponent component, FacesContext context)
      throws IOException {
    if (ids == null) return null;

    StringBuilder clientIds = new StringBuilder();
    String[] idlist = ids.split("[\\s]");
    for (String id : idlist) {
      if (!id.startsWith("@")) {
        UIComponent found = component.findComponent(id);
        if (found != null) {
          if (clientIds.length() > 0) clientIds.append(" ");
          clientIds.append(found.getClientId(context));
        } else {
          throw new IOException("Cannot find id " + id + " within components NamingContainer");
        }
      }
    }

    return clientIds.toString();
  }
  private static void renderPassThruAttributesOptimized(
      FacesContext context,
      ResponseWriter writer,
      UIComponent component,
      Attribute[] knownAttributes,
      List<String> setAttributes,
      Map<String, List<ClientBehavior>> behaviors)
      throws IOException {

    String behaviorEventName = getSingleBehaviorEventName(behaviors);
    boolean renderedBehavior = false;

    Collections.sort(setAttributes);
    boolean isXhtml = XHTML_CONTENT_TYPE.equals(writer.getContentType());
    Map<String, Object> attrMap = component.getAttributes();
    for (String name : setAttributes) {

      int index = Arrays.binarySearch(knownAttributes, Attribute.attr(name));
      if (index >= 0) {
        Object value = attrMap.get(name);
        if (value != null && shouldRenderAttribute(value)) {

          Attribute attr = knownAttributes[index];

          if (isBehaviorEventAttribute(attr, behaviorEventName)) {
            renderHandler(context, component, null, name, value, behaviorEventName);

            renderedBehavior = true;
          } else {
            writer.writeAttribute(prefixAttribute(name, isXhtml), value, name);
          }
        }
      }
    }

    if ((behaviorEventName != null) && !renderedBehavior) {

      for (int i = 0; i < knownAttributes.length; i++) {
        Attribute attr = knownAttributes[i];
        String[] events = attr.getEvents();
        if ((events != null) && (events.length > 0) && (behaviorEventName.equals(events[0]))) {

          renderHandler(context, component, null, attr.getName(), null, behaviorEventName);
        }
      }
    }
  }
  @SuppressWarnings("rawtypes")
  public static void renderXHTMLStyleBooleanAttributes(ResponseWriter writer, UIComponent component)
      throws IOException {

    assert (writer != null);
    assert (component != null);

    Map attrMap = component.getAttributes();
    for (String attrName : BOOLEAN_ATTRIBUTES) {
      Object val = attrMap.get(attrName);
      if (val == null) {
        continue;
      }

      if (Boolean.valueOf(val.toString())) {
        writer.writeAttribute(attrName, true, attrName);
      }
    }
  }
  @SuppressWarnings("rawtypes")
  public static void renderOnclick(
      FacesContext context,
      UIComponent component,
      Collection<ClientBehaviorContext.Parameter> params)
      throws IOException {

    final String handlerName = "onclick";
    final Object userHandler = component.getAttributes().get(handlerName);
    String behaviorEventName = "action";
    if (component instanceof ClientBehaviorHolder) {
      Map behaviors = ((ClientBehaviorHolder) component).getClientBehaviors();
      if (null != behaviors && behaviors.containsKey("click")) {
        behaviorEventName = "click";
      }
    }

    renderHandler(context, component, params, handlerName, userHandler, behaviorEventName);
  }