/**
 * Specialization of filterHtmlAttributes for Incremental DOM that can handle
 * attribute functions gracefully. In any other situation, this delegates to
 * the regular escaping directive.
 */
// tslint:disable-next-line:no-any
function filterHtmlAttributes(value: any) {
  if (isIdomFunctionType(value, SanitizedContentKind.ATTRIBUTES) ||
      isAttribute(value)) {
    return value;
  }
  return soy.$$filterHtmlAttributes(value);
}
/**
 * Prints an expression whose type is not statically known to be of type
 * "attributes". The expression is tested at runtime and evaluated depending
 * on what type it is. For example, if a string is printed in a context
 * that expects attributes, the string is evaluated dynamically to compute
 * attributes.
 */
function printDynamicAttr(
    incrementaldom: IncrementalDomRenderer,
    expr: SanitizedHtmlAttribute|string|boolean|IdomFunction) {
  if (goog.isFunction(expr) &&
      (expr as IdomFunction).contentKind === SanitizedContentKind.ATTRIBUTES) {
    // tslint:disable-next-line:no-any
    (expr as any as LetFunction)(incrementaldom);
    return;
  }
  const attributes = splitAttributes(expr.toString());
  const isExprAttribute = isAttribute(expr);
  for (const attribute of attributes) {
    const attrName = isExprAttribute ? attribute[0] :
                                       soy.$$filterHtmlAttributes(attribute[0]);
    if (attrName === 'zSoyz') {
      incrementaldom.attr(attrName, '');
    } else {
      incrementaldom.attr(String(attrName), String(attribute[1]));
    }
  }
}
/**
 * Calls an expression in case of a function or outputs it as text content.
 */
function callDynamicAttributes<A, B>(
    incrementaldom: IncrementalDomRenderer,
    // tslint:disable-next-line:no-any
    expr: Template<A, B>, data: A, ij: B) {
  // tslint:disable-next-line:no-any Attaching arbitrary attributes to function.
  const type = (expr as any as IdomFunction).contentKind;
  if (type === SanitizedContentKind.ATTRIBUTES) {
    (expr as IdomTemplate<A, B>)(incrementaldom, data, ij);
  } else {
    let val: string|SanitizedHtmlAttribute;
    if (type === SanitizedContentKind.HTML) {
      // This effectively negates the value of splitting a string. However,
      // This can be removed if Soy decides to treat attribute printing
      // and attribute names differently.
      val = soy.$$filterHtmlAttributes(htmlToString(
          () => (expr as IdomTemplate<A, B>)(defaultIdomRenderer, data, ij)));
    } else {
      val = (expr as SoyTemplate<A, B>)(data, ij) as SanitizedHtmlAttribute;
    }
    printDynamicAttr(incrementaldom, val);
  }
}