/** {@inheritDoc} */
  public Query getQuery(String action, List<String> keys) {

    // classes for FROM clause
    QueryClass qcDisease = new QueryClass(Disease.class);
    QueryClass qcGene = new QueryClass(Gene.class);
    QueryClass qcPub = new QueryClass(Publication.class);

    // fields for SELECT clause
    QueryField qfDiseaseName = new QueryField(qcDisease, "diseaseId");
    QueryField qfGeneId = new QueryField(qcGene, "id");
    QueryField qfGeneName = new QueryField(qcGene, "primaryIdentifier");
    QueryField qfId = new QueryField(qcPub, "pubMedId");
    QueryField qfPubTitle = new QueryField(qcPub, "title");

    // constraints
    ConstraintSet cs = new ConstraintSet(ConstraintOp.AND);

    // constrain genes to be in list
    if (!action.startsWith("population")) {
      cs.addConstraint(new BagConstraint(qfGeneId, ConstraintOp.IN, bag.getOsb()));
    }

    // disease.publication = publication
    QueryCollectionReference qcr = new QueryCollectionReference(qcGene, "diseases");
    cs.addConstraint(new ContainsConstraint(qcr, ConstraintOp.CONTAINS, qcDisease));

    QueryCollectionReference fin =
        new QueryCollectionReference(qcDisease, "associatedPublications");
    cs.addConstraint(new ContainsConstraint(fin, ConstraintOp.CONTAINS, qcPub));

    Query q = new Query();
    q.setDistinct(true);

    // from statement
    q.addFrom(qcGene);
    q.addFrom(qcDisease);
    q.addFrom(qcPub);

    // add constraints to query
    q.setConstraint(cs);

    // needed for the 'not analysed' number
    if ("analysed".equals(action)) {
      q.addToSelect(qfGeneId);
      // export query
      // needed for export button on widget
    } else if ("export".equals(action)) {

      q.addToSelect(qfId);
      q.addToSelect(qfGeneName);
      q.addToOrderBy(qfId);

      // total queries
      // needed for enrichment calculations
    } else if (action.endsWith("Total")) {
      q.addToSelect(qfGeneId);
      Query subQ = q;
      q = new Query();
      q.addFrom(subQ);
      q.addToSelect(new QueryFunction()); // disease count

      // needed for enrichment calculations
    } else {

      q.addToSelect(qfId);
      q.addToGroupBy(qfId);
      q.addToSelect(new QueryFunction()); // disease count
      if ("sample".equals(action)) {
        q.addToSelect(qfPubTitle);
        q.addToGroupBy(qfPubTitle);
      }
    }
    return q;
  }
  /** {@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;
  }