/** Creates instances of the fields that the current field should be copied to */
 private static void parseCopyFields(
     ParseContext context, FieldMapper fieldMapper, List<String> copyToFields) throws IOException {
   if (!context.isWithinCopyTo() && copyToFields.isEmpty() == false) {
     context = context.createCopyToContext();
     for (String field : copyToFields) {
       // In case of a hierarchy of nested documents, we need to figure out
       // which document the field should go to
       ParseContext.Document targetDoc = null;
       for (ParseContext.Document doc = context.doc(); doc != null; doc = doc.getParent()) {
         if (field.startsWith(doc.getPrefix())) {
           targetDoc = doc;
           break;
         }
       }
       assert targetDoc != null;
       final ParseContext copyToContext;
       if (targetDoc == context.doc()) {
         copyToContext = context;
       } else {
         copyToContext = context.switchDoc(targetDoc);
       }
       parseCopy(field, copyToContext);
     }
   }
 }
  private Fields generateTermVectorsFromDoc(TermVectorRequest request, boolean doAllFields)
      throws IOException {
    // parse the document, at the moment we do update the mapping, just like percolate
    ParsedDocument parsedDocument =
        parseDocument(indexShard.shardId().getIndex(), request.type(), request.doc());

    // select the right fields and generate term vectors
    ParseContext.Document doc = parsedDocument.rootDoc();
    Collection<String> seenFields = new HashSet<>();
    Collection<GetField> getFields = new HashSet<>();
    for (IndexableField field : doc.getFields()) {
      FieldMapper fieldMapper = indexShard.mapperService().smartNameFieldMapper(field.name());
      if (seenFields.contains(field.name())) {
        continue;
      } else {
        seenFields.add(field.name());
      }
      if (!isValidField(fieldMapper)) {
        continue;
      }
      if (request.selectedFields() == null
          && !doAllFields
          && !fieldMapper.fieldType().storeTermVectors()) {
        continue;
      }
      if (request.selectedFields() != null && !request.selectedFields().contains(field.name())) {
        continue;
      }
      String[] values = doc.getValues(field.name());
      getFields.add(new GetField(field.name(), Arrays.asList((Object[]) values)));
    }
    return generateTermVectors(getFields, request.offsets(), request.perFieldAnalyzer());
  }
  static ObjectMapper parseObject(ParseContext context, ObjectMapper mapper, boolean atRoot)
      throws IOException {
    if (mapper.isEnabled() == false) {
      context.parser().skipChildren();
      return null;
    }
    XContentParser parser = context.parser();

    String currentFieldName = parser.currentName();
    if (atRoot
        && MapperService.isMetadataField(currentFieldName)
        && Version.indexCreated(context.indexSettings()).onOrAfter(Version.V_2_0_0_beta1)) {
      throw new MapperParsingException(
          "Field ["
              + currentFieldName
              + "] is a metadata field and cannot be added inside a document. Use the index API request parameters.");
    }
    XContentParser.Token token = parser.currentToken();
    if (token == XContentParser.Token.VALUE_NULL) {
      // the object is null ("obj1" : null), simply bail
      return null;
    }

    if (token.isValue()) {
      throw new MapperParsingException(
          "object mapping for ["
              + mapper.name()
              + "] tried to parse field ["
              + currentFieldName
              + "] as object, but found a concrete value");
    }

    ObjectMapper.Nested nested = mapper.nested();
    if (nested.isNested()) {
      context = context.createNestedContext(mapper.fullPath());
      ParseContext.Document nestedDoc = context.doc();
      ParseContext.Document parentDoc = nestedDoc.getParent();
      // pre add the uid field if possible (id was already provided)
      IndexableField uidField = parentDoc.getField(UidFieldMapper.NAME);
      if (uidField != null) {
        // we don't need to add it as a full uid field in nested docs, since we don't need
        // versioning
        // we also rely on this for UidField#loadVersion

        // this is a deeply nested field
        nestedDoc.add(
            new Field(
                UidFieldMapper.NAME,
                uidField.stringValue(),
                UidFieldMapper.Defaults.NESTED_FIELD_TYPE));
      }
      // the type of the nested doc starts with __, so we can identify that its a nested one in
      // filters
      // note, we don't prefix it with the type of the doc since it allows us to execute a nested
      // query
      // across types (for example, with similar nested objects)
      nestedDoc.add(
          new Field(
              TypeFieldMapper.NAME,
              mapper.nestedTypePathAsString(),
              TypeFieldMapper.Defaults.FIELD_TYPE));
    }

    // if we are at the end of the previous object, advance
    if (token == XContentParser.Token.END_OBJECT) {
      token = parser.nextToken();
    }
    if (token == XContentParser.Token.START_OBJECT) {
      // if we are just starting an OBJECT, advance, this is the object we are parsing, we need the
      // name first
      token = parser.nextToken();
    }

    ObjectMapper update = null;
    while (token != XContentParser.Token.END_OBJECT) {
      ObjectMapper newUpdate = null;
      if (token == XContentParser.Token.START_OBJECT) {
        newUpdate = parseObject(context, mapper, currentFieldName);
      } else if (token == XContentParser.Token.START_ARRAY) {
        newUpdate = parseArray(context, mapper, currentFieldName);
      } else if (token == XContentParser.Token.FIELD_NAME) {
        currentFieldName = parser.currentName();
      } else if (token == XContentParser.Token.VALUE_NULL) {
        parseNullValue(context, mapper, currentFieldName);
      } else if (token == null) {
        throw new MapperParsingException(
            "object mapping for ["
                + mapper.name()
                + "] tried to parse field ["
                + currentFieldName
                + "] as object, but got EOF, has a concrete value been provided to it?");
      } else if (token.isValue()) {
        newUpdate = parseValue(context, mapper, currentFieldName, token);
      }
      token = parser.nextToken();
      if (newUpdate != null) {
        if (update == null) {
          update = newUpdate;
        } else {
          update = update.merge(newUpdate, false);
        }
      }
    }
    // restore the enable path flag
    if (nested.isNested()) {
      ParseContext.Document nestedDoc = context.doc();
      ParseContext.Document parentDoc = nestedDoc.getParent();
      if (nested.isIncludeInParent()) {
        for (IndexableField field : nestedDoc.getFields()) {
          if (field.name().equals(UidFieldMapper.NAME)
              || field.name().equals(TypeFieldMapper.NAME)) {
            continue;
          } else {
            parentDoc.add(field);
          }
        }
      }
      if (nested.isIncludeInRoot()) {
        ParseContext.Document rootDoc = context.rootDoc();
        // don't add it twice, if its included in parent, and we are handling the master doc...
        if (!nested.isIncludeInParent() || parentDoc != rootDoc) {
          for (IndexableField field : nestedDoc.getFields()) {
            if (field.name().equals(UidFieldMapper.NAME)
                || field.name().equals(TypeFieldMapper.NAME)) {
              continue;
            } else {
              rootDoc.add(field);
            }
          }
        }
      }
    }
    return update;
  }