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;
020import java.util.ArrayList;
021import java.util.List;
022import java.util.regex.Matcher;
023import java.util.regex.Pattern;
024
025public class GenericTree<T, V extends GenericTree<T, V>> {
026
027        protected static int idCounter = 0;
028
029    protected T data;
030    protected V parent;
031    protected List<V> children = new ArrayList<>();
032
033    public GenericTree() {}
034    
035    public GenericTree(T data) {
036        setData(data);
037    }
038    
039        public void setParent(V parent) {
040                this.parent = parent;
041        }
042    
043        /**
044         * @return the parent node of this tree, or <code>null</code> if this
045         * tree is the root node
046         */
047        public V getParent() {
048                return parent;
049        }
050
051        /**
052         * @return all direct children of this tree
053         */
054    public List<V> getChildren() {
055        return this.children;
056    }
057    
058    /**
059     * @return all leaf nodes of this tree
060     */
061    public List<V> getLeafs() {
062        List<V> leafs = new ArrayList<>();
063        for(V child : children) {
064                if(child.isLeaf()) {
065                        leafs.add(child);
066                } else {
067                        leafs.addAll(child.getLeafs());
068                }
069        }
070        return leafs;
071    }
072    
073    /**
074     * @return whether this is the root node
075     */
076    public boolean isRoot() {
077        return parent == null;
078    }
079    
080    /**
081     * @return whether this is a leaf node
082     */
083    public boolean isLeaf() {
084        return children.isEmpty();
085    }
086
087    public int getNumberOfChildren() {
088        return getChildren().size();
089    }
090
091    public boolean hasChildren() {
092        return !children.isEmpty();
093    }
094
095    public void setChildren(List<V> children) {
096        this.children = children;
097    }
098
099    public void addChild(V child) {
100        children.add(child);
101        child.setParent((V) this);
102    }
103    
104    public void addChildren(List<V> children) {
105        for (V v : children) {
106                        addChild(v);
107                }
108    }
109    
110    public void removeChild(V child) {
111        children.remove(child);
112        child.setParent(null);
113    }
114
115    public void addChildAt(int index, V child) throws IndexOutOfBoundsException {
116        children.add(index, child);
117        child.setParent((V) this);
118    }
119
120    public void removeChildren() {
121        this.children = new ArrayList<>();
122    }
123
124    public void removeChildAt(int index) throws IndexOutOfBoundsException {
125        children.remove(index);
126    }
127
128    public V getChildAt(int index) throws IndexOutOfBoundsException {
129        return children.get(index);
130    }
131
132    @Override
133    public boolean equals(Object o) {
134        if (this == o) return true;
135        if (o == null || getClass() != o.getClass()) return false;
136
137        GenericTree<?, ?> that = (GenericTree<?, ?>) o;
138
139        return data.equals(that.data);
140    }
141
142    @Override
143    public int hashCode() {
144        return data.hashCode();
145    }
146
147    public T getData() {
148        return this.data;
149    }
150
151    public void setData(T data) {
152        this.data = data;
153    }
154
155    public String toString() {
156        return getData().toString();
157    }
158
159        protected static synchronized int createID() {
160                return idCounter++;
161        }
162
163    public String toStringVerbose() {
164        String stringRepresentation = getData().toString() + ":[";
165
166        for (V node : getChildren()) {
167            stringRepresentation += node.toStringVerbose() + ", ";
168        }
169
170        //Pattern.DOTALL causes ^ and $ to match. Otherwise it won't. It's retarded.
171        Pattern pattern = Pattern.compile(", $", Pattern.DOTALL);
172        Matcher matcher = pattern.matcher(stringRepresentation);
173
174        stringRepresentation = matcher.replaceFirst("");
175        stringRepresentation += "]";
176
177        return stringRepresentation;
178    }
179}