/**
   * Implements {@link ClientSideConverter#generateClientSideConverter(FacesContext, UIComponent)}
   */
  public String generateClientSideConverter(FacesContext context, UIComponent component) {
    UIInput input = (UIInput) component;
    DateTimeConverter converter = (DateTimeConverter) input.getConverter();

    String dateType = converter.getType();
    int valueType = TYPE_TIMESTAMP;
    if (StringUtil.isNotEmpty(dateType)) {
      if (dateType.equals(DateTimeConverter.TYPE_DATE)) {
        valueType = TYPE_DATE;
      } else if (dateType.equals(DateTimeConverter.TYPE_TIME)) {
        valueType = TYPE_TIME;
      }
    }

    // TODO in 9.0.2, should update this to handle message changes for SPR#MKEE7TXMLG
    String message;
    if (TYPE_DATE == valueType) {
      message = getMessageDate();
    } else if (TYPE_TIME == valueType) {
      message = getMessageTime();
    } else {
      message = getMessageBoth();
    }

    DojoModuleResource module;
    StringBuilder builder = new StringBuilder();
    switch (valueType) {
      case TYPE_DATE:
        {
          module = ISO_DATE_CONVERTER_MODULE;
          builder.append("new extlib.date.IsoDateConverter({message:"); // $NON-NLS-1$
          JavaScriptUtil.addMessage(builder, message);
          builder.append("})"); // $NON-NLS-1$
          break;
        }
      case TYPE_TIME:
        {
          module = ISO_TIME_CONVERTER_MODULE;
          builder.append("new extlib.date.IsoTimeConverter({message:"); // $NON-NLS-1$
          JavaScriptUtil.addMessage(builder, message);
          builder.append("})"); // $NON-NLS-1$
          break;
        }
      default:
        { // TYPE_TIMESTAMP
          module = ISO_DATE_TIME_CONVERTER_MODULE;
          builder.append("new extlib.date.IsoDateTimeConverter({message:"); // $NON-NLS-1$
          JavaScriptUtil.addMessage(builder, message);
          builder.append("})"); // $NON-NLS-1$
          break;
        }
    }
    if (null != module) {
      UIViewRootEx rootEx = (UIViewRootEx) context.getViewRoot();
      rootEx.addEncodeResource(context, module);
    }
    return builder.toString();
  }
  // === continue code from InputRendererUtil ===
  // ClientSide validation
  // com.ibm.xsp.renderkit.html_basic.InputRendererUtil.generateClientSideValidation(FacesContext,
  // UIInput, ResponseWriter)
  private void generateClientSideValidation(
      FacesContext context, UIInput uiInput, ResponseWriter writer) throws IOException {
    // Check if the input field is required
    boolean required = uiInput.isRequired();
    Converter c = InputRendererUtil.findConverter(context, uiInput);
    Validator[] v = uiInput.getValidators();

    // Check if it might make sense to generate a function
    boolean validate = required;
    if (!validate) {
      validate = c instanceof ClientSideConverter;
    }
    if (!validate) {
      for (int i = 0; i < v.length; i++) {
        validate = v[i] instanceof ClientSideValidator;
        if (validate) {
          break;
        }
      }
    }

    if (validate) {
      // This flag is maintained if we actually need to generate the function
      // Some converter/validator may not actually generate any client code, depending on their
      // parameters
      validate = false;

      StringBuilder b = new StringBuilder(128);
      b.append("XSP.attachValidator("); // $NON-NLS-1$
      JavaScriptUtil.addString(b, uiInput.getClientId(context));

      // Add the required flag
      if (required) {
        b.append(",new XSP.RequiredValidator("); // $NON-NLS-1$
        JavaScriptUtil.addMessage(b, InputRendererUtil.getRequiredMessage(context, uiInput));
        b.append(")");
        validate = true;
      } else {
        b.append(",null"); // $NON-NLS-1$
      }

      // Add the converter
      if (c instanceof ClientSideConverter) {
        ClientSideConverter clientSideConverter = (ClientSideConverter) c;
        // TODO this is handling of converterRenderer
        // differs from the original implementation in InputRendererUtil.
        String s;
        Renderer renderer =
            FacesUtil.getRenderer(context, uiInput.getFamily(), uiInput.getRendererType());
        ClientSideConverter converterRenderer =
            (ClientSideConverter) FacesUtil.getRendererAs(renderer, ClientSideConverter.class);
        if (null != converterRenderer) {
          // if the control renderer implements ClientSideConverter
          // delegate to the renderer instead of to the converter.
          s = converterRenderer.generateClientSideConverter(context, uiInput);
        } else {
          s = clientSideConverter.generateClientSideConverter(context, uiInput);
        }
        if (StringUtil.isNotEmpty(s)) {
          b.append(",");
          b.append(s); // not JSUtil because contains client script.
          validate = true;
        } else {
          b.append(",null"); // $NON-NLS-1$
        }
      } else {
        b.append(",null"); // $NON-NLS-1$
      }

      // And add the validator
      for (int i = 0; i < v.length; i++) {
        if (v[i] instanceof ClientSideValidator) {
          String s = ((ClientSideValidator) v[i]).generateClientSideValidation(context, uiInput);
          if (StringUtil.isNotEmpty(s)) {
            b.append(",");
            b.append(s); // not JSUtil because contains client script.
            validate = true;
          }
        }
      }

      // Finally, check for multiple values
      String multiSep = null;
      if (uiInput instanceof UIInputEx) {
        multiSep = ((UIInputEx) uiInput).getMultipleSeparator();
      }
      if (c instanceof ListConverter) {
        multiSep = ((ListConverter) c).getDelimiter();
        if (StringUtil.isEmpty(multiSep)) {
          multiSep = ","; // $NON-NLS-1$
        }
      }
      if (StringUtil.isNotEmpty(multiSep)) {
        b.append(",");
        JSUtil.addString(b, multiSep);
      }

      b.append(");");

      // get the scriptcollector component (needed to add script blocks the the rendered output).
      if (validate) {
        JavaScriptUtil.addScriptOnLoad(b.toString());
      }
    }
  }