NS_IMETHODIMP
nsXFormsControlStub::ResetBoundNode(const nsString &aBindAttribute,
                                    PRUint16        aResultType,
                                    PRBool         *aContextChanged)
{
  NS_ENSURE_ARG(aContextChanged);

  // Clear existing bound node, etc.
  *aContextChanged = mBoundNode ? PR_TRUE : PR_FALSE;
  nsCOMPtr<nsIDOMNode> oldBoundNode;
  oldBoundNode.swap(mBoundNode);
  mUsesModelBinding = PR_FALSE;
  mAppearDisabled = PR_FALSE;
  mDependencies.Clear();
  RemoveIndexListeners();

  if (!mHasParent || !mHasDoc || !HasBindingAttribute())
    return NS_OK_XFORMS_NOTREADY;

  nsCOMPtr<nsIDOMXPathResult> result;
  nsresult rv = ProcessNodeBinding(aBindAttribute, aResultType,
                                   getter_AddRefs(result));

  if (NS_FAILED(rv)) {
    nsXFormsUtils::ReportError(NS_LITERAL_STRING("controlBindError"), mElement);
    return rv;
  }

  if (rv == NS_OK_XFORMS_DEFERRED || rv == NS_OK_XFORMS_NOTREADY || !result) {
    // Binding was deferred, or not bound
    return rv;
  }

  // Get context node, if any
  if (mUsesModelBinding) {
    // When bound via @bind, we'll get a snapshot back
    result->SnapshotItem(0, getter_AddRefs(mBoundNode));
  } else {
    result->GetSingleNodeValue(getter_AddRefs(mBoundNode));
  }

  *aContextChanged = (oldBoundNode != mBoundNode);

  // Some controls may not be bound to certain types of content. If the content
  // is a disallowed type, report the error and dispatch a binding exception
  // event.
  PRBool isAllowed = IsContentAllowed();

  if (!mBoundNode || !isAllowed) {
    // If there's no result (ie, no instance node) returned by the above, it
    // means that the binding is not pointing to an instance data node, so we
    // should disable the control.
    mAppearDisabled = PR_TRUE;

    if (!isAllowed) {
      // build the error string that we want output to the ErrorConsole
      nsAutoString localName;
      mElement->GetLocalName(localName);
      const PRUnichar *strings[] = { localName.get() };

      nsXFormsUtils::ReportError(
        NS_LITERAL_STRING("boundTypeErrorComplexContent"),
        strings, 1, mElement, mElement);

      nsXFormsUtils::DispatchEvent(mElement, eEvent_BindingException);
    }

    nsCOMPtr<nsIXTFElementWrapper> wrapper(do_QueryInterface(mElement));
    NS_ENSURE_STATE(wrapper);

    PRInt32 iState;
    GetDisabledIntrinsicState(&iState);
    return wrapper->SetIntrinsicState(iState);
  }

  // Check for presence of @xsi:type on bound node and add as a dependency
  nsCOMPtr<nsIDOMElement> boundEl(do_QueryInterface(mBoundNode));
  if (boundEl) {
    nsCOMPtr<nsIDOMAttr> attrNode;
    rv = boundEl->GetAttributeNodeNS(NS_LITERAL_STRING(NS_NAMESPACE_XML_SCHEMA_INSTANCE),
                                     NS_LITERAL_STRING("type"),
                                     getter_AddRefs(attrNode));
    if (NS_SUCCEEDED(rv) && attrNode) {
      mDependencies.AppendObject(attrNode);
    }
  }

  return NS_OK;
}
NS_IMETHODIMP
nsXFormsRepeatElement::Refresh()
{
#ifdef DEBUG_XF_REPEAT
  printf("nsXFormsRepeatElement::Refresh()\n");
#endif

  if (mAddingChildren || mIsParent)
    return NS_OK;

  nsPostRefresh postRefresh = nsPostRefresh();

  PRUint32 oldIndex = mCurrentIndex;

  /// @todo The spec says: "This node-set must consist of contiguous child
  /// element nodes, with the same local name and namespace name of a common
  /// parent node. The behavior of element repeat with respect to
  /// non-homogeneous node-sets is undefined."
  /// @see http://www.w3.org/TR/xforms/slice9.html#ui-repeat
  ///
  /// Can/should we check this somehow? (XXX)


  // Get the nodeset we are bound to
  nsresult rv;
  nsCOMPtr<nsIDOMXPathResult> result;
  rv = ProcessNodeBinding(NS_LITERAL_STRING("nodeset"),
                          nsIDOMXPathResult::ORDERED_NODE_SNAPSHOT_TYPE,
                          getter_AddRefs(result));
  NS_ENSURE_SUCCESS(rv, rv);

  // Unroll the repeat rows
  rv = UnrollRows(result);
  NS_ENSURE_SUCCESS(rv, rv);

  // Maintain the index
  if (mCurrentIndex || !mMaxIndex) {
    // Somebody might have been fooling around with our children since last
    // refresh (either using delete or through script). Or we might have an
    // empty nodeset. So fix the index value.
    SanitizeIndex(&mCurrentIndex);
  } else if (mMaxIndex) {
    // repeat-index has not been initialized, set it.
    if (!mParent) {
      GetStartingIndex(&mCurrentIndex);
      // Inform listeners of initial index value
      IndexHasChanged();
    } else if (mLevel > 1) {
      // Set repeat-index for inner repeats. If parent <contextcontainer/>
      // element is selected then mCurrentIndex is setted on starting index.

      nsCOMPtr<nsIDOMNode> temp = mElement;
      nsCOMPtr<nsIDOMNode> parent;
      nsCOMPtr<nsIXFormsRepeatItemElement> context;

      while (!context) {
        rv = temp->GetParentNode(getter_AddRefs(parent));
        NS_ENSURE_SUCCESS(rv, rv);
        if (!parent)
          break;
        context = do_QueryInterface(parent);
        temp.swap(parent);
      }

      if (context) {
        PRBool hasIndex = PR_FALSE;
        context->GetIndexState(&hasIndex);
        if (hasIndex) {
          PRUint32 index = 0;
          GetStartingIndex(&index);
          SetIndex(&index, PR_FALSE);
        }
      }
      return NS_OK;
    }
  }

  // If we have the repeat-index, set it.
  if (mCurrentIndex) {
    SetChildIndex(mCurrentIndex, PR_TRUE, PR_TRUE);
  }

  if (mCurrentIndex != oldIndex) {
    mParent ? mParent->IndexHasChanged() : IndexHasChanged();
  }

  return NS_OK;
}
NS_IMETHODIMP
nsXFormsItemSetElement::Refresh()
{
  // We need to create item elements for each element referenced by the
  // nodeset.  Each of these items will create an anonymous HTML option element
  // which will return from GetAnonymousNodes.  We then clone our template
  // content and insert the cloned content as children of the HTML option.

  if (!nsXFormsUtils::IsDocumentReadyForBind(mElement)) {
    // not ready to bind yet, defer
    nsXFormsModelElement::DeferElementBind(this);
    return NS_OK;
  }

  nsCOMPtr<nsIModelElementPrivate> model;
  nsCOMPtr<nsIDOMXPathResult> result;
  nsresult rv = ProcessNodeBinding(NS_LITERAL_STRING("nodeset"),
                                   nsIDOMXPathResult::ORDERED_NODE_SNAPSHOT_TYPE,
                                   getter_AddRefs(result),
                                   getter_AddRefs(model));

  if (NS_FAILED(rv) | !result | !model)
    return rv;

  nsCOMPtr<nsIDOMNode> node, templateNode, cloneNode, tmpNode;
  nsCOMPtr<nsIDOMElement> itemNode, itemWrapperNode, contextContainer;
  nsCOMPtr<nsIDOMNodeList> templateNodes;
  mElement->GetChildNodes(getter_AddRefs(templateNodes));
  PRUint32 templateNodeCount = 0;
  if (templateNodes)
    templateNodes->GetLength(&templateNodeCount);

  nsCOMPtr<nsIContent> content(do_QueryInterface(mElement));
  NS_ENSURE_STATE(content);
  nsCOMPtr<nsIDocument> doc = content->GetCurrentDoc();
  nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(doc));
  NS_ENSURE_STATE(domDoc);

  PRUint32 nodeCount;
  result->GetSnapshotLength(&nodeCount);

  nsCOMPtr<nsIDOMNode> parent, tmp;
  mElement->GetParentNode(getter_AddRefs(parent));

  while (parent) {
    if (nsXFormsUtils::IsXFormsElement(parent, NS_LITERAL_STRING("select1")) ||
        nsXFormsUtils::IsXFormsElement(parent, NS_LITERAL_STRING("select"))) {
      break;
    }
    tmp.swap(parent);
    tmp->GetParentNode(getter_AddRefs(parent));
  }

  nsCOMPtr<nsIXFormsItemSetUIElement> uiItemSet(do_QueryInterface(mElement));
  nsCOMPtr<nsIDOMElement> anonContent;
  if (uiItemSet) {
    uiItemSet->GetAnonymousItemSetContent(getter_AddRefs(anonContent));
  }

  NS_ENSURE_STATE(anonContent);

  nsCOMPtr<nsIDOMNode> childNode, nodeReturn;
  while (NS_SUCCEEDED(anonContent->GetFirstChild(getter_AddRefs(childNode))) &&
       childNode) {
    anonContent->RemoveChild(childNode, getter_AddRefs(nodeReturn));
  }

  for (PRUint32 i = 0; i < nodeCount; ++i) {
    result->SnapshotItem(i, getter_AddRefs(node));
    NS_ASSERTION(node, "incorrect snapshot length");

    rv = domDoc->CreateElementNS(NS_LITERAL_STRING(NS_NAMESPACE_XFORMS),
                                 NS_LITERAL_STRING("item"),
                                 getter_AddRefs(itemNode));
    NS_ENSURE_SUCCESS(rv, rv);

    anonContent->AppendChild(itemNode, getter_AddRefs(tmpNode));

    nsCOMPtr<nsIXFormsContextControl> ctx(do_QueryInterface(itemNode));
    if (ctx) {
      ctx->SetContext(node, i + 1, nodeCount);
    }

    // Clone the template content under the item
    for (PRUint32 j = 0; j < templateNodeCount; ++j) {
      templateNodes->Item(j, getter_AddRefs(templateNode));
      templateNode->CloneNode(PR_TRUE, getter_AddRefs(cloneNode));
      itemNode->AppendChild(cloneNode, getter_AddRefs(templateNode));
    }

  }

  // refresh parent so that it has a chance to reflect the changes we just made
  if (parent) {
    nsCOMPtr<nsIXFormsControlBase> control = do_QueryInterface(parent);
    if (control) {
      control->Refresh();
    }
  }

  return NS_OK;
}