private static void intersectPropertySets(final List<TypeInfo> reducedTypeInfos) {

    // substract property set from type info with more than one
    // occurrence from type infos with the given superclass
    for (final TypeInfo info : reducedTypeInfos) {

      if (info.getHierarchyLevel() > 1) {

        final Set<String> supertypeKeySet = info.getPropertySet().keySet();

        for (final TypeInfo subType : reducedTypeInfos) {

          final Set<String> subtypeKeySet = subType.getPropertySet().keySet();

          // only substract property set if it is a true subtype (and not the same :))
          //					if ( subType.getUsages() == 1 && subType.hasSuperclass(info.getPrimaryType())) {
          if (subType.getHierarchyLevel() < info.getHierarchyLevel()
              && subType.hasSuperclass(info.getPrimaryType())) {

            subtypeKeySet.removeAll(supertypeKeySet);
          }
        }
      }
    }
  }
  private static void reduceTypeInfos(
      final Map<String, List<TypeInfo>> typeInfoTypeMap, final List<TypeInfo> reducedTypeInfos) {

    for (final Map.Entry<String, List<TypeInfo>> entry : typeInfoTypeMap.entrySet()) {

      final List<TypeInfo> listOfTypeInfosWithSamePrimaryType = entry.getValue();
      TypeInfo firstTypeInfo = null;

      for (final TypeInfo typeInfo : listOfTypeInfosWithSamePrimaryType) {

        if (firstTypeInfo == null) {

          firstTypeInfo = typeInfo;

        } else {

          firstTypeInfo.combinePropertySets(typeInfo.getPropertySet());

          // "save" node references for later use
          firstTypeInfo.getNodeIds().addAll(typeInfo.getNodeIds());
        }
      }

      // firstTypeInfo now contains the intersection of all type infos of a given type
      reducedTypeInfos.add(firstTypeInfo);

      // set hierarchy level
      firstTypeInfo.setHierarchyLevel(listOfTypeInfosWithSamePrimaryType.size());
    }
  }