public void encodeClientScript(
      ResponseWriter writer, FacesContext facesContext, UIDataTableBase component)
      throws IOException {
    AbstractCollapsibleSubTable subTable = (AbstractCollapsibleSubTable) component;

    String id = subTable.getClientId(facesContext);

    UIComponent nestingForm = getUtils().getNestingForm(subTable);
    String formId = nestingForm != null ? nestingForm.getClientId(facesContext) : "";

    Map<String, Object> options = new HashMap<String, Object>();
    options.put("stateInput", subTable.getClientId(facesContext) + STATE);
    options.put("optionsInput", subTable.getClientId(facesContext) + OPTIONS);
    options.put("expandMode", subTable.getExpandMode());
    options.put("eventOptions", AjaxRendererUtils.buildEventOptions(facesContext, subTable));

    JSFunction jsFunction = new JSFunction("new RichFaces.ui.CollapsibleSubTable");
    jsFunction.addParameter(id);
    jsFunction.addParameter(formId);
    jsFunction.addParameter(options);

    writer.startElement(HtmlConstants.SCRIPT_ELEM, subTable);
    writer.writeAttribute(HtmlConstants.TYPE_ATTR, HtmlConstants.JAVASCRIPT_TYPE, null);
    writer.writeText(jsFunction.toScript(), null);
    writer.endElement(HtmlConstants.SCRIPT_ELEM);
  }
  protected void doDecode(FacesContext facesContext, UIComponent component) {
    AbstractCollapsibleSubTable subTable = (AbstractCollapsibleSubTable) component;

    String clientId = subTable.getClientId(facesContext);
    Map<String, String> requestMap = facesContext.getExternalContext().getRequestParameterMap();

    String optionsId = clientId + OPTIONS;
    String togglerId = requestMap.get(optionsId);

    String stateId = clientId + STATE;
    String state = (String) requestMap.get(stateId);

    boolean isExpanded = true;
    if (state != null) {
      int newValue = Integer.parseInt(state);

      if (newValue < 1) {
        isExpanded = false;
      }

      if (subTable.isExpanded() != isExpanded) {
        new CollapsibleSubTableToggleEvent(subTable, isExpanded, togglerId).queue();
      }
    }
  }
  public void encodeHiddenInput(
      ResponseWriter writer, FacesContext facesContext, UIDataTableBase dataTableBase)
      throws IOException {
    AbstractCollapsibleSubTable subTable = (AbstractCollapsibleSubTable) dataTableBase;

    String stateId = subTable.getClientId(facesContext) + STATE;

    writer.startElement(HtmlConstants.INPUT_ELEM, subTable);
    writer.writeAttribute(HtmlConstants.ID_ATTRIBUTE, stateId, null);
    writer.writeAttribute(HtmlConstants.NAME_ATTRIBUTE, stateId, null);
    writer.writeAttribute(HtmlConstants.TYPE_ATTR, HtmlConstants.INPUT_TYPE_HIDDEN, null);

    int state =
        subTable.isExpanded()
            ? AbstractCollapsibleSubTable.EXPANDED_STATE
            : AbstractCollapsibleSubTable.COLLAPSED_STATE;

    writer.writeAttribute(HtmlConstants.VALUE_ATTRIBUTE, state, null);
    writer.endElement(HtmlConstants.INPUT_ELEM);

    String optionsId = subTable.getClientId(facesContext) + OPTIONS;
    writer.startElement(HtmlConstants.INPUT_ELEM, subTable);
    writer.writeAttribute(HtmlConstants.ID_ATTRIBUTE, optionsId, null);
    writer.writeAttribute(HtmlConstants.NAME_ATTRIBUTE, optionsId, null);
    writer.writeAttribute(HtmlConstants.TYPE_ATTR, HtmlConstants.INPUT_TYPE_HIDDEN, null);
    writer.endElement(HtmlConstants.INPUT_ELEM);
  }
 public void begin(
     ResponseWriter writer, FacesContext context, UIComponent component, Object[] params)
     throws IOException {
   AbstractCollapsibleSubTable subTable = (AbstractCollapsibleSubTable) component;
   writer.startElement(HtmlConstants.TR_ELEMENT, subTable);
   writer.writeAttribute(
       HtmlConstants.ID_ATTRIBUTE,
       subTable.getContainerClientId(context) + HIDDEN_CONTAINER_ID,
       null);
   writer.writeAttribute(HtmlConstants.STYLE_ATTRIBUTE, DISPLAY_NONE, null);
   writer.startElement(HtmlConstants.TD_ELEM, subTable);
 }
  @Override
  public void encodeMetaComponent(
      FacesContext facesContext, UIComponent component, String metaComponentId) throws IOException {
    AbstractCollapsibleSubTable subTable = (AbstractCollapsibleSubTable) component;

    if (AbstractCollapsibleSubTable.BODY.equals(metaComponentId)) {
      ResponseWriter writer = facesContext.getResponseWriter();
      UIDataTableBase dataTableBase = findParent(subTable);

      String updateId =
          dataTableBase.getRelativeClientId(facesContext) + ":" + subTable.getId() + TB_ROW;

      partialStart(facesContext, updateId);
      encodeTableRows(writer, facesContext, subTable, false);
      partialEnd(facesContext);
    }
  }
  public void encodeTableFacets(
      ResponseWriter writer, FacesContext context, UIDataTableBase dataTable) throws IOException {
    AbstractCollapsibleSubTable subTable = (AbstractCollapsibleSubTable) dataTable;

    encodeStyle(writer, context, subTable, null);

    encodeHeaderFacet(writer, context, subTable, false);

    String rowClass = getRowSkinClass();
    String cellClass = getCellSkinClass();
    String firstClass = getFirstRowSkinClass();

    rowClass = mergeStyleClasses("rowClass", rowClass, subTable);
    cellClass = mergeStyleClasses("cellClass", cellClass, subTable);
    firstClass = mergeStyleClasses("firstRowClass", firstClass, subTable);

    saveRowStyles(context, subTable.getContainerClientId(context), firstClass, rowClass, cellClass);
  }
  @Override
  public void encodeTableBodyStart(
      ResponseWriter writer, FacesContext facesContext, UIDataTableBase dataTableBase)
      throws IOException {
    AbstractCollapsibleSubTable subTable = (AbstractCollapsibleSubTable) dataTableBase;

    UIDataTableBase component = findParent(subTable);
    if (component instanceof AbstractDataTable) {
      writer.startElement(HtmlConstants.TBODY_ELEMENT, null);
      writer.writeAttribute(
          HtmlConstants.ID_ATTRIBUTE,
          component.getRelativeClientId(facesContext) + ":" + subTable.getId() + TB_ROW,
          null);
      writer.writeAttribute(HtmlConstants.CLASS_ATTRIBUTE, getTableSkinClass(), null);

      String predefinedStyles = !subTable.isExpanded() ? DISPLAY_NONE : null;
      encodeStyle(writer, facesContext, subTable, predefinedStyles);
    }
  }
 private void encodeSubTableDomElement(
     ResponseWriter writer, FacesContext facesContext, AbstractCollapsibleSubTable subTable)
     throws IOException {
   writer.startElement(HtmlConstants.TR_ELEMENT, subTable);
   writer.writeAttribute(HtmlConstants.STYLE_ATTRIBUTE, DISPLAY_NONE, null);
   writer.writeAttribute(
       HtmlConstants.ID_ATTRIBUTE, subTable.getContainerClientId(facesContext), null);
   writer.startElement(HtmlConstants.TD_ELEM, subTable);
   writer.endElement(HtmlConstants.TD_ELEM);
   writer.endElement(HtmlConstants.TR_ELEMENT);
 }
  protected UIDataTableBase findParent(AbstractCollapsibleSubTable subTable) {
    UIComponent parent = subTable.getParent();

    while (parent != null && !(parent instanceof UIDataTableBase)) {
      parent = parent.getParent();
    }

    if (parent == null) {
      // TODO: anton -> do we need this?
      throw new AbortProcessingException(
          "UISubTable should be a child of UIDataTable or UISubTable");
    }
    return (UIDataTableBase) parent;
  }