public static void collectOr(Expr expr, List<ExprList> list) {
    if (expr instanceof E_LogicalOr) {
      E_LogicalOr e = (E_LogicalOr) expr;

      collectOr(e.getArg1(), list);
      collectOr(e.getArg2(), list);
    } else if (expr instanceof E_LogicalAnd) {
      // List<Expr> ors = new ArrayList<Expr>();
      ExprList ors = new ExprList();
      collectAnd(expr, ors);

      list.add(ors);
    } else {
      list.add(new ExprList(expr));
    }
  }
  public static Expr handle(ExprFunction expr) {
    // System.out.println("Converting to DNF: [" + expr.getClass() + "]: " + expr);

    // not(and(A, B)) -> or(not A, not B)
    // not(or(A, B)) -> or(not A, not B)

    if (expr instanceof E_LogicalNot) {

      Expr tmp = ((E_LogicalNot) expr).getArg();
      if (!(tmp instanceof ExprFunction)) {
        return expr;
      }

      ExprFunction child = (ExprFunction) tmp;

      Expr newExpr = expr;

      if (child instanceof E_LogicalAnd) {
        newExpr =
            new E_LogicalOr(
                eval(new E_LogicalNot(child.getArg(1))), eval(new E_LogicalNot(child.getArg(2))));
      } else if (child instanceof E_LogicalOr) {
        newExpr =
            new E_LogicalAnd(
                eval(new E_LogicalNot(child.getArg(1))), eval(new E_LogicalNot(child.getArg(2))));
      } else if (child instanceof E_LogicalNot) { // Remove double negation
        newExpr = eval(child.getArg(1));
      } else {
        return expr;
      }

      return eval(newExpr);
    } else if (expr instanceof E_LogicalOr) {
      // return expr;
      // return eval(expr);
      return new E_LogicalOr(eval(expr.getArg(1)), eval(expr.getArg(2)));
    }

    /* Given:
     * (A or B) AND (C x D) becomes:
     * (A and (C x D)) OR (B and (c x D))
     *
     *
     * (A or B) AND (C or D)
     *
     * Goal:
     * (A and C) OR (A and D) OR (B and C) OR (B and D)
     *
     * This method transforms any "or" children of an AND node.
     * other nodes are left untouched:
     * (A or B) AND (c x D) becomes:
     * (A and (c x D)) OR (B and (c x D))
     */
    else if (expr instanceof E_LogicalAnd) {

      Expr aa = eval(expr.getArg(1));
      Expr bb = eval(expr.getArg(2));

      E_LogicalOr a = null;
      Expr b = null;

      if (aa instanceof E_LogicalOr) {
        a = (E_LogicalOr) aa;
        b = bb;
      } else if (bb instanceof E_LogicalOr) {
        a = (E_LogicalOr) bb;
        b = aa;
      }

      if (a == null) {
        return new E_LogicalAnd(aa, bb);
      } else {
        return new E_LogicalOr(
            eval(new E_LogicalAnd(a.getArg(1), b)), eval(new E_LogicalAnd(a.getArg(2), b)));
      }
    } else if (expr
        instanceof
        E_NotEquals) { // Normalize (a != b) to !(a = b) --- this makes it easier to find "a and !a"
                       // cases
      return new E_LogicalNot(eval(new E_Equals(expr.getArg(1), expr.getArg(2))));
    }

    return expr;

    /*
    if(expr instanceof E_LogicalNot) {

    	Expr tmp = ((E_LogicalNot)expr).getArg();
    	if (!(tmp instanceof ExprFunction))
    		return expr;

    	ExprFunction child = (ExprFunction) tmp;

    	String newFuncName = "";

    	if (child.getName().equals("and"))
    		newFuncName = "or";
    	else if (child.getName().equals("or"))
    		newFuncName = "and";
    	else if (child.getName().equals("not")) // Remove double negation
    		return eval(child.getChildren().get(0));
    	else
    		return expr;

    	FuncExpr result = new FuncExpr(newFuncName, child.getArity());
    	for (int i = 0; i < child.getArity(); ++i)
    		result.setChild(i,
    				new FuncExpr("not", child.getChildren().get(i)));

    	return eval(result);
    }

    if (expr.getName().equals("or")) {
    	List<IExpr> children = new ArrayList<IExpr>();
    	for (IExpr child : expr.getChildren())
    		children.add(eval(child));

    	if (!ExprUtil.containsDirectFuncChild(children, "or"))
    		return new FuncExpr("or", children);

    	// flatten or expressions
    	// or(or(A, B), C) becomes or(A, B, C)
    	List<IExpr> resultChildren = new ArrayList<IExpr>();
    	for (IExpr child : children)
    		if (ExprUtil.isFunc(child, "or"))
    			resultChildren.addAll(child.getChildren());
    		else
    			resultChildren.add(child);

    	return new FuncExpr("or", resultChildren);
    }

    if (expr.getName().equals("and")) {
    	List<IExpr> children = new ArrayList<IExpr>();
    	for (IExpr child : expr.getChildren())
    		children.add(eval(child));

    	// FIXME an and-node must have at least 2 children
    	// but maybe validation should be done somewhere else
    	// On the other hand it might be convenient to assume that
    	// whenever a binary expression only contains a single child
    	// it should be treated as if there was no operation at all.

    	// No 'or'-expression => nothing todo
    	if (!ExprUtil.containsDirectFuncChild(children, "or"))
    		return new FuncExpr("and", children);

    	// Collect all expressions
    	List<List<IExpr>> tables = new ArrayList<List<IExpr>>();
    	for (IExpr child : children) {

    		if (ExprUtil.isFunc(child, "or"))
    			tables.add(child.getChildren());
    		else
    			tables.add(Collections.singletonList(child));

    	}

    	Collection<List<IExpr>> joinedTable = new JoinIterable<IExpr>(
    			tables);
    	FuncExpr result = new FuncExpr("or", joinedTable.size());

    	// List<IExpr> resultChildren = new ArrayList<IExpr>();

    	int i = 0;
    	for (List<IExpr> row : joinedTable) {
    		IExpr newChild = new FuncExpr("and", row);

    		result.setChild(i, newChild);

    		++i;
    	}

    	return result;
    }

    // TODO Auto-generated method stub
    return expr;
    */

  }