/*
   * ?x p ?y FILTER ((?x > 10) && (?z > 10))
   *
   */
  public boolean bound(Edge edge, Filter filter) {
    List<String> vars = new ArrayList<String>();
    if (edge.getNode(0).isVariable()) {
      vars.add(edge.getNode(0).toString());
    }
    if (edge.getNode(1).isVariable()) {
      vars.add(edge.getNode(1).toString());
    }

    List<String> varsFilter = filter.getVariables();
    for (String var : varsFilter) {
      if (!vars.contains(var)) {
        return false;
      }
    }
    return true;
  }
  public String processValueConstraints(Edge qEdge, Edge bEdge) {
    String where = "WHERE ";

    // Handling BINDINGS
    if (bEdge.getNode(0).isVariable() && bEdge.getNode(1).isVariable()) {
      return "";
    } else {
      String prop = qEdge.getLabel();
      // + "         \" SELECT Dataset.dataset_id, Dataset.name FROM Dataset %VALUE-CONSTRAINTS%
      // \")\n"
      if (prop.equals(
          "http://www.irisa.fr/visages/team/farooq/ontologies/iec-owl-lite.owl#is-referred-to-by")) {
        if (!bEdge.getNode(0).isVariable()) {
          where += "DATASET.SUBJECT_ID LIKE '" + extractSubjectId(bEdge.getNode(0)) + "' AND\n";
          //                    where += "Dataset.Subject_subject_id LIKE '" +
          // extractSubjectId(bEdge.getNode(0)) + "' AND\n";
        }
        if (!bEdge.getNode(1).isVariable()) {
          where += "DATASET.DATASET_ID LIKE '" + extractDatasetId(bEdge.getNode(1)) + "' AND\n";
          //                    where += "Dataset.dataset_id LIKE '" +
          // extractDatasetId(bEdge.getNode(1)) + "' AND\n";
        }
        // + "         \" SELECT Dataset.dataset_id, Dataset.name FROM Dataset %VALUE-CONSTRAINTS%
        // \")\n"
      } else if (prop.equals(
          "http://www.irisa.fr/visages/team/farooq/ontologies/linguistic-expression-owl-lite.owl#has-for-name")) {
        if (!bEdge.getNode(0).isVariable()) {
          where += "DATASET.DATASET_ID LIKE '" + extractDatasetId(bEdge.getNode(0)) + "' AND\n";
          //                    where += "Dataset.dataset_id LIKE '" +
          // extractDatasetId(bEdge.getNode(0)) + "' AND\n";
        }
        if (!bEdge.getNode(1).isVariable()) {
          where += "DATASET.NAME LIKE '" + bEdge.getNode(1).getValue().toString() + "' AND\n";
          //                    where += "Dataset.name LIKE '" +
          // bEdge.getNode(1).getValue().toString() + "' AND\n";
        }
        // + "        \" SELECT Subject.subject_id, Subject.subject_common_identifier FROM Subject
        // %VALUE-CONSTRAINTS% \")\n"
      } else if (prop.equals(
          "http://www.irisa.fr/visages/team/farooq/ontologies/examination-subject-owl-lite.owl#has-for-subject-identifier")) {
        if (!bEdge.getNode(0).isVariable()) {
          where += "SUBJECT.SUBJECT_ID LIKE '" + extractSubjectId(bEdge.getNode(0)) + "' AND\n";
          //                    where += "Subject.subject_id LIKE '" +
          // extractSubjectId(bEdge.getNode(0)) + "' AND\n";
        }
        if (!bEdge.getNode(1).isVariable()) {
          where += "SUBJECT.NAME LIKE '" + bEdge.getNode(1).getValue().toString() + "' AND\n";
          //                    where += "Subject.subject_common_identifier LIKE '" +
          // bEdge.getNode(1).getValue().toString() + "' AND\n";
        }
      } else if (prop.equals(
          "http://www.irisa.fr/visages/team/farooq/ontologies/study-owl-lite.owl#involves-as-patient")) {
        if (!bEdge.getNode(0).isVariable()) {
          where +=
              "REL_SUBJECT_STUDY.STUDY_ID LIKE '" + extractStudyId(bEdge.getNode(0)) + "' AND\n";
          //                    where += "Subject.subject_id LIKE '" +
          // extractSubjectId(bEdge.getNode(0)) + "' AND\n";
        }
        if (!bEdge.getNode(1).isVariable()) {
          where +=
              "REL_SUBJECT_STUDY.SUBJECT_ID LIKE '"
                  + extractSubjectId(bEdge.getNode(1))
                  + "' AND\n";
          //                    where += "Subject.subject_common_identifier LIKE '" +
          // bEdge.getNode(1).getValue().toString() + "' AND\n";
        }

      } else {
        logger.warn("Unsupporting bind join for " + bEdge);
      }
    }

    // Handling FILTERS

    // post-processing the SQL WHERE clause
    if (where.equals("WHERE ")) {
      return "";
    } else if (where.endsWith("AND\n")) {
      where = where.substring(0, where.lastIndexOf("AND\n"));
      //            logger.info("generated where clause \n" + where);
      return where;
    }
    logger.info("generated where clause \n" + where);
    return where;
  }
  public String getSparqlQuery(Edge edge, Environment env) {

    // prefix handling
    String sparqlPrefixes = "";
    if (env.getQuery().getAST() instanceof ASTQuery) {
      ASTQuery ast = (ASTQuery) env.getQuery().getAST();
      NSManager namespaceMgr = ast.getNSM();
      for (String p : namespaceMgr.getPrefixes()) {
        sparqlPrefixes += "PREFIX " + p + ": " + "<" + namespaceMgr.getNamespace(p) + ">\n";
      }
    }

    // filter handling
    ArrayList<String> filters = new ArrayList<String>();
    for (Exp exp : env.getQuery().getBody()) {
      if (exp.isFilter()) {
        Filter kgFilter = exp.getFilter();
        if (bound(edge, kgFilter)) {
          filters.add(((Term) kgFilter).toSparql());
        }
      }
    }

    // binding handling
    Node subject = env.getNode(edge.getNode(0));
    Node object = env.getNode(edge.getNode(1));
    Node predicate = null;

    if (edge.getEdgeVariable() != null) {
      predicate = env.getNode(edge.getEdgeVariable());
    }

    //
    if (subject == null) {
      subject = edge.getNode(0);
    }
    if (object == null) {
      object = edge.getNode(1);
    }
    if (predicate == null) {
      predicate = edge.getEdgeNode();
    }

    EdgeImpl bEdge = new EdgeImpl();
    bEdge.setEdgeNode(predicate);
    bEdge.setNode(0, subject);
    bEdge.setNode(1, object);

    //        logger.info("Bind join ? " + edge.toString() + " -> (" + subject + ", " + predicate +
    // ", " + object + ")");

    String property = edge.getLabel();
    String sql = rdfSqlMappings.get(property);

    if (sql != null) {
      sql = sql.replaceAll("%SUBJECT%", edge.getNode(0).toString());
      sql = sql.replaceAll("%OBJECT%", edge.getNode(1).toString());
    } else {
      return null;
    }

    String valueConstraints = processValueConstraints(edge, bEdge);
    sql = sql.replaceAll("%VALUE-CONSTRAINTS%", valueConstraints);

    String sparql = sparqlPrefixes;
    sparql +=
        "construct  { "
            + edge.getNode(0).toString()
            + " <"
            + property
            + "> "
            + edge.getNode(1).toString()
            + " } \n where { \n"
            + sql;

    if (filters.size() > 0) {
      sparql += "\t  FILTER (\n";
      int i = 0;
      for (String filter : filters) {
        if (i == (filters.size() - 1)) {
          sparql += "\t\t " + filter + "\n";
        } else {
          sparql += "\t\t " + filter + "&&\n";
        }
        i++;
      }
      sparql += "\t  )\n";
    }
    sparql += " }";

    return sparql;
  }