/**
  * Called by makePathQueryForCollection
  *
  * @param webConfig the webConfig
  * @param model the object model
  * @param object the InterMineObject
  * @param field the name of the field for the collection in the InterMineObject
  * @param sr the list of classes and subclasses
  * @return a PathQuery
  */
 private static PathQuery makePathQueryForCollectionForClass(
     WebConfig webConfig, Model model, InterMineObject object, String field, List<Class<?>> sr) {
   Class<?> commonClass = CollectionUtil.findCommonSuperclass(sr);
   String typeOfCollection = TypeUtil.unqualifiedName(DynamicUtil.getSimpleClassName(commonClass));
   String startClass = TypeUtil.unqualifiedName(DynamicUtil.getSimpleClassName(object.getClass()));
   String collectionPath = startClass + "." + field;
   PathQuery pathQuery =
       getQueryWithDefaultView(typeOfCollection, model, webConfig, collectionPath);
   pathQuery.addConstraint(Constraints.eq(startClass + ".id", object.getId().toString()));
   return pathQuery;
 }
  private void doMatches(Map<String, Object> ret, BagQueryResult bqr) {

    for (Entry<Integer, List> pair : bqr.getMatches().entrySet()) {
      Map<String, Object> resultItem;
      InterMineObject imo;
      try {
        imo = im.getObjectStore().getObjectById(pair.getKey());
      } catch (ObjectStoreException e) {
        throw new IllegalStateException("Could not retrieve object reported as match", e);
      }
      String idKey = String.valueOf(imo.getId());
      if (ret.containsKey(idKey)) {
        resultItem = (Map<String, Object>) ret.get(idKey);
      } else {
        resultItem = new HashMap<String, Object>();
        resultItem.put("identifiers", new HashMap<String, Object>());
      }
      if (!resultItem.containsKey("summary")) {
        resultItem.put("summary", getObjectDetails(imo));
      }
      Map<String, Object> identifiers = (Map<String, Object>) resultItem.get("identifiers");
      for (Object o : pair.getValue()) {
        String ident = (String) o;
        if (!identifiers.containsKey(ident)) {
          identifiers.put(ident, new HashSet<String>());
        }
        Set<String> categories = (Set<String>) identifiers.get(ident);
        categories.add("MATCH");
      }
      String className = DynamicUtil.getSimpleClassName(imo.getClass());
      resultItem.put("type", className.replaceAll("^.*\\.", ""));
      ret.put(idKey, resultItem);
    }
  }
  /**
   * Create a PathQuery to get results for a collection of items from an InterMineObject
   *
   * @param webConfig the WebConfig
   * @param os the production ObjectStore
   * @param object the InterMineObject
   * @param referencedClassName the collection type
   * @param field the name of the field for the collection in the InterMineObject
   * @return a PathQuery
   */
  public static PathQuery makePathQueryForCollection(
      WebConfig webConfig,
      ObjectStore os,
      InterMineObject object,
      String referencedClassName,
      String field) {

    String className = TypeUtil.unqualifiedName(DynamicUtil.getSimpleClassName(object.getClass()));
    Path path;
    try {
      path = new Path(os.getModel(), className + "." + field);
    } catch (PathException e) {
      throw new IllegalArgumentException(
          "Could not build path for \"" + className + "." + field + "\".");
    }
    List<Class<?>> types = new ArrayList<Class<?>>();
    if (path.endIsCollection()) {
      CollectionDescriptor end = (CollectionDescriptor) path.getEndFieldDescriptor();
      // Only look for types if the refClass exactly matches the path type.
      if (end.getReferencedClassName().equals(referencedClassName)) {
        types = queryForTypesInCollection(object, field, os);
      }
      if (types.isEmpty()) {
        // the collection was empty, but still generate a query with the collection type
        types.add(os.getModel().getClassDescriptorByName(referencedClassName).getType());
      }
    } else if (path.endIsReference()) {
      types.add(path.getLastClassDescriptor().getType());
    }
    return makePathQueryForCollectionForClass(webConfig, os.getModel(), object, field, types);
  }
  private void doDuplicates(final Map<String, Object> ret, BagQueryResult bqr, String key) {
    Map<String, Map<String, List>> issues = bqr.getIssues().get(key);
    if (issues == null) {
      return;
    }
    for (Map<String, List> issueSet : issues.values()) {
      for (Entry<String, List> identToObjects : issueSet.entrySet()) {
        String ident = identToObjects.getKey();
        for (Object o : identToObjects.getValue()) {
          InterMineObject imo;
          Map<String, Object> resultItem;
          if (o instanceof Integer) {
            try {
              imo = im.getObjectStore().getObjectById((Integer) o);
            } catch (ObjectStoreException e) {
              throw new IllegalStateException("Could not retrieve object reported as match", e);
            }
          } else if (o instanceof ConvertedObjectPair) {
            imo = ((ConvertedObjectPair) o).getNewObject();
          } else {
            imo = (InterMineObject) o;
          }
          String idKey = String.valueOf(imo.getId());
          if (ret.containsKey(idKey)) {
            resultItem = (Map<String, Object>) ret.get(idKey);
          } else {
            resultItem = new HashMap<String, Object>();
            resultItem.put("identifiers", new HashMap<String, Object>());
          }
          if (!resultItem.containsKey("summary")) {
            resultItem.put("summary", getObjectDetails(imo));
          }
          Map<String, Object> identifiers = (Map<String, Object>) resultItem.get("identifiers");

          if (!identifiers.containsKey(ident)) {
            identifiers.put(ident, new HashSet<String>());
          }
          Set<String> categories = (Set<String>) identifiers.get(ident);
          categories.add(key);
          String className = DynamicUtil.getSimpleClassName(imo.getClass());
          resultItem.put("type", className.replaceAll("^.*\\.", ""));
          ret.put(idKey, resultItem);
        }
      }
    }
  }
 private Map<String, Object> getObjectDetails(InterMineObject imo) {
   WebConfig webConfig = InterMineContext.getWebConfig();
   Model m = im.getModel();
   Map<String, Object> objectDetails = new HashMap<String, Object>();
   String className = DynamicUtil.getSimpleClassName(imo.getClass());
   ClassDescriptor cd = m.getClassDescriptorByName(className);
   for (FieldConfig fc : FieldConfigHelper.getClassFieldConfigs(webConfig, cd)) {
     try {
       Path p = new Path(m, cd.getUnqualifiedName() + "." + fc.getFieldExpr());
       if (p.endIsAttribute() && fc.getShowInSummary()) {
         objectDetails.put(
             p.getNoConstraintsString().replaceAll("^[^.]*\\.", ""), PathUtil.resolvePath(p, imo));
       }
     } catch (PathException e) {
       LOG.error(e);
     }
   }
   return objectDetails;
 }
  /**
   * Search for the classes in a collection for a given InterMineObject, for example find all of the
   * sub-classes of Employee in the Department.employees collection of a given Department. If there
   * are no subclasses or the collection is empty a list with the type of the collection is
   * returned.
   *
   * @param object an InterMineObject to inspect
   * @param field the name if the collection to check
   * @param os the ObjectStore in which to execute the query
   * @return a list of classes in the collection
   */
  public static List<Class<?>> queryForTypesInCollection(
      InterMineObject object, String field, ObjectStore os) {
    List<Class<?>> typesInCollection = new ArrayList<Class<?>>();

    // if there are no subclasses there can only be one type in the collection
    Model model = os.getModel();
    ClassDescriptor startCld =
        model.getClassDescriptorByName(DynamicUtil.getSimpleClassName(object));
    CollectionDescriptor col = startCld.getCollectionDescriptorByName(field, true);
    ClassDescriptor colCld = col.getReferencedClassDescriptor();

    if (model.getAllSubs(colCld).isEmpty()) {
      // there aren't any subclasses, so no need to do a query
      typesInCollection.add(colCld.getType());
    } else {
      // there may be multiple subclasses in the collection, need to run a query
      Query query = new Query();
      QueryClass qc = new QueryClass(colCld.getType());
      query.addFrom(qc);
      query.addToSelect(new QueryField(qc, "class"));
      query.setDistinct(true);
      query.setConstraint(
          new ContainsConstraint(
              new QueryCollectionReference(object, field), ConstraintOp.CONTAINS, qc));
      for (Object o : os.executeSingleton(query)) {
        typesInCollection.add((Class<?>) o);
      }

      // Collection was empty but add collection type to be consistent with collection types
      // without subclasses.
      if (typesInCollection.isEmpty()) {
        typesInCollection.add(colCld.getType());
      }
    }
    return typesInCollection;
  }