protected List<SelectChoice> createCustomSelectChoices(String completeTextValue) {
    // copied from org.javarosa.xform.util.XFormAnswerDataParser.getSelections()
    List<String> textValues =
        DateUtils.split(completeTextValue, XFormAnswerDataSerializer.DELIMITER, true);

    int index = 0;
    List<SelectChoice> customSelectChoices = new ArrayList<SelectChoice>();
    for (String textValue : textValues) {
      SelectChoice selectChoice = new SelectChoice(textValue, textValue, false);
      selectChoice.setIndex(index++);
      customSelectChoices.add(selectChoice);
    }

    return customSelectChoices;
  }
  @Override
  public IAnswerData resolveAnswer(String textVal, TreeElement treeElement, FormDef formDef) {
    QuestionDef questionDef =
        XFormParser.ghettoGetQuestionDef(treeElement.getDataType(), formDef, treeElement.getRef());
    if (questionDef != null
        && (questionDef.getControlType() == Constants.CONTROL_SELECT_ONE
            || questionDef.getControlType() == Constants.CONTROL_SELECT_MULTI)) {
      boolean containsSearchExpression = false;

      XPathFuncExpr xPathExpression = null;
      try {
        xPathExpression =
            ExternalDataUtil.getSearchXPathExpression(questionDef.getAppearanceAttr());
      } catch (Exception e) {
        Log.e(ExternalDataUtil.LOGGER_NAME, e.getMessage(), e);
        // there is a search expression, but has syntax errors
        containsSearchExpression = true;
      }

      if (xPathExpression != null || containsSearchExpression) {
        // that means that we have dynamic selects

        // read the static choices from the options sheet
        List<SelectChoice> staticChoices = questionDef.getChoices();
        for (int index = 0; index < staticChoices.size(); index++) {
          SelectChoice selectChoice = staticChoices.get(index);
          String selectChoiceValue = selectChoice.getValue();
          if (ExternalDataUtil.isAnInteger(selectChoiceValue)) {

            Selection selection = selectChoice.selection();

            switch (questionDef.getControlType()) {
              case Constants.CONTROL_SELECT_ONE:
                {
                  if (selectChoiceValue.equals(textVal)) {
                    // This means that the user selected a static selection.
                    //
                    // Although (for select1 fields) the default implementation will catch this and
                    // return the right thing
                    // (if we call super.resolveAnswer(textVal, treeElement, formDef))
                    // we just need to make sure, so we will override that.
                    if (questionDef.getControlType() == Constants.CONTROL_SELECT_ONE) {
                      // we don't need another, just return the static choice.
                      return new SelectOneData(selection);
                    }
                  }
                }
              case Constants.CONTROL_SELECT_MULTI:
                {
                  // we should search in a potential comma-separated string of values for a match
                  // copied from org.javarosa.xform.util.XFormAnswerDataParser.getSelections()
                  List<String> textValues =
                      DateUtils.split(textVal, XFormAnswerDataSerializer.DELIMITER, true);
                  if (textValues.contains(textVal)) {
                    // this means that the user has selected AT LEAST the static choice.
                    if (selectChoiceValue.equals(textVal)) {
                      // this means that the user selected ONLY the static answer, so just return
                      // that
                      List<Selection> customSelections = new ArrayList<Selection>();
                      customSelections.add(selection);
                      return new SelectMultiData(customSelections);
                    } else {
                      // we will ignore it for now since we will return that selection together with
                      // the dynamic ones.
                    }
                  }
                  break;
                }
              default:
                {
                  // There is a bug if we get here, so let's throw an Exception
                  throw createBugRuntimeException(treeElement, textVal);
                }
            }

          } else {
            switch (questionDef.getControlType()) {
              case Constants.CONTROL_SELECT_ONE:
                {
                  // the default implementation will search for the "textVal" (saved answer) inside
                  // the static choices.
                  // Since we know that there isn't such, we just wrap the textVal in a virtual
                  // choice in order to
                  // create a SelectOneData object to be used as the IAnswer to the TreeElement.
                  // (the caller of this function is searching for such an answer to populate the
                  // in-memory model.)
                  SelectChoice customSelectChoice = new SelectChoice(textVal, textVal, false);
                  customSelectChoice.setIndex(index);
                  return new SelectOneData(customSelectChoice.selection());
                }
              case Constants.CONTROL_SELECT_MULTI:
                {
                  // we should create multiple selections and add them to the pile
                  List<SelectChoice> customSelectChoices = createCustomSelectChoices(textVal);
                  List<Selection> customSelections = new ArrayList<Selection>();
                  for (SelectChoice customSelectChoice : customSelectChoices) {
                    customSelections.add(customSelectChoice.selection());
                  }
                  return new SelectMultiData(customSelections);
                }
              default:
                {
                  // There is a bug if we get here, so let's throw an Exception
                  throw createBugRuntimeException(treeElement, textVal);
                }
            }
          }
        }

        // if we get there then that means that we have a bug
        throw createBugRuntimeException(treeElement, textVal);
      }
    }
    // default behavior matches original behavior (for static selects, etc.)
    return super.resolveAnswer(textVal, treeElement, formDef);
  }
    public User parse() throws InvalidStructureException, IOException, XmlPullParserException {
        this.checkNode("registration");
        
        //parse (with verification) the next tag
        this.nextTag("username");
        String username = parser.nextText();
        
        this.nextTag("password");
        String passwordHash = parser.nextText();
        
        this.nextTag("uuid");
        String uuid = parser.nextText();
        
        this.nextTag("date");
        String dateModified = parser.nextText();
        Date modified = DateUtils.parseDateTime(dateModified);

        User u;
        try {
            u = retrieve(uuid);
        } catch (SessionUnavailableException e) {
            // User db's closed so escape since saving isn't possible.
            throw new UserStorageClosedException(e.getMessage());
        }
        
        if(u == null) {
            u = new User(username, passwordHash, uuid);
            u.setWrappedKey(wrappedKey);
        } else {
            if(passwordHash != null && !passwordHash.equals(u.getPassword())) {
                u.setPassword(passwordHash);
                u.setWrappedKey(wrappedKey);
            } 
        }
        
        //Now look for optional components
        while (this.nextTagInBlock("registration")) {
            String tag = parser.getName().toLowerCase();
            
            if(tag.equals("registering_phone_id")) {
                String phoneid = parser.nextText();
            } else if(tag.equals("token")) {
                String token = parser.nextText();
            } else if(tag.equals("user_data")) {
                while(this.nextTagInBlock("user_data")) {
                    this.checkNode("data");
                    
                    String key = this.parser.getAttributeValue(null, "key");
                    String value = this.parser.nextText();
                    
                    u.setProperty(key, value);
                }
                
                //This should be the last block in the registration stuff...
                break;
            } else {
                throw new InvalidStructureException("Unrecognized tag in user registraiton data: " + tag,parser);
            }
        }
        
        commit(u);
        return u;
    }