/*
   * See http://www.w3.org/TR/rdf-sparql-query paragraph 11.4.4
   *
   * "(STR) Returns the lexical form of a literal; returns the codepoint representation of an IRI."
   *
   * @see http://www.w3.org/TR/rdf-sparql-query
   */
  private void convertStr(E_Str expr) {
    logger.debug("convertStr " + expr.toString());

    expr.getArg().visit(this);

    Expression arg = expression.pop();

    if (arg instanceof AttributeExprEx) {
      // make a new AttributeExprEx with changed NodeMaker, which returns plain literal
      // TODO this seems to work, but needs more testing.
      AttributeExprEx attribute = (AttributeExprEx) arg;
      TypedNodeMaker nodeMaker = (TypedNodeMaker) attribute.getNodeMaker();
      TypedNodeMaker newNodeMaker =
          new TypedNodeMaker(
              TypedNodeMaker.PLAIN_LITERAL, nodeMaker.valueMaker(), nodeMaker.isUnique());
      logger.debug("changing nodemaker " + nodeMaker + " to " + newNodeMaker);
      expression.push(
          new AttributeExprEx((Attribute) attribute.attributes().iterator().next(), newNodeMaker));
    } else if (arg instanceof ConstantEx) {
      ConstantEx constant = (ConstantEx) arg;
      Node node = constant.getNode();
      String lexicalForm = node.getLiteral().getLexicalForm();
      node = Node.createLiteral(lexicalForm);
      ConstantEx constantEx = new ConstantEx(NodeValue.makeNode(node).asString(), node);
      logger.debug("pushing " + constantEx);
      expression.push(constantEx);
    } else {
      conversionFailed(expr);
    }
  }
  /**
   * Delivers the corresponding sql-expression for a sparql-var
   *
   * @param exprVar - a sparql-expr-var
   * @return List<Expression> - the equivalent sql-expressions
   */
  private List<Expression> toExpression(ExprVar exprVar) {
    ArrayList<Expression> result = new ArrayList<Expression>();

    if (this.nodeRelation != null && exprVar != null) {
      // get the nodemaker for the expr-var
      NodeMaker nodeMaker = nodeRelation.nodeMaker(exprVar.asVar());
      if (nodeMaker instanceof TypedNodeMaker) {
        TypedNodeMaker typedNodeMaker = (TypedNodeMaker) nodeMaker;
        Iterator<ProjectionSpec> it = typedNodeMaker.projectionSpecs().iterator();
        if (!it.hasNext()) {
          logger.debug("no projection spec for " + exprVar + ", assuming constant");
          Node node = typedNodeMaker.makeNode(null);
          result.add(new ConstantEx(NodeValue.makeNode(node).asString(), node));
        }
        while (it.hasNext()) {
          ProjectionSpec projectionSpec = it.next();

          if (projectionSpec == null) return Collections.emptyList();

          if (projectionSpec instanceof Attribute) {
            result.add(new AttributeExprEx((Attribute) projectionSpec, nodeMaker));
          } else {
            // projectionSpec is a ExpressionProjectionSpec
            ExpressionProjectionSpec expressionProjectionSpec =
                (ExpressionProjectionSpec) projectionSpec;
            Expression expression = expressionProjectionSpec.toExpression();
            if (expression instanceof SQLExpression) result.add(((SQLExpression) expression));
            else return Collections.emptyList();
          }
        }
      } else if (nodeMaker instanceof FixedNodeMaker) {
        FixedNodeMaker fixedNodeMaker = (FixedNodeMaker) nodeMaker;
        Node node = fixedNodeMaker.makeNode(null);
        result.add(new ConstantEx(NodeValue.makeNode(node).asString(), node));
      }
    }

    return result;
  }
  static NodeMaker cast(NodeMaker nodeMaker, RDFDatatype datatype) {
    if (nodeMaker instanceof TypedNodeMaker)
      return new TypedNodeMaker(
          TypedNodeMaker.typedLiteral(datatype),
          ((TypedNodeMaker) nodeMaker).valueMaker(),
          nodeMaker.isUnique());

    if (nodeMaker instanceof FixedNodeMaker) {
      Node node = nodeMaker.makeNode(null);

      return new FixedNodeMaker(XSD.cast(node, datatype), nodeMaker.isUnique());
    }

    throw new RuntimeException("unknown nodeMaker type");
  }