protected KmlType createKmlType(KmlRoute route, int startIndex, int endIndex) {
    ObjectFactory objectFactory = new ObjectFactory();
    KmlType kmlType = objectFactory.createKmlType();
    DocumentType documentType = objectFactory.createDocumentType();
    kmlType.setAbstractFeatureGroup(objectFactory.createDocument(documentType));
    documentType.setName(createDocumentName(route));
    documentType.setDescription(asDescription(route.getDescription()));
    documentType.setOpen(TRUE);

    if (hasCharacteristics(singletonList(route), Route))
      documentType
          .getAbstractStyleSelectorGroup()
          .add(
              objectFactory.createStyle(
                  createLineStyle(ROUTE_LINE_STYLE, getLineWidth(), getRouteLineColor())));
    if (hasCharacteristics(singletonList(route), Track)) {
      documentType
          .getAbstractStyleSelectorGroup()
          .add(
              objectFactory.createStyle(
                  createLineStyle(TRACK_LINE_STYLE, getLineWidth(), getTrackLineColor())));
      if (isWriteSpeed())
        for (StyleType style : createSpeedTrackColors(getSpeedLineWidth()))
          documentType.getAbstractStyleSelectorGroup().add(objectFactory.createStyle(style));
    }

    FolderType folderType = createWayPoints(route, startIndex, endIndex);
    documentType.getAbstractFeatureGroup().add(objectFactory.createFolder(folderType));

    PlacemarkType placemarkTrack = createTrack(route, startIndex, endIndex);
    documentType.getAbstractFeatureGroup().add(objectFactory.createPlacemark(placemarkTrack));

    if (hasCharacteristics(singletonList(route), Track)) {
      FolderType speed = createSpeed(route, startIndex, endIndex);
      if (speed != null)
        documentType.getAbstractFeatureGroup().add(objectFactory.createFolder(speed));
    }
    if (!route.getCharacteristics().equals(Waypoints) && isWriteMarks()) {
      FolderType marks = createMarks(route, startIndex, endIndex);
      documentType.getAbstractFeatureGroup().add(objectFactory.createFolder(marks));
    }
    return kmlType;
  }
  protected void extractTracks(KmlType kmlType, ParserContext<KmlRoute> context)
      throws IOException {
    AbstractFeatureType feature = kmlType.getAbstractFeatureGroup().getValue();
    if (feature instanceof AbstractContainerType) {
      AbstractContainerType containerType = (AbstractContainerType) feature;
      List<JAXBElement<? extends AbstractFeatureType>> features = null;
      if (containerType instanceof FolderType)
        features = ((FolderType) containerType).getAbstractFeatureGroup();
      else if (containerType instanceof DocumentType)
        features = ((DocumentType) containerType).getAbstractFeatureGroup();
      extractTracks(
          trim(containerType.getName()), trim(containerType.getDescription()), features, context);
    }

    if (feature instanceof PlacemarkType) {
      PlacemarkType placemarkType = (PlacemarkType) feature;
      String placemarkName =
          asDescription(trim(placemarkType.getName()), trim(placemarkType.getDescription()));

      List<KmlPosition> positions =
          extractPositionsFromGeometry(placemarkType.getAbstractGeometryGroup());
      for (KmlPosition position : positions) {
        enrichPosition(
            position,
            extractTime(placemarkType.getAbstractTimePrimitiveGroup()),
            placemarkName,
            placemarkType.getDescription(),
            context.getStartDate());
      }
      context.appendRoute(new KmlRoute(this, Waypoints, placemarkName, null, positions));
    }

    if (feature instanceof TourType) {
      TourType tourType = (TourType) feature;
      String tourName = asDescription(trim(tourType.getName()), trim(tourType.getDescription()));

      List<KmlPosition> positions =
          extractPositionsFromTour(tourType.getPlaylist().getAbstractTourPrimitiveGroup());
      for (KmlPosition position : positions) {
        enrichPosition(
            position,
            extractTime(tourType.getAbstractTimePrimitiveGroup()),
            tourName,
            tourType.getDescription(),
            context.getStartDate());
      }
      context.appendRoute(new KmlRoute(this, Track, tourName, null, positions));
    }
  }
  private KmlType createKmlType(List<KmlRoute> routes) {
    ObjectFactory objectFactory = new ObjectFactory();
    KmlType kmlType = objectFactory.createKmlType();
    DocumentType documentType = objectFactory.createDocumentType();
    kmlType.setAbstractFeatureGroup(objectFactory.createDocument(documentType));
    /* might make sense for Waypoint lists with one position lists in the file
    if(routes.size() == 1) {
        KmlRoute route = routes.get(0);
        documentType.setName(createDocumentName(route));
        documentType.setDescription(asDescription(route.getDescription()));
    }
    */
    documentType.setOpen(TRUE);

    if (hasCharacteristics(routes, Route))
      documentType
          .getAbstractStyleSelectorGroup()
          .add(
              objectFactory.createStyle(
                  createLineStyle(ROUTE_LINE_STYLE, getLineWidth(), getRouteLineColor())));
    if (hasCharacteristics(routes, Track)) {
      documentType
          .getAbstractStyleSelectorGroup()
          .add(
              objectFactory.createStyle(
                  createLineStyle(TRACK_LINE_STYLE, getLineWidth(), getTrackLineColor())));
      if (isWriteSpeed())
        for (StyleType style : createSpeedTrackColors(getSpeedLineWidth()))
          documentType.getAbstractStyleSelectorGroup().add(objectFactory.createStyle(style));
    }

    for (KmlRoute route : routes) {
      switch (route.getCharacteristics()) {
        case Waypoints:
          FolderType wayPoints = createWayPoints(route, 0, route.getPositionCount());
          documentType.getAbstractFeatureGroup().add(objectFactory.createFolder(wayPoints));
          break;
        case Route:
          FolderType routeFolder = objectFactory.createFolderType();
          routeFolder.setName(createPlacemarkName(ROUTE, route));
          documentType.getAbstractFeatureGroup().add(objectFactory.createFolder(routeFolder));

          PlacemarkType routePlacemarks = createRoute(route);
          routeFolder.getAbstractFeatureGroup().add(objectFactory.createPlacemark(routePlacemarks));
          if (isWriteMarks())
            routeFolder
                .getAbstractFeatureGroup()
                .add(objectFactory.createFolder(createMarks(route, 0, route.getPositionCount())));
          break;
        case Track:
          FolderType trackFolder = objectFactory.createFolderType();
          trackFolder.setName(createPlacemarkName(TRACK, route));
          documentType.getAbstractFeatureGroup().add(objectFactory.createFolder(trackFolder));

          PlacemarkType track = createTrack(route, 0, route.getPositionCount());
          trackFolder.getAbstractFeatureGroup().add(objectFactory.createPlacemark(track));
          if (isWriteSpeed()) {
            FolderType speed = createSpeed(route, 0, route.getPositionCount());
            if (speed != null)
              trackFolder.getAbstractFeatureGroup().add(objectFactory.createFolder(speed));
          }
          if (isWriteMarks())
            trackFolder
                .getAbstractFeatureGroup()
                .add(objectFactory.createFolder(createMarks(route, 0, route.getPositionCount())));
          break;
        default:
          throw new IllegalArgumentException(
              "Unknown RouteCharacteristics " + route.getCharacteristics());
      }
    }
    return kmlType;
  }
 protected void process(KmlType kmlType, ParserContext<KmlRoute> context) throws IOException {
   if (kmlType == null || kmlType.getAbstractFeatureGroup() == null) return;
   extractTracks(kmlType, context);
 }