001/**
002 * Copyright (C) 2007 - 2016, Jens Lehmann
003 *
004 * This file is part of DL-Learner.
005 *
006 * DL-Learner is free software; you can redistribute it and/or modify
007 * it under the terms of the GNU General Public License as published by
008 * the Free Software Foundation; either version 3 of the License, or
009 * (at your option) any later version.
010 *
011 * DL-Learner is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
014 * GNU General Public License for more details.
015 *
016 * You should have received a copy of the GNU General Public License
017 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
018 */
019package org.dllearner.algorithms.qtl.datastructures.impl;
020
021import javax.xml.bind.DatatypeConverter;
022import java.io.PrintWriter;
023import java.util.*;
024import java.util.Map.Entry;
025import java.util.regex.Pattern;
026
027import com.google.common.collect.Sets;
028import org.apache.jena.datatypes.BaseDatatype;
029import org.apache.jena.datatypes.RDFDatatype;
030import org.apache.jena.datatypes.xsd.XSDDatatype;
031import org.apache.jena.graph.Node;
032import org.apache.jena.graph.NodeFactory;
033import org.apache.jena.graph.Triple;
034import org.apache.jena.query.Query;
035import org.apache.jena.query.QueryFactory;
036import org.apache.jena.query.Syntax;
037import org.apache.jena.rdf.model.Literal;
038import org.apache.jena.sparql.core.TriplePath;
039import org.apache.jena.sparql.syntax.ElementGroup;
040import org.apache.jena.sparql.syntax.ElementPathBlock;
041import org.apache.jena.sparql.syntax.ElementTriplesBlock;
042import org.apache.jena.sparql.syntax.ElementVisitorBase;
043import org.apache.jena.vocabulary.OWL;
044import org.apache.jena.vocabulary.RDF;
045import org.apache.jena.vocabulary.RDFS;
046import org.dllearner.algorithms.qtl.datastructures.NodeRenderer;
047import org.dllearner.algorithms.qtl.datastructures.QueryTree;
048import org.dllearner.algorithms.qtl.datastructures.rendering.Edge;
049import org.dllearner.algorithms.qtl.datastructures.rendering.Vertex;
050import org.dllearner.algorithms.qtl.filters.Filters;
051import org.dllearner.utilities.PrefixCCMap;
052import org.jgrapht.Graph;
053import org.json.JSONArray;
054import org.json.JSONException;
055import org.json.JSONObject;
056import org.semanticweb.owlapi.model.*;
057import org.semanticweb.owlapi.vocab.OWL2Datatype;
058import org.semanticweb.owlapi.vocab.OWLFacet;
059import uk.ac.manchester.cs.owl.owlapi.OWLDataFactoryImpl;
060
061/**
062 * 
063 * @author Lorenz Bühmann
064 *
065 */
066public class QueryTreeImpl<N> implements QueryTree<N>{
067        
068        public enum NodeType{
069                RESOURCE, LITERAL, BLANK, VARIABLE
070    }
071        
072        public enum LiteralNodeSubsumptionStrategy {
073                DATATYPE,
074                INTERVAL,
075                MIN,
076                MAX,
077                ENUMERATION,
078                OFF
079        }
080        
081        public enum LiteralNodeConversionStrategy{
082                /**
083                 * Literals in form of an enumeration, e.g. {3, 4, 10}
084                 */
085                DATA_ONE_OF, 
086                /**
087                 * Literals as an interval on the datatype, e.g. [>= 5 <=10]
088                 */
089                MIN_MAX, 
090                /**
091                 * Literals as datatype, e.g. xsd:integer
092                 */
093                DATATYPE,
094                
095                MIN,
096                
097                MAX,
098        }
099        
100        private N userObject;
101
102    private QueryTreeImpl<N> parent;
103
104    private List<QueryTreeImpl<N>> children;
105
106    private Map<QueryTree<N>, Object> child2EdgeMap;
107    private Map<String, List<QueryTree<N>>> edge2ChildrenMap;
108    
109    private NodeRenderer<N> toStringRenderer;
110    
111    private boolean tagged = false;
112    
113    private int cnt;
114    
115    private int id;
116    
117    private boolean isLiteralNode = false;
118    private boolean isResourceNode = false;
119    private boolean isBlankNode = false;
120    
121    private Set<Literal> literals = new HashSet<>();
122
123        private NodeType nodeType;
124    
125    public QueryTreeImpl(N userObject) {
126        this.userObject = userObject;
127        children = new ArrayList<>();
128        child2EdgeMap = new HashMap<>();
129        edge2ChildrenMap = new HashMap<>();
130        toStringRenderer = new NodeRenderer<N>() {
131            @Override
132            public String render(QueryTree<N> object) {
133                String label = object.toString() + "(" + object.getId() + ")";
134                if(object.isLiteralNode()){
135//                      if(object.getLiterals().size() == 1){
136//                              label += object.getLiterals().iterator().next();
137//                      } else if(object.getLiterals().size() > 1){
138//                              label += "Values: " + object.getLiterals();
139//                      }
140                        if(!object.getLiterals().isEmpty()){
141                                label += "Values: " + object.getLiterals();
142                        }
143                }
144//              label += object.isResourceNode() + "," + object.isLiteralNode();
145                return label;
146            }
147        };
148//        if(isVarNode() && !getUserObject().equals("?")){
149//              System.out.println(getUserObject());
150//              System.out.println("ERROR1");
151////                    System.exit(0);
152//      }
153    }
154    
155    public QueryTreeImpl(N userObject, NodeType nodeType) {
156        this(userObject, nodeType, 0);
157    }
158    
159    public QueryTreeImpl(N userObject, NodeType nodeType, int id) {
160        this.userObject = userObject;
161                this.nodeType = nodeType;
162        this.id = id;
163        children = new ArrayList<>();
164        child2EdgeMap = new HashMap<>();
165        edge2ChildrenMap = new HashMap<>();
166        toStringRenderer = new NodeRenderer<N>() {
167            @Override
168            public String render(QueryTree<N> object) {
169                String label = object.toString() + "(" + object.getId() + ")";
170                if(object.isLiteralNode()){
171//                      if(object.getLiterals().size() == 1){
172//                              label += object.getLiterals().iterator().next();
173//                      } else if(object.getLiterals().size() > 1){
174//                              label += "Values: " + object.getLiterals();
175//                      }
176                        if(!object.getLiterals().isEmpty()){
177                                label += "Values: " + object.getLiterals();
178                        }
179                }
180//              label += object.isResourceNode() + "," + object.isLiteralNode();
181                return  label;
182            }
183        };
184        if(nodeType == NodeType.RESOURCE){
185                isResourceNode = true;
186        } else if(nodeType == NodeType.LITERAL){
187                isLiteralNode = true;
188        }
189//        if(isVarNode() && !getUserObject().equals("?")){
190//              System.out.println(getUserObject());
191//              System.out.println("ERROR2");
192//              System.exit(0);
193//      }
194    }
195    
196    public QueryTreeImpl(QueryTree<N> tree){
197        this(tree.getUserObject(), tree.getNodeType());
198        
199//      this.userObject = tree.getUserObject();
200//        children = new ArrayList<QueryTreeImpl<N>>();
201//        child2EdgeMap = new HashMap<QueryTree<N>, Object>();
202//        edge2ChildrenMap = new HashMap<String, List<QueryTree<N>>>();
203//        toStringRenderer = new NodeRenderer<N>() {
204//            public String render(QueryTree<N> object) {
205//              String label = object.toString() + "(" + object.getId() + ")";
206//              if(object.isLiteralNode()){
207////                            if(object.getLiterals().size() == 1){
208////                                    label += object.getLiterals().iterator().next();
209////                            } else if(object.getLiterals().size() > 1){
210////                                    label += "Values: " + object.getLiterals();
211////                            }
212//                      if(!object.getLiterals().isEmpty()){
213//                              label += "Values: " + object.getLiterals();
214//                      }
215//              }
216////                    label += object.isResourceNode() + "," + object.isLiteralNode();
217//                return label;
218//            }
219//        };
220        
221        setId(tree.getId());
222        QueryTreeImpl<N> subTree;
223        for(QueryTree<N> child : tree.getChildren()){
224                subTree = new QueryTreeImpl<>(child);
225                subTree.setId(child.getId());
226                subTree.setIsLiteralNode(child.isLiteralNode());
227                subTree.setIsResourceNode(child.isResourceNode());
228                subTree.addLiterals(child.getLiterals());
229                addChild(subTree, tree.getEdge(child));
230        }
231        
232        setIsResourceNode(tree.isResourceNode());
233        setIsLiteralNode(tree.isLiteralNode());
234        addLiterals(tree.getLiterals());
235    }
236    
237    @Override
238    public boolean sameType(QueryTree<N> tree){
239        return (isResourceNode && tree.isResourceNode()) ||
240                (isVarNode() && tree.isVarNode()) ||
241                (isLiteralNode && tree.isLiteralNode());
242    }
243
244    @Override
245    public N getUserObject() {
246        return userObject;
247    }
248    
249    @Override
250    public void setUserObject(N userObject) {
251        this.userObject = userObject;
252    }
253    
254    @Override
255    public void setId(int id) {
256        this.id = id;
257    }
258    
259    @Override
260    public int getId() {
261        return id;
262    }
263    
264        @Override
265        public NodeType getNodeType() {
266                return nodeType;
267        }
268    
269    @Override
270    public boolean isEmpty(){
271        return this.children.isEmpty();
272    }
273    
274    @Override
275    public QueryTree<N> getNodeById(int nodeId){
276        QueryTree<N> node = null;
277        if(this.id == nodeId){
278                node = this;
279        } else {
280                for(QueryTree<N> child : children){
281                        node = child.getNodeById(nodeId);
282                        if(node != null){
283                                return node;
284                        }
285                }
286        }
287        return node;
288    }
289    
290    @Override
291    public boolean isLiteralNode() {
292        return isLiteralNode;
293    }
294    
295    @Override
296    public void setIsLiteralNode(boolean isLiteralNode) {
297        this.isLiteralNode = isLiteralNode;
298    }
299    
300    public void setIsBlankNode(boolean isBlankNode) {
301                this.isBlankNode = isBlankNode;
302        }
303    
304    public boolean isBlankNode() {
305                return isBlankNode;
306        }
307    
308    @Override
309    public boolean isResourceNode() {
310        return isResourceNode;
311    }
312    
313    @Override
314    public void setIsResourceNode(boolean isResourceNode) {
315        this.isResourceNode = isResourceNode;
316    }
317    
318    @Override
319    public boolean isVarNode() {
320        return !isLiteralNode && !isResourceNode;
321    }
322    
323    @Override
324    public void setVarNode(boolean isVarNode) {
325        isLiteralNode = false;
326        isResourceNode = false;
327    }
328
329    public void setParent(QueryTreeImpl<N> parent) {
330        if (this.parent != null) {
331            this.parent.children.remove(this);
332        }
333        this.parent = parent;
334        this.parent.children.add(this);
335    }
336    
337    /* (non-Javadoc)
338         * @see org.dllearner.algorithms.qtl.datastructures.QueryTree#setParent(org.dllearner.algorithms.qtl.datastructures.QueryTree)
339         */
340        @Override
341        public void setParent(QueryTree<N> parent) {
342                setParent((QueryTreeImpl<N>)parent);
343        }
344
345    @Override
346    public void addChild(QueryTreeImpl<N> child) {
347        children.add(child);
348        child.parent = this;
349    }
350    
351    public void addChild(QueryTree<N> child) {
352        children.add((QueryTreeImpl<N>) child);
353        child.setParent(this);
354    }
355    
356    /* (non-Javadoc)
357         * @see org.dllearner.algorithms.qtl.datastructures.QueryTree#addChild(org.dllearner.algorithms.qtl.datastructures.QueryTree, java.lang.Object)
358         */
359        @Override
360        public void addChild(QueryTree<N> child, Object edge) {
361                addChild((QueryTreeImpl<N>)child, edge);
362        }
363    
364    @Override
365    public void addChild(QueryTreeImpl<N> child, int position) {
366        children.add(position, child);
367        child.parent = this;
368    }
369
370    @Override
371    public void addChild(QueryTreeImpl<N> child, Object edge) {
372        addChild(child);
373        child2EdgeMap.put(child, edge);
374        
375        List<QueryTree<N>> children = edge2ChildrenMap.get(edge);
376        if(children == null){
377                children = new ArrayList<>();
378                edge2ChildrenMap.put((String)edge, children);
379        }
380        children.add(child);
381    }
382    
383    @Override
384    public void addChild(QueryTreeImpl<N> child, Object edge, int position) {
385        addChild(child, position);
386        child2EdgeMap.put(child, edge);
387        
388        List<QueryTree<N>> children = edge2ChildrenMap.get(edge);
389        if(children == null){
390                children = new ArrayList<>();
391                edge2ChildrenMap.put((String)edge, children);
392        }
393        children.add(child);
394        
395    }
396
397    @Override
398    public int removeChild(QueryTreeImpl<N> child) {
399        int pos = children.indexOf(child);
400        children.remove(child);
401        edge2ChildrenMap.get(child2EdgeMap.get(child)).remove(child);
402        child.parent = null;
403        return pos;
404    }
405    
406    public void removeChildren(Set<QueryTreeImpl<N>> children) {
407        for(QueryTreeImpl<N> child : children){
408                this.children.remove(child);
409            child.parent = null;
410        }
411    }
412    
413    /**
414     * Removes all children connected by the given edge.
415     */
416    @Override
417    public void removeChildren(Object edge) {
418        List<QueryTree<N>> children = edge2ChildrenMap.remove(edge);
419        if(children != null){
420                this.children.removeAll(children);
421        }
422//      List<QueryTree<N>> list = edge2ChildrenMap.get("http://dl-learner.org/carcinogenesis#hasAtom");
423//      List<QueryTree<N>> newList = new ArrayList<QueryTree<N>>();
424//      for (int i = 0; i < Math.min(list.size(), 11); i++) {
425//              QueryTreeImpl<N> keep = (QueryTreeImpl<N>) list.get(i);
426//              newList.add(keep);
427//              }
428//      list.clear();
429//      list.addAll(newList);
430//      this.children.clear();
431//      this.children = new ArrayList<QueryTreeImpl<N>>();
432//      this.children.addAll((Collection<? extends QueryTreeImpl<N>>) list);
433//      edge2ChildrenMap.clear();
434//      edge2ChildrenMap.put("http://dl-learner.org/carcinogenesis#hasAtom", list);
435    }
436
437    @Override
438    public Object getEdge(QueryTree<N> child) {
439        return child2EdgeMap.get(child);
440    }
441    
442    @Override
443    public Set<Object> getEdges(){
444        return new TreeSet<>(child2EdgeMap.values());
445    }
446
447    @Override
448    public void sortChildren(Comparator<QueryTree<N>> comparator) {
449        Collections.sort(children, comparator);
450    }
451
452    public void clearChildren() {
453        for (QueryTreeImpl<N> child : new ArrayList<>(children)) {
454            removeChild(child);
455        }
456    }
457
458    @Override
459    public QueryTree<N> getParent() {
460        return parent;
461    }
462
463    @Override
464    public List<QueryTree<N>> getChildren() {
465        return new ArrayList<>(children);
466    }
467    
468    @Override
469    public List<QueryTree<N>> getChildren(Object edge) {
470//      List<QueryTree<N>> children = new ArrayList<QueryTree<N>>();
471//      for(Entry<QueryTree<N>, Object> entry : child2EdgeMap.entrySet()){
472//              if(entry.getValue().equals(edge)){
473//                      children.add(entry.getKey());
474//              }
475//      }
476//        return children;
477        List<QueryTree<N>> children = edge2ChildrenMap.get(edge);
478        if(children == null){
479                children = new ArrayList<>();
480        }
481        return new ArrayList<>(children);
482    }
483    
484    @Override
485    public int getChildCount() {
486        return children.size();
487    }
488
489    @Override
490    public boolean isRoot() {
491        return parent == null;
492    }
493
494    @Override
495    public boolean isLeaf() {
496        return children.isEmpty();
497    }
498    
499    @Override
500    public boolean isSubsumedBy(QueryTree<N> tree) {
501//      System.out.println("++++++++++++++++++++++++++++");
502//      System.out.println(tree + "-" + this.userObject);
503//      System.out.println(tree.isResourceNode() + "," + tree.isLiteralNode() + "---" + this.isResourceNode + "," + this.isLiteralNode);
504//      if(tree.getParent() != null && getParent() != null)
505//              System.out.println(tree.getParent().getEdge(tree) + "#" + getParent().getEdge(this));
506//      System.out.println(tree.getUserObject().equals("?") || tree.getUserObject().equals(this.userObject));
507        if(!(tree.getUserObject().equals("?") || tree.getUserObject().equals(this.userObject))){
508                return false;
509        }
510        if(isResourceNode() && tree.isResourceNode() && this.userObject.equals(tree.getUserObject())){
511                return true;
512        }
513        Object edge;
514        for(QueryTree<N> child : tree.getChildren()){
515                boolean isSubsumed = false;
516                edge = tree.getEdge(child);
517                for(QueryTree<N> child2 : this.getChildren(edge)){
518                        if(child2.isSubsumedBy(child)){
519                                isSubsumed = true;
520                                break;
521                        }
522                }
523                if(!isSubsumed){
524//                      System.err.println(child.getParent() + "--" + child.getParent().getEdge(child) + "-->" + child);
525//                      System.err.println(child.getStringRepresentation(true));
526                                return false;
527                        }
528        }
529        return true;
530//      return isSubsumedBy(tree, LiteralNodeSubsumptionStrategy.OFF);
531    }
532    
533    @Override
534    public boolean isSubsumedBy(QueryTree<N> tree, LiteralNodeSubsumptionStrategy strategy) {
535//      System.out.println("++++++++++++++++++++++++++++");
536//      System.out.println(tree + "-" + this.userObject);
537//      System.out.println(tree.isResourceNode() + "," + tree.isLiteralNode() + "---" + this.isResourceNode + "," + this.isLiteralNode);
538//      if(tree.getParent() != null && getParent() != null)
539//              System.out.println(tree.getParent().getEdge(tree) + "#" + getParent().getEdge(this));
540//      System.out.println(tree.getUserObject().equals("?") || tree.getUserObject().equals(this.userObject));
541        
542        if(tree.isResourceNode() && this.isResourceNode){
543                if(!(tree.getUserObject().equals("?") || tree.getUserObject().equals(this.userObject))){
544                        return false;
545                }
546        } else if(tree.isLiteralNode() && this.isLiteralNode){
547                if(!tree.getUserObject().equals(this.userObject)){
548                        if(strategy == LiteralNodeSubsumptionStrategy.OFF){
549                                return tree.getUserObject().equals("?") || tree.getUserObject().equals(this.userObject);
550                        } else {
551                                // rdf:PlainLiteral
552                                if(tree.getDatatype() == null && this.getDatatype() == null) {
553                                        return true;
554                                }
555                                if(tree.getLiterals().isEmpty()) {
556                                        return true;
557                                }
558                                return subsumes(tree.getLiterals(), this.getLiterals(), strategy);
559                        }
560                }
561        } else if(!tree.isVarNode() && this.isVarNode()){
562                return false;
563        } else if(tree.isVarNode() && this.isLiteralNode()) {
564                return true;
565        } else if(tree.isResourceNode() && this.isLiteralNode || tree.isLiteralNode() && this.isResourceNode){//node type mismatch
566                return false;
567        }
568        Object edge;
569        for(QueryTree<N> child : tree.getChildren()){
570                boolean isSubsumed = false;
571                edge = tree.getEdge(child);
572                for(QueryTree<N> child2 : this.getChildren(edge)){
573                        if(child2.isSubsumedBy(child, strategy)){
574                                isSubsumed = true;
575                                break;
576                        }
577                }
578                if(!isSubsumed){
579//                      System.err.println("not covered: " + QueryTreeUtils.printPathToRoot(child, tree));
580                                return false;
581                        }
582        }
583        return true;
584    }
585    
586    private boolean subsumes(Set<Literal> subsumer, Set<Literal> subsumee, LiteralNodeSubsumptionStrategy strategy){
587        if(subsumer.isEmpty() || subsumee.isEmpty()){
588                return false;
589        }
590        if(strategy == LiteralNodeSubsumptionStrategy.DATATYPE){
591                //check if both datatypes are the same
592                        RDFDatatype subsumerDatatype = getDatatype(subsumer);
593                        RDFDatatype subsumeeDatatype = getDatatype(subsumee);
594                        
595//                      if(subsumerDatatype == null && subsumeeDatatype == null) {
596//                              return true;
597//                      }
598                        
599                        if(subsumerDatatype == null || subsumeeDatatype == null) {
600                                return false;
601                        }
602                        
603                        return subsumerDatatype.equals(subsumeeDatatype);
604                } else if(strategy == LiteralNodeSubsumptionStrategy.ENUMERATION){
605                        return subsumer.containsAll(subsumee);
606                } else { 
607                        //check if both datatypes are the same
608                        RDFDatatype subsumerDatatype = getDatatype(subsumer);
609                        RDFDatatype subsumeeDatatype = getDatatype(subsumee);
610                        
611                        if(subsumerDatatype == null || subsumeeDatatype == null) {
612                                return false;
613                        }
614                        
615                        if(!subsumerDatatype.equals(subsumeeDatatype)){
616                                return false;
617                        }
618                        
619                        //avoid boolean datatypes for interval check as there are only 2 possible values
620                        if(subsumerDatatype.equals(XSDDatatype.XSDboolean)){
621                                return true;
622                        }
623                        
624                        if(strategy == LiteralNodeSubsumptionStrategy.INTERVAL){
625                                //check if subsumee interval is contained in subsumer interval
626                                Literal subsumerMin = getMin(subsumer);
627                                Literal subsumerMax = getMax(subsumer);
628                                
629                                Literal subsumeeMin = getMin(subsumee);
630                                Literal subsumeeMax = getMax(subsumee);
631                                
632                                boolean leftMoreGeneral = isLessOrEqual(subsumerMin, subsumeeMin);
633                                boolean rightMoreGeneral = isGreaterOrEqual(subsumerMax, subsumeeMax);
634                                
635                                if(!(leftMoreGeneral && rightMoreGeneral)){
636        //                              System.out.println("[" + subsumeeMin + "," + subsumeeMax + "] not in interval " + "[" + subsumerMin + "," + subsumerMax + "]");
637                                        return false;
638                                }
639                        } else if(strategy == LiteralNodeSubsumptionStrategy.MIN){
640                        
641                                //check if subsumee min is greater than subsumer min
642                                Literal subsumerMin = getMin(subsumer);
643                                Literal subsumeeMin = getMin(subsumee);
644                                
645                                return isGreaterOrEqual(subsumeeMin, subsumerMin);
646                        } else if(strategy == LiteralNodeSubsumptionStrategy.MAX){
647                        
648                                //check if subsumee min is greater than subsumer min
649                                Literal subsumerMax = getMax(subsumer);
650                                Literal subsumeeMax = getMax(subsumee);
651                                
652                                return isGreaterOrEqual(subsumerMax, subsumeeMax);
653                        }
654                }
655        return true;
656    }
657    
658    /**
659     * Returns the datatype of the literals. Throws exception if there are multiple datatypes.
660     * @param literals
661     */
662    private RDFDatatype getDatatype(Set<Literal> literals){
663        RDFDatatype datatype = literals.iterator().next().getDatatype();
664        return datatype;
665    }
666    
667    /**
668     * Checks if all literals have the same datatype. 
669     * @param literals
670     * @return
671     */
672    private boolean sameDatatype(Set<Literal> literals){
673        Iterator<Literal> iterator = literals.iterator();
674        RDFDatatype datatype = iterator.next().getDatatype();
675        while(iterator.hasNext()){
676                if(!iterator.next().getDatatype().equals(datatype)){
677                        return false;
678                }
679        }
680        return true;
681    }
682    
683    @Override
684    public boolean isSubsumedBy(QueryTree<N> tree, boolean stopAfterError) {
685        if(!(tree.getUserObject().equals("?") || tree.getUserObject().equals(this.userObject))){
686                return false;
687        }
688        
689        Object edge;
690        for(QueryTree<N> child : tree.getChildren()){
691                boolean isSubsumed = false;
692                edge = tree.getEdge(child);
693                for(QueryTree<N> child2 : this.getChildren(edge)){
694                        if(child2.isSubsumedBy(child, true)){
695                                isSubsumed = true;
696                                break;
697                        }
698                }
699                if(!isSubsumed){
700                        child.tag();
701                                return false;
702                        }
703        }
704        return true;
705    }
706    
707    @Override
708    public void tag(){
709        tagged = true;
710    }
711    
712    @Override
713    public boolean isTagged(){
714        return tagged;
715    }
716
717    @Override
718    public QueryTree<N> getRoot() {
719        if (parent == null) {
720            return this;
721        }
722        return parent.getRoot();
723    }
724    
725    @Override
726    public List<QueryTree<N>> getLeafs(){
727        List<QueryTree<N>> leafs = new LinkedList<>();
728        if(isLeaf()){
729                leafs.add(this);
730        } else {
731                for(QueryTree<N> child : children){
732                        leafs.addAll(child.getLeafs());
733                }
734        }
735        return leafs;
736    }
737
738    @Override
739    public List<QueryTree<N>> getPathToRoot() {
740        List<QueryTree<N>> path = new ArrayList<>();
741        path.add(0, this);
742        QueryTree<N> par = parent;
743        while (par != null) {
744            path.add(0, par);
745            par = par.getParent();
746        }
747        return path;
748    }
749    
750   
751
752    @Override
753    public List<N> getUserObjectPathToRoot() {
754        List<N> path = new ArrayList<>();
755        path.add(0, this.getUserObject());
756        QueryTree<N> par = parent;
757        while (par != null) {
758            path.add(0, par.getUserObject());
759            par = par.getParent();
760        }
761        return path;
762    }
763    
764    @Override
765    public List<QueryTree<N>> getChildrenClosure() {
766        List<QueryTree<N>> children = new ArrayList<>();
767        getChildrenClosure(this, children);
768        return children;
769    }
770
771    private void getChildrenClosure(QueryTree<N> tree, List<QueryTree<N>> bin) {
772        bin.add(tree);
773        for (QueryTree<N> child : tree.getChildren()) {
774                getChildrenClosure(child, bin);
775        }
776    }
777
778    @Override
779    public Set<N> getUserObjectClosure() {
780        Set<N> objects = new HashSet<>();
781        getUserObjectClosure(this, objects);
782        return objects;
783    }
784    
785    @Override
786    public int getTriplePatternCount(){
787        return countTriplePattern(this);
788    }
789    
790    private int countTriplePattern(QueryTree<N> tree){
791        int cnt = 0;
792        Object object;
793        if(!tree.isLeaf()){
794                for(QueryTree<N> child : tree.getChildren()){
795                        object = child.getUserObject();
796                        boolean objectIsResource = !object.equals("?");
797                        cnt++;
798                        if(!objectIsResource){
799                                cnt+=countTriplePattern(child);
800                        }
801                }
802        }
803        return cnt;
804    }
805    
806    public QueryTree<N> getSPARQLQueryTree(){
807        return createSPARQLQueryTree(this);
808    }
809    
810    private QueryTree<N> createSPARQLQueryTree(QueryTree<N> tree){
811        QueryTree<N> copy = new QueryTreeImpl<>(tree.getUserObject());
812        if(tree.getUserObject().equals("?")){
813                for(QueryTree<N> child : tree.getChildren()){
814                        copy.addChild((QueryTreeImpl<N>) createSPARQLQueryTree(child), tree.getEdge(child));
815                }
816        }
817//      for(QueryTree<N> child : tree.getChildren()){
818//              if(child.getUserObject().equals("?")){
819//                      copy.addChild((QueryTreeImpl<N>) createSPARQLQueryTree(child), tree.getEdge(child));
820//              } else {
821//                      copy.addChild((QueryTreeImpl<N>) child, tree.getEdge(child));
822//              }
823//              
824//      }
825        
826        return copy;
827    }
828
829    private void getUserObjectClosure(QueryTree<N> tree, Set<N> bin) {
830        bin.add(tree.getUserObject());
831        for (QueryTree<N> child : tree.getChildren()) {
832            getUserObjectClosure(child, bin);
833        }
834    }
835    
836    @Override
837    public String getStringRepresentation(){
838        return getStringRepresentation(false);
839    }
840    
841    /**
842     * Prints the query tree and shows children of resources only if enabled.
843     * @param stopIfChildIsResourceNode whether to stop if child is resource
844     * @return the query tree string
845     */
846    @Override
847    public String getStringRepresentation(boolean stopIfChildIsResourceNode){
848        int depth = getPathToRoot().size();
849        StringBuilder sb = new StringBuilder();
850        if(isRoot()){
851                sb.append("TREE\n\n");
852        }
853        String ren = toStringRenderer.render(this);
854        ren = ren.replace("\n", "\n" + sb);
855        sb.append(ren);
856        sb.append("\n");
857        if(isRoot() || !isResourceNode || (isResourceNode && !stopIfChildIsResourceNode)){
858                for (QueryTree<N> child : getChildren()) {
859                for (int i = 0; i < depth; i++) {
860                    sb.append("\t");
861                }
862                Object edge = getEdge(child);
863                if (edge != null) {
864                        sb.append("  ");
865                        sb.append(edge);
866                        sb.append(" ---> ");
867                }
868                sb.append(child.getStringRepresentation(stopIfChildIsResourceNode));
869            }
870        }
871        return sb.toString();
872    }
873    
874    public String getStringRepresentation(int indent){
875        int depth = getPathToRoot().size();
876        StringBuilder sb = new StringBuilder();
877        for (int i = 0; i < depth + indent; i++) {
878            sb.append("\t");
879        }
880        String ren = toStringRenderer.render(this);
881        ren = ren.replace("\n", "\n" + sb);
882        sb.append(ren);
883        sb.append("\n");
884        for (QueryTree<N> child : getChildren()) {
885            Object edge = getEdge(child);
886            if (edge != null) {
887                sb.append("--- ");
888                sb.append(edge);
889                sb.append(" ---\n");
890            }
891            sb.append(((QueryTreeImpl<N>)child).getStringRepresentation(indent));
892        }
893        return sb.toString();
894    }
895    
896    @Override
897    public void dump() {
898        dump(new PrintWriter(System.out), 0);
899    }
900
901    @Override
902    public void dump(PrintWriter writer) {
903        dump(writer, 0);
904    }
905
906    @Override
907    public void dump(PrintWriter writer, int indent) {
908        int depth = getPathToRoot().size();
909        StringBuilder sb = new StringBuilder();
910        for (int i = 0; i < depth + indent; i++) {
911            sb.append("\t");
912        }
913        writer.print(sb.toString());
914        String ren = toStringRenderer.render(this);
915        ren = ren.replace("\n", "\n" + sb);
916        writer.println(ren);
917        for (QueryTree<N> child : getChildren()) {
918            Object edge = getEdge(child);
919            boolean meaningful = !edge.equals(RDF.type.getURI()) || meaningful(child);
920            if (meaningful) {
921                writer.print(sb.toString());
922                writer.print("--- ");
923                writer.print(edge);
924                writer.print(" ---\n");
925
926                // recursive call
927                                child.dump(writer, indent);
928            }
929        }
930        writer.flush();
931//      int depth = getPathToRoot().size();
932//        StringBuilder sb = new StringBuilder();
933//        for (int i = 0; i < depth + indent; i++) {
934//            sb.append("\t");
935//        }
936//        writer.print(sb.toString());
937//        String ren = toStringRenderer.render(this);
938//        ren = ren.replace("\n", "\n" + sb);
939//        writer.println(ren);
940//        for (QueryTree<N> child : getChildren()) {
941//            Object edge = getEdge(child);
942//            if (edge != null) {
943//                writer.print(sb.toString());
944//                writer.print("--- ");
945//                writer.print(edge);
946//                writer.print(" ---\n");
947//            }
948//            child.dump(writer, indent);
949//        }
950//        writer.flush();
951    }
952
953    private boolean meaningful(QueryTree<N> tree){
954        if(tree.isResourceNode() || tree.isLiteralNode()){
955                return true;
956        } else {
957                for (QueryTree<N> child : tree.getChildren()) {
958                        Object edge = tree.getEdge(child);
959                        if(!edge.equals(RDFS.subClassOf.getURI())){
960                                return true;
961                        } else if(child.isResourceNode()){
962                                return true;
963                        } else if(meaningful(child)){
964                                return true;
965                        }
966                }
967        }
968        return false;
969    }
970
971    @Override
972    public List<N> fillDepthFirst() {
973        List<N> results = new ArrayList<>();
974        fillDepthFirst(this, results);
975        return results;
976    }
977
978    private void fillDepthFirst(QueryTree<N> tree, List<N> bin) {
979        bin.add(tree.getUserObject());
980        for (QueryTree<N> child : tree.getChildren()) {
981            fillDepthFirst(child, bin);
982        }
983    }
984
985    public void replace(QueryTreeImpl<N> tree) {
986        parent.children.remove(this);
987        parent.children.add(tree);
988        parent = null;
989        tree.children.clear();
990        tree.children.addAll(children);
991        children.clear();
992    }
993    
994    public String toString() {
995        if (userObject != null) {
996            return userObject.toString();
997        } else {
998            return "";
999        }
1000    }
1001
1002    public int getSize() {
1003        return getUserObjectClosure().size();
1004    }
1005
1006    @Override
1007    public int getMaxDepth() {
1008        return getMaxDepth(this);
1009    }
1010
1011    private int getMaxDepth(QueryTree<N> tree) {
1012        int maxChildDepth = tree.getPathToRoot().size();
1013        for (QueryTree<N> child : tree.getChildren()) {
1014            int childDepth = getMaxDepth(child);
1015            if(childDepth > maxChildDepth) {
1016                maxChildDepth = childDepth;
1017            }
1018        }
1019        return maxChildDepth;
1020    }
1021    
1022    @Override
1023    public Object clone() throws CloneNotSupportedException {
1024        QueryTreeImpl<N> copy = new QueryTreeImpl<>(this.userObject, this.nodeType);
1025        copy.setIsResourceNode(isResourceNode);
1026        copy.setIsLiteralNode(isLiteralNode);
1027        for(QueryTreeImpl<N> child : children){
1028                copy.addChild((QueryTreeImpl<N>)child.clone(), getEdge(child));
1029        }
1030        
1031        return copy;
1032    }
1033    
1034//    @Override
1035//    public boolean equals(Object obj) {
1036//      if(obj == this){
1037//              return true;
1038//      }
1039//      if(!(obj instanceof QueryTreeImpl<?>)){
1040//              return false;
1041//      }
1042//      QueryTreeImpl<N> other = (QueryTreeImpl<N>)obj;
1043//      if(!this.userObject.equals(other.getUserObject())){
1044//              return false;
1045//      }
1046//      Object edge;
1047//      for(QueryTreeImpl<N> child : this.children){
1048//              boolean existsEqualChild = false;
1049//              edge = child2EdgeMap.get(child);
1050//              for(QueryTree<N> child2 : other.getChildren(edge)){
1051//                      if(child.equals(child2)){
1052//                              existsEqualChild = true;
1053//                              break;
1054//                      }
1055//              }
1056//              if(!existsEqualChild){
1057//                      return false;
1058//              }
1059//      }
1060//      return true;
1061//    }
1062    
1063    @Override
1064    public boolean isSameTreeAs(QueryTree<N> tree){
1065        if(!this.userObject.equals(tree.getUserObject())){
1066                return false;
1067        }
1068        Object edge;
1069        for(QueryTreeImpl<N> child : this.children){
1070                boolean existsEqualChild = false;
1071                edge = child2EdgeMap.get(child);
1072                for(QueryTree<N> child2 : tree.getChildren(edge)){
1073                        if(child.isSameTreeAs(child2)){
1074                                existsEqualChild = true;
1075                                break;
1076                        }
1077                }
1078                if(!existsEqualChild){
1079                        return false;
1080                }
1081        }
1082        return true;
1083    }
1084    
1085    @Override
1086    public Query toSPARQLQuery() {
1087        return QueryFactory.create(toSPARQLQueryString(), Syntax.syntaxARQ);
1088    }
1089    
1090    @Override
1091    public String toSPARQLQueryString() {
1092        if(children.isEmpty()){
1093                return "SELECT ?x0 WHERE {?x0 ?y ?z.}";
1094        }
1095        cnt = 0;
1096        StringBuilder sb = new StringBuilder();
1097        sb.append("SELECT DISTINCT ?x0 WHERE {\n");
1098        List<String> filters = new ArrayList<>();
1099        buildSPARQLQueryString(this, sb, true, false, filters);
1100        for(String filter : filters){
1101                sb.append(filter).append("\n");
1102        }
1103        sb.append("}");
1104        return sb.toString();
1105    }
1106    
1107    @Override
1108    public String toSPARQLQueryString(boolean filterMeaninglessProperties, boolean useNumericalFilters) {
1109        return toSPARQLQueryString(filterMeaninglessProperties, useNumericalFilters, Collections.<String, String>emptyMap());
1110    }
1111    
1112    @Override
1113    public String toSPARQLQueryString(boolean filterMeaninglessProperties, boolean useNumericalFilters, Map<String, String> prefixMap) {
1114        if(children.isEmpty()){
1115                return "SELECT ?x0 WHERE {?x0 ?y ?z.}";
1116        }
1117        cnt = 0;
1118        StringBuilder sb = new StringBuilder();
1119        List<String> filters = new ArrayList<>();
1120        sb.append("SELECT DISTINCT ?x0 WHERE {\n");
1121        buildSPARQLQueryString(this, sb, filterMeaninglessProperties, useNumericalFilters, filters);
1122        for(String filter : filters){
1123                sb.append(filter).append("\n");
1124        }
1125        sb.append("}");
1126        Query query = QueryFactory.create(sb.toString(), Syntax.syntaxSPARQL_11);
1127        
1128        //get the used resources in the query
1129        Set<String> usedResources = getUsedResources(query);
1130        
1131        //add a prefix for each used namespace
1132                for (Entry<String, String> entry : prefixMap.entrySet()) {
1133                        String prefix = entry.getKey();
1134                        String namespace = entry.getValue();
1135                        for (String res : usedResources) {
1136                                if(res.startsWith(namespace)){
1137                                        query.setPrefix(prefix, namespace);
1138                                        break;
1139                                }
1140                        }
1141                }
1142        return query.toString();
1143    }
1144    
1145        private Set<String> getUsedResources(Query query) {
1146                final Set<String> resources = Sets.newHashSet();
1147                query.getQueryPattern().visit(new ElementVisitorBase() {
1148                        @Override
1149                        public void visit(ElementGroup el) {
1150                                el.getElements().get(0).visit(this);
1151                        }
1152
1153                        @Override
1154                        public void visit(ElementPathBlock el) {
1155                                for (Iterator<TriplePath> it = el.patternElts(); it.hasNext();) {
1156                                        Triple t = it.next().asTriple();
1157                                        if (t.getSubject().isURI()) {
1158                                                resources.add(t.getSubject().getURI());
1159                                        }
1160                                        if (t.getPredicate().isURI()) {
1161                                                resources.add(t.getPredicate().getURI());
1162                                        }
1163                                        if (t.getObject().isURI()) {
1164                                                resources.add(t.getObject().getURI());
1165                                        }
1166                                }
1167                        }
1168
1169                        @Override
1170                        public void visit(ElementTriplesBlock el) {
1171                                for (Iterator<Triple> it = el.patternElts(); it.hasNext();) {
1172                                        Triple t = it.next();
1173                                        if (t.getSubject().isURI()) {
1174                                                resources.add(t.getSubject().getURI());
1175                                        }
1176                                        if (t.getPredicate().isURI()) {
1177                                                resources.add(t.getPredicate().getURI());
1178                                        }
1179                                        if (t.getObject().isURI()) {
1180                                                resources.add(t.getObject().getURI());
1181                                        }
1182                                }
1183                        }
1184                });
1185                return resources;
1186        }
1187    
1188    private void buildSPARQLQueryString(QueryTree<N> tree, StringBuilder sb, boolean filterMeaninglessProperties, boolean useNumericalFilters, List<String> filters){
1189        Object subject = null;
1190        if(tree.getUserObject().equals("?")){
1191                subject = "?x" + cnt++;
1192                if(useNumericalFilters){
1193                        if(tree.isLiteralNode() && !tree.getLiterals().isEmpty()){
1194                                filters.add(getFilter(subject.toString(), tree.getLiterals()));
1195                        }
1196                }
1197        } else {
1198                subject = "<" + tree.getUserObject() + ">";
1199        }
1200        Object predicate;
1201        Object object;
1202        if(!tree.isLeaf()){
1203                for(QueryTree<N> child : tree.getChildren()){
1204                        predicate = tree.getEdge(child);
1205                        if(filterMeaninglessProperties){
1206                                if(Filters.getAllFilterProperties().contains(predicate.toString())){
1207                                        continue;
1208                                }
1209                        }
1210                        object = child.getUserObject();
1211                        boolean objectIsResource = !object.equals("?");
1212                        if(!objectIsResource){
1213                                object = "?x" + cnt;
1214                        } else if(((String)object).startsWith("http://")){
1215                                object = "<" + object + ">";
1216                        }
1217                        if(child.isLiteralNode() && object.toString().contains("\n")) {
1218                                object = "\"\"" + object + "\"\"";
1219                        }
1220                        sb.append(subject).append(" <").append(predicate).append("> ").append(object).append(".\n");
1221                        if(!objectIsResource){
1222                                buildSPARQLQueryString(child, sb, filterMeaninglessProperties, useNumericalFilters, filters);
1223                        }
1224                }
1225        } 
1226    }
1227    
1228    private void buildSPARQLQueryStringPretty(QueryTree<N> tree, StringBuilder sb, boolean filterMeaninglessProperties, boolean useNumericalFilters, List<String> filters){
1229        Object subject = null;
1230        if(tree.getUserObject().equals("?")){
1231                subject = "?x" + cnt++;
1232                if(useNumericalFilters){
1233                        if(tree.isLiteralNode() && !tree.getLiterals().isEmpty()){
1234                                filters.add(getFilter(subject.toString(), tree.getLiterals()));
1235                        }
1236                }
1237        } else {
1238                subject = "<" + tree.getUserObject() + ">";
1239        }
1240        boolean first = true;
1241        Object predicate;
1242        Object object;
1243        if(!tree.isLeaf()){
1244                for(Iterator<QueryTree<N>> iter = tree.getChildren().iterator(); iter.hasNext();){
1245                        QueryTree<N> child = iter.next();
1246                        //get the predicate
1247                        predicate = tree.getEdge(child);
1248                        if(filterMeaninglessProperties){
1249                                if(Filters.getAllFilterProperties().contains(predicate.toString())){
1250                                        continue;
1251                                }
1252                        }
1253                        //get the object
1254                        object = child.getUserObject();
1255                        boolean objectIsResource = !object.equals("?");
1256                        if(!objectIsResource){
1257                                object = "?x" + cnt;
1258                        } else if(((String)object).startsWith("http://")){
1259                                object = "<" + object + ">";
1260                        }
1261                        //attach the triple pattern
1262                        if(first){
1263                                sb.append(subject).append(" <").append(predicate).append("> ").append(object);
1264                                if(iter.hasNext() && (objectIsResource || child.isLeaf())){
1265                                        sb.append(";");
1266                                } else {
1267                                        sb.append(".");
1268                                }
1269                                sb.append("\n");
1270                                first = false;
1271                        } else {
1272                                sb.append(" <").append(predicate).append("> ").append(object);
1273                                if(iter.hasNext() && (objectIsResource || child.isLeaf())){
1274                                        sb.append(";");
1275                                } else {
1276                                        sb.append(".");
1277                                }
1278                                sb.append("\n");
1279                        }
1280                        
1281                        //recursive call if object is not a resource or literal
1282                        if(!child.isResourceNode() && !child.isLeaf()){
1283                                buildSPARQLQueryString(child, sb, filterMeaninglessProperties, useNumericalFilters, filters);
1284                                if(child.isVarNode()){
1285                                        first = true;
1286                                }
1287                        }
1288                }
1289        } 
1290    }
1291    
1292    private String getFilter(String varName, Set<Literal> literals){
1293        String filter = "FILTER(";
1294        
1295        Literal min = getMin(literals);
1296        filter += varName + ">=\"" + min.getLexicalForm() + "\"^^<" + min.getDatatypeURI() + ">";
1297        
1298        filter += " && ";
1299        
1300        Literal max = getMax(literals);
1301        filter += varName + "<=\"" + max.getLexicalForm() + "\"^^<" + min.getDatatypeURI() + ">";
1302        
1303        filter += ")";
1304        return filter;
1305    }
1306    
1307    private boolean isLessOrEqual(Literal l1, Literal l2){
1308        if((l1.getDatatype() == XSDDatatype.XSDinteger || l1.getDatatype() == XSDDatatype.XSDint) &&
1309                        (l2.getDatatype() == XSDDatatype.XSDinteger || l2.getDatatype() == XSDDatatype.XSDint)){
1310                        return (l1.getInt() <= l2.getInt());
1311                } else if((l1.getDatatype() == XSDDatatype.XSDdouble || l1.getDatatype() == XSDDatatype.XSDdecimal) &&
1312                        (l2.getDatatype() == XSDDatatype.XSDdouble || l2.getDatatype() == XSDDatatype.XSDdecimal)){
1313                        return l1.getDouble() <= l2.getDouble();
1314                } else if(l1.getDatatype() == XSDDatatype.XSDfloat && l2.getDatatype() == XSDDatatype.XSDfloat){
1315                        return l1.getFloat() <= l2.getFloat();
1316                } else if(l1.getDatatype() == XSDDatatype.XSDdate && l2.getDatatype() == XSDDatatype.XSDdate){
1317                        Calendar date1 = DatatypeConverter.parseDate(l1.getLexicalForm());
1318                        Calendar date2 = DatatypeConverter.parseDate(l2.getLexicalForm());
1319                        int comp = date1.compareTo(date2);
1320                        return comp <= 0;
1321                } 
1322        return false;
1323    }
1324    
1325    private boolean isGreaterOrEqual(Literal l1, Literal l2){
1326        if((l1.getDatatype() == XSDDatatype.XSDinteger || l1.getDatatype() == XSDDatatype.XSDint) &&
1327                        (l2.getDatatype() == XSDDatatype.XSDinteger || l2.getDatatype() == XSDDatatype.XSDint)){
1328                        return (l1.getInt() >= l2.getInt());
1329                } else if((l1.getDatatype() == XSDDatatype.XSDdouble || l1.getDatatype() == XSDDatatype.XSDdecimal) &&
1330                        (l2.getDatatype() == XSDDatatype.XSDdouble || l2.getDatatype() == XSDDatatype.XSDdecimal)){
1331                        return l1.getDouble() >= l2.getDouble();
1332                } else if(l1.getDatatype() == XSDDatatype.XSDfloat && l2.getDatatype() == XSDDatatype.XSDfloat){
1333                        return l1.getFloat() >= l2.getFloat();
1334                } else if(l1.getDatatype() == XSDDatatype.XSDdate && l2.getDatatype() == XSDDatatype.XSDdate){
1335                        Calendar date1 = DatatypeConverter.parseDate(l1.getLexicalForm());
1336                        Calendar date2 = DatatypeConverter.parseDate(l2.getLexicalForm());
1337                        int comp = date1.compareTo(date2);
1338                        return comp >= 0;
1339                } 
1340        return false;
1341    }
1342    
1343    private Literal getMin(Set<Literal> literals){
1344        Iterator<Literal> iter = literals.iterator();
1345        Literal min = iter.next();
1346        Literal l;
1347        while(iter.hasNext()){
1348                l = iter.next();
1349                if(l.getDatatype() == XSDDatatype.XSDinteger || l.getDatatype() == XSDDatatype.XSDint){
1350                        min = (l.getInt() < min.getInt()) ? l : min;
1351                } else if(l.getDatatype() == XSDDatatype.XSDdouble || l.getDatatype() == XSDDatatype.XSDdecimal){
1352                        min = (l.getDouble() < min.getDouble()) ? l : min;
1353                } else if(l.getDatatype() == XSDDatatype.XSDfloat){
1354                        min = (l.getFloat() < min.getFloat()) ? l : min;
1355                } else if(l.getDatatype() == XSDDatatype.XSDdate){
1356                        min = (DatatypeConverter.parseDate(l.getLexicalForm()).compareTo(DatatypeConverter.parseDate(min.getLexicalForm())) == -1) ? l : min;
1357                } else if(l.getDatatype() == XSDDatatype.XSDgYear){
1358                        min = (DatatypeConverter.parseDate(l.getLexicalForm()).compareTo(DatatypeConverter.parseDate(min.getLexicalForm())) == -1) ? l : min;
1359                } 
1360        }
1361        return min;
1362    }
1363    
1364    private Literal getMax(Set<Literal> literals){
1365        Iterator<Literal> iter = literals.iterator();
1366        Literal max = iter.next();
1367        Literal l;
1368        while(iter.hasNext()){
1369                l = iter.next();
1370                if(l.getDatatype() == XSDDatatype.XSDinteger || l.getDatatype() == XSDDatatype.XSDint){
1371                        max = (l.getInt() > max.getInt()) ? l : max;
1372                } else if(l.getDatatype() == XSDDatatype.XSDdouble || l.getDatatype() == XSDDatatype.XSDdecimal){
1373                        max = (l.getDouble() > max.getDouble()) ? l : max;
1374                } else if(l.getDatatype() == XSDDatatype.XSDfloat){
1375                        max = (l.getFloat() > max.getFloat()) ? l : max;
1376                } else if(l.getDatatype() == XSDDatatype.XSDdate){
1377                        max = (DatatypeConverter.parseDate(l.getLexicalForm()).compareTo(DatatypeConverter.parseDate(max.getLexicalForm())) == 1) ? l : max;
1378                } else if(l.getDatatype() == XSDDatatype.XSDgYear){
1379                        max = (DatatypeConverter.parseDate(l.getLexicalForm()).compareTo(DatatypeConverter.parseDate(max.getLexicalForm())) == 1) ? l : max;
1380                } 
1381        }
1382        return max;
1383    }
1384    
1385    @Override
1386    public Query toQuery(){
1387        Query query = QueryFactory.make();
1388        query.setQuerySelectType();
1389        query.addResultVar(NodeFactory.createVariable("x0"));
1390        query.setDistinct(true);
1391        query.setPrefix("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#");
1392        query.setPrefix("rdfs", "http://www.w3.org/2000/01/rdf-schema#");
1393        query.setPrefix("yago", "http://dbpedia.org/class/yago/");
1394        query.setPrefix("cyc", "http://sw.opencyc.org/2008/06/10/concept/");
1395        query.setPrefix("owl", "http://www.w3.org/2002/07/owl#");
1396        query.setPrefix("dbp", "http://dbpedia.org/property/");
1397        query.setPrefix("dbo", "http://dbpedia.org/ontology/");
1398        query.setPrefix("dbr", "http://dbpedia.org/resource/");
1399        query.setPrefix("dc", "http://purl.org/dc/terms/");
1400        ElementGroup whereClause = new ElementGroup();
1401        ElementTriplesBlock triples = new ElementTriplesBlock();
1402        for(Triple t : buildTriples(this)){
1403                triples.addTriple(t);
1404        }
1405        whereClause.addElement(triples);
1406        
1407        query.setQueryPattern(whereClause);
1408        return query;
1409    }
1410    
1411    private List<Triple> buildTriples(QueryTree<N> tree){
1412        List<Triple> triples = new ArrayList<>();
1413        Pattern pattern = Pattern.compile("^^", Pattern.LITERAL);
1414        
1415        Node subject = tree.getUserObject().equals("?") ? NodeFactory.createVariable("x" + tree.getId()) : NodeFactory.createURI((String) tree.getUserObject());
1416        Node predicate = null;
1417        Node object = null;
1418        
1419        String objectLabel = null;
1420        for(QueryTree<N> child : tree.getChildren()){
1421                predicate = NodeFactory.createURI((String) tree.getEdge(child));
1422                objectLabel = (String) child.getUserObject();
1423                if(objectLabel.equals("?")){
1424                        object = NodeFactory.createVariable("x" + child.getId());
1425                } else if(objectLabel.startsWith("http:")){
1426                        object = NodeFactory.createURI(objectLabel);
1427                } else {
1428//                      System.out.println(objectLabel);
1429                        String[] split = objectLabel.split("@");
1430//                      System.out.println(Arrays.toString(split));
1431                        if(split.length == 2){
1432                                object = NodeFactory.createLiteral(split[0], split[1], null);
1433                        } else {
1434
1435                                split = pattern.split(objectLabel);
1436                                if(split.length == 2){
1437                                        object = NodeFactory.createLiteral(split[0], null, new BaseDatatype(split[1]));
1438                                } else {
1439                                        object = NodeFactory.createLiteral(objectLabel);
1440                                }
1441                        }
1442                        
1443                }
1444                triples.add(new Triple(subject, predicate, object));
1445                if(!child.isLeaf() && child.isVarNode()){
1446                        triples.addAll(buildTriples(child));
1447                }
1448        }
1449        return triples;
1450    }
1451    
1452    public void addLiteral(Literal l){
1453        literals.add(l);
1454    }
1455    
1456    @Override
1457    public Set<Literal> getLiterals() {
1458                return literals;
1459        }
1460    
1461    public void addLiterals(Collection<Literal> literals) {
1462        this.literals.addAll(literals);
1463        }
1464    
1465    @Override
1466    public RDFDatatype getDatatype(){
1467        if(isLiteralNode){
1468                if(!literals.isEmpty()){
1469                        return literals.iterator().next().getDatatype();
1470                } else {
1471                        return null;
1472                }
1473        } else {
1474                throw new UnsupportedOperationException("Node ist not a literal");
1475        }
1476    }
1477    
1478    /**
1479     * Converts the query tree in a corresponding OWL class expression. Literal nodes
1480     * are transformed into existential restrictions.
1481     */
1482    @Override
1483    public OWLClassExpression asOWLClassExpression(){
1484        return asOWLClassExpression(LiteralNodeConversionStrategy.DATATYPE);
1485    }
1486    
1487    /**
1488     * Converts the query tree in a corresponding OWL class expression. Literal nodes
1489     * are transformed following the given strategy.
1490     */
1491    @Override
1492    public OWLClassExpression asOWLClassExpression(LiteralNodeConversionStrategy literalNodeConversionStrategy){
1493        OWLDataFactory df = new OWLDataFactoryImpl();
1494        QueryTree<N> root = getRoot();
1495        Set<OWLClassExpression> classExpressions = buildOWLClassExpressions(df, root, literalNodeConversionStrategy);
1496        if(classExpressions.size() == 1){
1497                return classExpressions.iterator().next();
1498        } else {
1499                return df.getOWLObjectIntersectionOf(classExpressions);
1500        }
1501    }
1502    
1503    private Set<OWLClassExpression> buildOWLClassExpressions(OWLDataFactory df, QueryTree<N> tree, LiteralNodeConversionStrategy literalNodeConversionStrategy){
1504        
1505        List<QueryTree<N>> children = tree.getChildren();
1506        
1507        // if tree has no children return owl:Thing
1508        if(children.isEmpty()) {
1509                return Collections.<OWLClassExpression>singleton(df.getOWLThing());
1510        }
1511        
1512        // process children
1513        Set<OWLClassExpression> classExpressions = new HashSet<>();
1514        for(QueryTree<N> child : children){
1515                String childLabel = (String) child.getUserObject();
1516                String predicateString = (String) tree.getEdge(child);
1517                if(predicateString.equals(RDF.type.getURI()) || predicateString.equals(RDFS.subClassOf.getURI())){//A
1518                        if(child.isVarNode()){
1519                                classExpressions.addAll(buildOWLClassExpressions(df, child, literalNodeConversionStrategy));
1520                        } else {
1521                                if(!childLabel.equals(OWL.Thing.getURI())){//avoid trivial owl:Thing statements
1522                                        classExpressions.add(df.getOWLClass(IRI.create(childLabel)));
1523                                }
1524                        }
1525                } else {
1526                        if(child.isLiteralNode()){
1527                                OWLDataProperty p = df.getOWLDataProperty(IRI.create((String) tree.getEdge(child)));
1528                                if(childLabel.equals("?")){//p some int
1529                                        Set<Literal> literals = child.getLiterals();
1530                                        OWLDataRange dataRange = null;
1531                                        if(literals.isEmpty()){//happens if there are heterogeneous datatypes
1532                                                String datatypeURI = OWL2Datatype.RDFS_LITERAL.getIRI().toString();
1533                                                dataRange = df.getOWLDatatype(IRI.create(datatypeURI));
1534                                        } else {
1535                                                if(literalNodeConversionStrategy == LiteralNodeConversionStrategy.DATATYPE){
1536                                                        Literal lit = literals.iterator().next();
1537                                        RDFDatatype datatype = lit.getDatatype();
1538                                        String datatypeURI;
1539                                        if(datatype == null){
1540                                                datatypeURI = OWL2Datatype.RDF_PLAIN_LITERAL.getIRI().toString();
1541                                        } else {
1542                                                datatypeURI = datatype.getURI();
1543                                        }
1544                                        dataRange = df.getOWLDatatype(IRI.create(datatypeURI));
1545                                                } else if(literalNodeConversionStrategy == LiteralNodeConversionStrategy.DATA_ONE_OF){
1546                                                        dataRange = asDataOneOf(df, literals);
1547                                                } else if(literalNodeConversionStrategy == LiteralNodeConversionStrategy.MIN_MAX){
1548                                                        dataRange = asFacet(df, literals);
1549                                                } else if(literalNodeConversionStrategy == LiteralNodeConversionStrategy.MIN){
1550                                                        dataRange = asMinFacet(df, literals);
1551                                                } else if(literalNodeConversionStrategy == LiteralNodeConversionStrategy.MAX){
1552                                                        dataRange = asMaxFacet(df, literals);
1553                                                }
1554                                        }
1555                                classExpressions.add(df.getOWLDataSomeValuesFrom(p, dataRange));
1556                                } else {//p value 1.2
1557                                        Set<Literal> literals = child.getLiterals();
1558                                Literal lit = literals.iterator().next();
1559                                OWLLiteral owlLiteral = asOWLLiteral(df, lit);
1560                                classExpressions.add(df.getOWLDataHasValue(p, owlLiteral));
1561                                }
1562                        } else {
1563                                OWLObjectProperty p = df.getOWLObjectProperty(IRI.create((String) tree.getEdge(child)));
1564                                OWLClassExpression filler;
1565                                if(child.isVarNode()){//p some C
1566//                                      System.out.println(child + ":" + child.isVarNode() + ":" + child.isResourceNode());
1567                                Set<OWLClassExpression> fillerClassExpressions = buildOWLClassExpressions(df, child, literalNodeConversionStrategy);
1568                                if(fillerClassExpressions.isEmpty()){
1569                                        filler = df.getOWLThing();
1570                                } else if(fillerClassExpressions.size() == 1){
1571                                        filler = fillerClassExpressions.iterator().next();
1572                                } else {
1573                                        filler = df.getOWLObjectIntersectionOf(fillerClassExpressions);
1574                                }
1575                                classExpressions.add(df.getOWLObjectSomeValuesFrom(p, filler));
1576                        } else {//p value {a}
1577                                classExpressions.add(df.getOWLObjectHasValue(p, df.getOWLNamedIndividual(IRI.create(childLabel))));
1578                        }
1579                        }
1580                }
1581        }
1582        return classExpressions;
1583    }
1584    
1585    private OWLDataRange asFacet(OWLDataFactory df, Set<Literal> literals){
1586        //return Boolean datatype because it doesn't make sense to return a facet of Boolean values
1587        if(getOWLDatatype(df, literals).equals(df.getBooleanOWLDatatype())){
1588                return df.getBooleanOWLDatatype();
1589        }
1590        Literal min = getMin(literals);
1591        Literal max = getMax(literals);
1592        
1593        OWLFacetRestriction minRestriction = df.getOWLFacetRestriction(OWLFacet.MIN_INCLUSIVE, asOWLLiteral(df, min));
1594        OWLFacetRestriction maxRestriction = df.getOWLFacetRestriction(OWLFacet.MAX_INCLUSIVE, asOWLLiteral(df, max));
1595        
1596        return df.getOWLDatatypeRestriction(getOWLDatatype(df, literals), minRestriction, maxRestriction);
1597    }
1598    
1599    private OWLDataRange asMinFacet(OWLDataFactory df, Set<Literal> literals){
1600        //return Boolean datatype because it doesn't make sense to return a facet of Boolean values
1601        if(getOWLDatatype(df, literals).equals(df.getBooleanOWLDatatype())){
1602                return df.getBooleanOWLDatatype();
1603        }
1604        Literal min = getMin(literals);
1605        
1606        OWLFacetRestriction minRestriction = df.getOWLFacetRestriction(OWLFacet.MIN_INCLUSIVE, asOWLLiteral(df, min));
1607        
1608        return df.getOWLDatatypeRestriction(getOWLDatatype(df, literals), minRestriction);
1609    }
1610    
1611    private OWLDataRange asMaxFacet(OWLDataFactory df, Set<Literal> literals){
1612        //return Boolean datatype because it doesn't make sense to return a facet of Boolean values
1613        if(getOWLDatatype(df, literals).equals(df.getBooleanOWLDatatype())){
1614                return df.getBooleanOWLDatatype();
1615        }
1616        Literal max = getMax(literals);
1617        
1618        OWLFacetRestriction maxRestriction = df.getOWLFacetRestriction(OWLFacet.MAX_INCLUSIVE, asOWLLiteral(df, max));
1619        
1620        return df.getOWLDatatypeRestriction(getOWLDatatype(df, literals), maxRestriction);
1621    }
1622    
1623    private OWLDataRange asDataOneOf(OWLDataFactory df, Set<Literal> literals){
1624        //return Boolean datatype because it doesn't make sense to return a enumeration of Boolean values
1625        if(getOWLDatatype(df, literals).equals(df.getBooleanOWLDatatype())){
1626                return df.getBooleanOWLDatatype();
1627        }
1628        return df.getOWLDataOneOf(asOWLLiterals(df, literals));
1629    }
1630    
1631    private Set<OWLLiteral> asOWLLiterals(OWLDataFactory df, Set<Literal> literals){
1632        Set<OWLLiteral> owlLiterals = new HashSet<>(literals.size());
1633        for (Literal literal : literals) {
1634                        owlLiterals.add(asOWLLiteral(df, literal));
1635                }
1636        return owlLiterals;
1637    }
1638    
1639    private OWLLiteral asOWLLiteral(OWLDataFactory df, Literal literal){
1640        OWLLiteral owlLiteral;
1641                if(literal.getDatatypeURI() == null){
1642                        owlLiteral = df.getOWLLiteral(literal.getLexicalForm(), literal.getLanguage());
1643                } else {
1644                        owlLiteral = df.getOWLLiteral(literal.getLexicalForm(), df.getOWLDatatype(IRI.create(literal.getDatatypeURI())));
1645                }
1646        return owlLiteral;
1647    }
1648    
1649    private OWLDatatype getOWLDatatype(OWLDataFactory df, Set<Literal> literals){
1650        return df.getOWLDatatype(IRI.create(literals.iterator().next().getDatatypeURI()));
1651    }
1652    
1653    private void buildGraph(Graph<Vertex, Edge> graph, QueryTree<N> tree){
1654        PrefixCCMap prefixes = PrefixCCMap.getInstance();
1655        List<QueryTree<N>> children = tree.getChildren();
1656        Vertex parent = new Vertex(tree.getId(), prefixed(prefixes, tree.getUserObject().toString()));
1657        graph.addVertex(parent);
1658        for (QueryTree<N> child : children) {
1659                Vertex childVertex = new Vertex(child.getId(), prefixed(prefixes, child.getUserObject().toString()));
1660                graph.addVertex(childVertex);
1661                Edge edge = new Edge(Long.parseLong(parent.getId() + "0" + childVertex.getId()), prefixed(prefixes, tree.getEdge(child).toString()));
1662                        graph.addEdge(parent, childVertex, edge);
1663                        buildGraph(graph, child);
1664                }
1665    }
1666    
1667    public String asJSON(){
1668        
1669        PrefixCCMap prefixes = PrefixCCMap.getInstance();
1670        JSONObject json = null;
1671                try {
1672                        json = buildJSON(this, prefixes);
1673                        JSONArray array = new JSONArray();
1674                        buildJSON2(array, this, prefixes);
1675                        System.out.println(array);
1676                } catch (JSONException e) {
1677                        e.printStackTrace();
1678                }
1679                
1680                
1681        return json.toString();
1682    }
1683    
1684    private JSONObject buildJSON(QueryTree<N> tree, PrefixCCMap prefixes) throws JSONException{
1685        JSONObject json = new JSONObject();
1686        json.put("name", prefixed(prefixes, tree.getUserObject().toString()));
1687        JSONArray children = new JSONArray();
1688        for (QueryTree<N> child : tree.getChildren()) {
1689                        children.put(buildJSON(child, prefixes));
1690                }
1691        json.put("children", children);
1692        return json;
1693    }
1694    
1695    private void buildJSON2(JSONArray array, QueryTree<N> tree, PrefixCCMap prefixes) throws JSONException{
1696        for (QueryTree<N> child : tree.getChildren()) {
1697                JSONObject json = new JSONObject();
1698                json.put("source", tree.getId());
1699                json.put("target", child.getId());
1700                json.put("type", prefixed(prefixes, tree.getEdge(child).toString()));
1701                array.put(json);
1702                buildJSON2(array, child, prefixes);
1703                }
1704    }
1705    
1706    private String prefixed(Map<String, String> prefixes, String uri){
1707        if(uri.startsWith("http://")){
1708                for (Entry<String, String> entry : prefixes.entrySet()) {
1709                        String prefix = entry.getKey();
1710                        String ns = entry.getValue();
1711                        if(uri.startsWith(ns)){
1712                                return uri.replace(ns, prefix + ":");
1713                        }
1714                }
1715        }
1716        return uri;
1717    }
1718}