/** Parses the last word(s) from the name if it is a suffix. */
  private void parseSuffix(Name name, NameTokenizer tokens) {
    if (tokens.mStartPointer == tokens.mEndPointer) {
      return;
    }

    String lastToken = tokens.mTokens[tokens.mEndPointer - 1];

    // Take care of an explicit comma-separated suffix
    if (tokens.mEndPointer - tokens.mStartPointer > 2 && tokens.hasComma(tokens.mEndPointer - 2)) {
      if (tokens.hasDot(tokens.mEndPointer - 1)) {
        lastToken += '.';
      }
      name.suffix = lastToken;
      tokens.mEndPointer--;
      return;
    }

    if (lastToken.length() > mMaxSuffixLength) {
      return;
    }

    String normalized = lastToken.toUpperCase();
    if (mSuffixesSet.contains(normalized)) {
      name.suffix = lastToken;
      tokens.mEndPointer--;
      return;
    }

    if (tokens.hasDot(tokens.mEndPointer - 1)) {
      lastToken += '.';
    }
    normalized += ".";

    // Take care of suffixes like M.D. and D.D.S.
    int pos = tokens.mEndPointer - 1;
    while (normalized.length() <= mMaxSuffixLength) {

      if (mSuffixesSet.contains(normalized)) {
        name.suffix = lastToken;
        tokens.mEndPointer = pos;
        return;
      }

      if (pos == tokens.mStartPointer) {
        break;
      }

      pos--;
      if (tokens.hasDot(pos)) {
        lastToken = tokens.mTokens[pos] + "." + lastToken;
      } else {
        lastToken = tokens.mTokens[pos] + " " + lastToken;
      }

      normalized = tokens.mTokens[pos].toUpperCase() + "." + normalized;
    }
  }
  private void parseLastName(Name name, NameTokenizer tokens) {
    if (tokens.mStartPointer == tokens.mEndPointer) {
      return;
    }

    // If the first word is followed by a comma, assume that it's the family name
    if (tokens.hasComma(tokens.mStartPointer)) {
      name.familyName = tokens.mTokens[tokens.mStartPointer];
      tokens.mStartPointer++;
      return;
    }

    // If the second word is followed by a comma and the first word
    // is a last name prefix as in "de Sade" and "von Cliburn", treat
    // the first two words as the family name.
    if (tokens.mStartPointer + 1 < tokens.mEndPointer
        && tokens.hasComma(tokens.mStartPointer + 1)
        && isFamilyNamePrefix(tokens.mTokens[tokens.mStartPointer])) {
      String familyNamePrefix = tokens.mTokens[tokens.mStartPointer];
      if (tokens.hasDot(tokens.mStartPointer)) {
        familyNamePrefix += '.';
      }
      name.familyName = familyNamePrefix + " " + tokens.mTokens[tokens.mStartPointer + 1];
      tokens.mStartPointer += 2;
      return;
    }

    // Finally, assume that the last word is the last name
    name.familyName = tokens.mTokens[tokens.mEndPointer - 1];
    tokens.mEndPointer--;

    // Take care of last names like "de Sade" and "von Cliburn"
    if ((tokens.mEndPointer - tokens.mStartPointer) > 0) {
      String lastNamePrefix = tokens.mTokens[tokens.mEndPointer - 1];
      if (isFamilyNamePrefix(lastNamePrefix)) {
        if (tokens.hasDot(tokens.mEndPointer - 1)) {
          lastNamePrefix += '.';
        }
        name.familyName = lastNamePrefix + " " + name.familyName;
        tokens.mEndPointer--;
      }
    }
  }
  /** Parses the first word from the name if it is a prefix. */
  private void parsePrefix(Name name, NameTokenizer tokens) {
    if (tokens.mStartPointer == tokens.mEndPointer) {
      return;
    }

    String firstToken = tokens.mTokens[tokens.mStartPointer];
    if (mPrefixesSet.contains(firstToken.toUpperCase())) {
      if (tokens.hasDot(tokens.mStartPointer)) {
        firstToken += '.';
      }
      name.prefix = firstToken;
      tokens.mStartPointer++;
    }
  }
  private void parseMiddleName(Name name, NameTokenizer tokens) {
    if (tokens.mStartPointer == tokens.mEndPointer) {
      return;
    }

    if ((tokens.mEndPointer - tokens.mStartPointer) > 1) {
      if ((tokens.mEndPointer - tokens.mStartPointer) == 2
          || !mConjuctions.contains(tokens.mTokens[tokens.mEndPointer - 2].toUpperCase())) {
        name.middleName = tokens.mTokens[tokens.mEndPointer - 1];
        if (tokens.hasDot(tokens.mEndPointer - 1)) {
          name.middleName += '.';
        }
        tokens.mEndPointer--;
      }
    }
  }
  private void parseGivenNames(Name name, NameTokenizer tokens) {
    if (tokens.mStartPointer == tokens.mEndPointer) {
      return;
    }

    if ((tokens.mEndPointer - tokens.mStartPointer) == 1) {
      name.givenNames = tokens.mTokens[tokens.mStartPointer];
    } else {
      StringBuilder sb = new StringBuilder();
      for (int i = tokens.mStartPointer; i < tokens.mEndPointer; i++) {
        if (i != tokens.mStartPointer) {
          sb.append(' ');
        }
        sb.append(tokens.mTokens[i]);
        if (tokens.hasDot(i)) {
          sb.append('.');
        }
      }
      name.givenNames = sb.toString();
    }
  }