/**
   * Populates the conflict resolver with one tag collection
   *
   * @param tagsForAllPrimitives the tag collection
   * @param sourceStatistics histogram of tag source, number of primitives of each type in the
   *     source
   * @param targetStatistics histogram of paste targets, number of primitives of each type in the
   *     paste target
   */
  public void populate(
      TagCollection tagsForAllPrimitives,
      Map<OsmPrimitiveType, Integer> sourceStatistics,
      Map<OsmPrimitiveType, Integer> targetStatistics) {
    mode = Mode.RESOLVING_ONE_TAGCOLLECTION_ONLY;
    tagsForAllPrimitives =
        tagsForAllPrimitives == null ? new TagCollection() : tagsForAllPrimitives;
    sourceStatistics = sourceStatistics == null ? new HashMap<>() : sourceStatistics;
    targetStatistics = targetStatistics == null ? new HashMap<>() : targetStatistics;

    // init the resolver
    //
    allPrimitivesResolver
        .getModel()
        .populate(tagsForAllPrimitives, tagsForAllPrimitives.getKeysWithMultipleValues());
    allPrimitivesResolver.getModel().prepareDefaultTagDecisions();

    // prepare the dialog with one tag resolver
    pnlTagResolver.removeAll();
    pnlTagResolver.add(allPrimitivesResolver, BorderLayout.CENTER);

    statisticsModel.reset();
    StatisticsInfo info = new StatisticsInfo();
    info.numTags = tagsForAllPrimitives.getKeys().size();
    info.sourceInfo.putAll(sourceStatistics);
    info.targetInfo.putAll(targetStatistics);
    statisticsModel.append(info);
    validate();
  }
 /**
  * Combines tags from TIGER data
  *
  * @param tc the tag collection
  */
 public static void combineTigerTags(TagCollection tc) {
   for (String key : tc.getKeys()) {
     if (TigerUtils.isTigerTag(key)) {
       tc.setUniqueForKey(key, TigerUtils.combineTags(key, tc.getValues(key)));
     }
   }
 }
  /**
   * Normalizes the tags in the tag collection <code>tc</code> before resolving tag conflicts.
   *
   * <p>Removes irrelevant tags like "created_by".
   *
   * <p>For tags which are not present on at least one of the merged nodes, the empty value "" is
   * added to the list of values for this tag, but only if there are at least two primitives with
   * tags, and at least one tagged primitive do not have this tag.
   *
   * @param tc the tag collection
   * @param merged the collection of merged primitives
   */
  public static void normalizeTagCollectionBeforeEditing(
      TagCollection tc, Collection<? extends OsmPrimitive> merged) {
    // remove irrelevant tags
    //
    for (String key : OsmPrimitive.getDiscardableKeys()) {
      tc.removeByKey(key);
    }

    Collection<OsmPrimitive> taggedPrimitives = new ArrayList<>();
    for (OsmPrimitive p : merged) {
      if (p.isTagged()) {
        taggedPrimitives.add(p);
      }
    }
    if (taggedPrimitives.size() <= 1) return;

    for (String key : tc.getKeys()) {
      // make sure the empty value is in the tag set if a tag is not present
      // on all merged nodes
      //
      for (OsmPrimitive p : taggedPrimitives) {
        if (p.get(key) == null) {
          tc.add(new Tag(key, "")); // add a tag with key and empty value
        }
      }
    }
  }
 /**
  * Completes tags in the tag collection <code>tc</code> with the empty value for each tag. If the
  * empty value is present the tag conflict resolution dialog will offer an option for removing the
  * tag and not only options for selecting one of the current values of the tag.
  *
  * @param tc the tag collection
  */
 public static void completeTagCollectionForEditing(TagCollection tc) {
   for (String key : tc.getKeys()) {
     // make sure the empty value is in the tag set such that we can delete the tag
     // in the conflict dialog if necessary
     //
     tc.add(new Tag(key, ""));
   }
 }
 protected List<Command> buildTagChangeCommand(OsmPrimitive primitive, TagCollection tc) {
   List<Command> cmds = new LinkedList<>();
   for (String key : tc.getKeys()) {
     if (tc.hasUniqueEmptyValue(key)) {
       if (primitive.get(key) != null) {
         cmds.add(new ChangePropertyCommand(primitive, key, null));
       }
     } else {
       String value = tc.getJoinedValues(key);
       if (!value.equals(primitive.get(key))) {
         cmds.add(new ChangePropertyCommand(primitive, key, value));
       }
     }
   }
   return cmds;
 }
  /**
   * Populate the tag conflict resolver with tags for each type of primitives
   *
   * @param tagsForNodes the tags belonging to nodes in the paste source
   * @param tagsForWays the tags belonging to way in the paste source
   * @param tagsForRelations the tags belonging to relations in the paste source
   * @param sourceStatistics histogram of tag source, number of primitives of each type in the
   *     source
   * @param targetStatistics histogram of paste targets, number of primitives of each type in the
   *     paste target
   */
  public void populate(
      TagCollection tagsForNodes,
      TagCollection tagsForWays,
      TagCollection tagsForRelations,
      Map<OsmPrimitiveType, Integer> sourceStatistics,
      Map<OsmPrimitiveType, Integer> targetStatistics) {
    tagsForNodes = (tagsForNodes == null) ? new TagCollection() : tagsForNodes;
    tagsForWays = (tagsForWays == null) ? new TagCollection() : tagsForWays;
    tagsForRelations = (tagsForRelations == null) ? new TagCollection() : tagsForRelations;
    if (tagsForNodes.isEmpty() && tagsForWays.isEmpty() && tagsForRelations.isEmpty()) {
      populate(null, null, null);
      return;
    }
    tpResolvers.removeAll();
    initResolver(OsmPrimitiveType.NODE, tagsForNodes, targetStatistics);
    initResolver(OsmPrimitiveType.WAY, tagsForWays, targetStatistics);
    initResolver(OsmPrimitiveType.RELATION, tagsForRelations, targetStatistics);

    pnlTagResolver.removeAll();
    pnlTagResolver.add(tpResolvers, BorderLayout.CENTER);
    mode = Mode.RESOLVING_TYPED_TAGCOLLECTIONS;
    validate();
    statisticsModel.reset();
    if (!tagsForNodes.isEmpty()) {
      StatisticsInfo info = new StatisticsInfo();
      info.numTags = tagsForNodes.getKeys().size();
      int numTargets =
          targetStatistics.get(OsmPrimitiveType.NODE) == null
              ? 0
              : targetStatistics.get(OsmPrimitiveType.NODE);
      if (numTargets > 0) {
        info.sourceInfo.put(OsmPrimitiveType.NODE, sourceStatistics.get(OsmPrimitiveType.NODE));
        info.targetInfo.put(OsmPrimitiveType.NODE, numTargets);
        statisticsModel.append(info);
      }
    }
    if (!tagsForWays.isEmpty()) {
      StatisticsInfo info = new StatisticsInfo();
      info.numTags = tagsForWays.getKeys().size();
      int numTargets =
          targetStatistics.get(OsmPrimitiveType.WAY) == null
              ? 0
              : targetStatistics.get(OsmPrimitiveType.WAY);
      if (numTargets > 0) {
        info.sourceInfo.put(OsmPrimitiveType.WAY, sourceStatistics.get(OsmPrimitiveType.WAY));
        info.targetInfo.put(OsmPrimitiveType.WAY, numTargets);
        statisticsModel.append(info);
      }
    }
    if (!tagsForRelations.isEmpty()) {
      StatisticsInfo info = new StatisticsInfo();
      info.numTags = tagsForRelations.getKeys().size();
      int numTargets =
          targetStatistics.get(OsmPrimitiveType.RELATION) == null
              ? 0
              : targetStatistics.get(OsmPrimitiveType.RELATION);
      if (numTargets > 0) {
        info.sourceInfo.put(
            OsmPrimitiveType.RELATION, sourceStatistics.get(OsmPrimitiveType.RELATION));
        info.targetInfo.put(OsmPrimitiveType.RELATION, numTargets);
        statisticsModel.append(info);
      }
    }

    for (int i = 0; i < getNumResolverTabs(); i++) {
      if (!getResolver(i).getModel().isResolvedCompletely()) {
        tpResolvers.setSelectedIndex(i);
        break;
      }
    }
  }