/** {@inheritDoc} */
  public PathQuery generatePathQuery(
      ObjectStore os, InterMineBag bag, String series, String category) {

    Model model = os.getModel();
    PathQuery q = new PathQuery(model);

    Path geneSymbol = PathQuery.makePath(model, q, "Gene.symbol");
    Path genePrimary = PathQuery.makePath(model, q, "Gene.primaryIdentifier");
    Path haemAtlasSampleName =
        PathQuery.makePath(model, q, "Gene.probeSets.haemAtlasResults.sampleName");
    Path haemAtlasGroup = PathQuery.makePath(model, q, "Gene.probeSets.haemAtlasResults.group");
    Path haemAtlasAverage =
        PathQuery.makePath(model, q, "Gene.probeSets.haemAtlasResults.averageIntensity");
    Path haemAtlasSample = PathQuery.makePath(model, q, "Gene.probeSets.haemAtlasResults.sample");
    Path haemAtlasP =
        PathQuery.makePath(model, q, "Gene.probeSets.haemAtlasResults.detectionProbabilities");
    Path haemAtlasIlluId = PathQuery.makePath(model, q, "Gene.probeSets.illuId");

    List<Path> view = new ArrayList<Path>();

    view.add(geneSymbol);
    view.add(genePrimary);
    view.add(haemAtlasSampleName);
    view.add(haemAtlasGroup);
    view.add(haemAtlasAverage);
    view.add(haemAtlasSample);
    view.add(haemAtlasP);
    view.add(haemAtlasIlluId);

    q.setViewPaths(view);

    String bagType = bag.getType();
    ConstraintOp constraintOp = ConstraintOp.IN;
    String constraintValue = bag.getName();

    String label = null, id = null, code = q.getUnusedConstraintCode();
    Constraint c = new Constraint(constraintOp, constraintValue, false, label, code, id, null);
    q.addNode(bagType).getConstraints().add(c);

    constraintOp = ConstraintOp.EQUALS;
    code = q.getUnusedConstraintCode();
    PathNode categoryNode = q.addNode("Gene.probeSets.haemAtlasResults.sampleName");
    Constraint categoryConstraint =
        new Constraint(constraintOp, series, false, label, code, id, null);
    categoryNode.getConstraints().add(categoryConstraint);

    constraintOp = ConstraintOp.LESS_THAN;
    code = q.getUnusedConstraintCode();
    PathNode seriesNode = q.addNode("Gene.probeSets.haemAtlasResults.detectionProbabilities");
    Constraint seriesConstraint = new Constraint(constraintOp, 0.01, false, label, code, id, null);
    seriesNode.getConstraints().add(seriesConstraint);

    q.setConstraintLogic("A and B and C");
    q.syncLogicExpression("and");

    List<OrderBy> sortOrder = new ArrayList<OrderBy>();

    sortOrder.add(new OrderBy(geneSymbol, "asc"));
    sortOrder.add(new OrderBy(genePrimary));

    q.setSortOrder(sortOrder);

    return q;
  }
  /**
   * Query all edges of fly regulatory network.
   *
   * @param model the Model
   * @param executor to run the query
   * @return interactionEdgeSet
   */
  private static void queryFlyRegulatoryEdges(Model model, PathQueryExecutor executor) {

    interactionEdgeSetFly = new LinkedHashSet<CytoscapeNetworkEdgeData>();

    // TODO fly doesn't use IM Object id
    PathQuery query = new PathQuery(model);
    query.addViews(
        "Regulation.type", // interaction type, e.g. TF-TF
        "Regulation.source.primaryIdentifier",
        "Regulation.source.symbol",
        "Regulation.target.primaryIdentifier",
        "Regulation.target.symbol");

    query.addConstraint(Constraints.eq("Regulation.source.primaryIdentifier", "FBgn*"), "A");
    query.addConstraint(Constraints.eq("Regulation.target.primaryIdentifier", "FBgn*"), "B");

    query.setConstraintLogic("A and B");

    ExportResultsIterator result;
    try {
      result = executor.execute(query);
    } catch (ObjectStoreException e) {
      throw new RuntimeException("Error retrieving results.", e);
    }

    while (result.hasNext()) {
      List<ResultElement> row = result.next();

      String interactionType = (String) row.get(0).getField();
      String sourceNodePId = (String) row.get(1).getField();
      String sourceNodeSymbol = (String) row.get(2).getField();
      String targetNodePId = (String) row.get(3).getField();
      String targetNodeSymbol = (String) row.get(4).getField();

      CytoscapeNetworkEdgeData aEdge = new CytoscapeNetworkEdgeData();

      // Handle bidirectional edges
      if (interactionEdgeSetFly.isEmpty()) {
        aEdge.setSourceId(sourceNodePId);

        if (sourceNodeSymbol == null || sourceNodeSymbol.length() < 1) {
          aEdge.setSourceLabel(sourceNodePId);
        } else {
          aEdge.setSourceLabel(sourceNodeSymbol);
        }

        aEdge.setTargetId(targetNodePId);

        if (targetNodeSymbol == null || targetNodeSymbol.length() < 1) {
          aEdge.setTargetLabel(targetNodePId);
        } else {
          aEdge.setTargetLabel(targetNodeSymbol);
        }

        aEdge.setInteractionType(interactionType);
        aEdge.setDirection("one");

        interactionEdgeSetFly.add(aEdge);
      } else {
        aEdge.setSourceId(sourceNodePId);

        if (sourceNodeSymbol == null || sourceNodeSymbol.length() < 1) {
          aEdge.setSourceLabel(sourceNodePId);
        } else {
          aEdge.setSourceLabel(sourceNodeSymbol);
        }

        aEdge.setTargetId(targetNodePId);

        if (targetNodeSymbol == null || targetNodeSymbol.length() < 1) {
          aEdge.setTargetLabel(targetNodePId);
        } else {
          aEdge.setTargetLabel(targetNodeSymbol);
        }

        // miRNA-TF and TF-miRNA are the same interaction type
        if ("TF-miRNA".equals(interactionType) || "miRNA-TF".equals(interactionType)) {
          String uniType = "miRNA-TF";
          aEdge.setInteractionType(uniType);
        } else {
          aEdge.setInteractionType(interactionType);
        }

        String interactingString = aEdge.generateInteractionString();
        String interactingStringRev = aEdge.generateReverseInteractionString();

        // Get a list of interactionString from interactionSet
        LinkedHashSet<String> intcStrSet = new LinkedHashSet<String>();
        for (CytoscapeNetworkEdgeData edgedata : interactionEdgeSetFly) {
          intcStrSet.add(edgedata.generateInteractionString());
        }
        // A none dulipcated edge
        if (!(intcStrSet.contains(interactingString)
            || intcStrSet.contains(interactingStringRev))) {
          aEdge.setDirection("one");
          interactionEdgeSetFly.add(aEdge);
        } else { // duplicated edge
          // Pull out the CytoscapeNetworkEdgeData which contains the current
          // interactionString
          for (CytoscapeNetworkEdgeData edgedata : interactionEdgeSetFly) {
            if (edgedata.generateInteractionString().equals(interactingString)
                || edgedata.generateInteractionString().equals(interactingStringRev)) {
              edgedata.setDirection("both");
              aEdge.setInteractionType(interactionType);
            }
          }
        }
      }
    }
  }