code: protected void throwInvalidState(final String methodName, final State... validStates) {
          if (state == State.INITIAL || state == State.SCOPE_DOCUMENT || state == State.DONE) {
              if (!methodName.startsWith("end") && !methodName.equals("writeName")) { // NOPMD
                  //NOPMD collapsing these if statements will not aid readability
                  String typeName = methodName.substring(5);
                  if (typeName.startsWith("start")) {
                      typeName = typeName.substring(5);
                  }
                  String article = "A";
                  if (Arrays.asList('A', 'E', 'I', 'O', 'U').contains(typeName.charAt(0))) {
                      article = "An";
                  }
                  throw new BsonInvalidOperationException(format("%s %s value cannot be written to the root level of a BSON document.",
                                                                 article, typeName));
              }
          }
  
          String validStatesString = StringUtils.join(" or ", Arrays.asList(validStates));
          throw new BsonInvalidOperationException(format("%s can only be called when State is %s, not when State is %s",
                                                         methodName, validStatesString, state));
      }
docs: Throws a {@link BsonInvalidOperationException} when the method called is not valid for the current state.
  
  @param methodName  The name of the method.
  @param validStates The valid states.
  @throws BsonInvalidOperationException when the method called is not valid for the current state.