@Override
  public Object getBackCopy() {

    final XFormsSwitchControl cloned;

    // We want the new one to point to the children of the cloned nodes, not the children

    // Get initial index as we copy "back" to an initial state
    final XFormsSwitchControlLocal initialLocal = (XFormsSwitchControlLocal) getInitialLocal();

    // Clone this and children
    cloned = (XFormsSwitchControl) super.getBackCopy();

    // Update clone's selected case control to point to one of the cloned children
    final XFormsSwitchControlLocal clonedLocal =
        (XFormsSwitchControlLocal) cloned.getInitialLocal();

    // NOTE: we don't call getLocalForUpdate() because we know that XFormsSwitchControlLocal is safe
    // to write
    // to (super.getBackCopy() ensures that we have a new copy)

    clonedLocal.selectedCaseControlId = initialLocal.selectedCaseControlId;

    return cloned;
  }
  /**
   * Set the currently selected case.
   *
   * @param caseControlToSelect case control to select
   */
  public void setSelectedCase(XFormsCaseControl caseControlToSelect) {

    if (caseControlToSelect.parent() != this)
      throw new OXFException("xf:case is not child of current xf:switch.");

    final XFormsSwitchControlLocal localForUpdate = (XFormsSwitchControlLocal) getLocalForUpdate();

    final XFormsCaseControl previouslySelectedCaseControl = getSelectedCase();
    final boolean isChanging = previouslySelectedCaseControl.getId() != caseControlToSelect.getId();
    localForUpdate.selectedCaseControlId = caseControlToSelect.getId();

    if (isChanging) {
      // "This action adjusts all selected attributes on the affected cases to reflect the new
      // state, and then
      // performs the following:"

      // "1. Dispatching an xforms-deselect event to the currently selected case."
      Dispatch.dispatchEvent(new XFormsDeselectEvent(previouslySelectedCaseControl));

      if (isXForms11Switch()) {
        // Partial refresh on the case that is being deselected
        // Do this after xforms-deselect is dispatched
        containingDocument().getControls().doPartialRefresh(previouslySelectedCaseControl);

        // Partial refresh on the case that is being selected
        // Do this before xforms-select is dispatched
        containingDocument().getControls().doPartialRefresh(caseControlToSelect);
      }

      // "2. Dispatching an xforms-select event to the case to be selected."
      Dispatch.dispatchEvent(new XFormsSelectEvent(caseControlToSelect));
    }
  }
  @Override
  public void onCreate() {
    super.onCreate();

    // Ensure that the initial state is set, either from default value, or for state
    // deserialization.
    if (!restoredState) {
      final XFormsSwitchControlLocal local = (XFormsSwitchControlLocal) getLocalForUpdate();
      local.selectedCaseControlId = findDefaultSelectedCaseId();
    } else {
      // NOTE: state deserialized -> state previously serialized -> control was relevant ->
      // onCreate() called
      restoredState = false;
    }
  }
  public XFormsSwitchControl(
      XBLContainer container, XFormsControl parent, Element element, String effectiveId) {
    super(container, parent, element, effectiveId);

    // Initial local state
    setLocal(new XFormsSwitchControlLocal());

    // Restore state if needed
    final ControlState state = stateToRestoreJava();
    if (state != null) {
      final Map<String, String> keyValues = state.keyValuesJava();

      // NOTE: Don't use getLocalForUpdate() as we don't want to cause initialLocal != currentLocal
      final XFormsSwitchControlLocal local = (XFormsSwitchControlLocal) getCurrentLocal();
      local.selectedCaseControlId = keyValues.get("case-id");

      // Indicate that deserialized state must be used
      restoredState = true;
    }
  }