001/*
002 * (C) Copyright 2006-2007 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Jean-Marc Orliaguet, Chalmers
018 *
019 * $Id$
020 */
021
022package org.nuxeo.theme.nodes;
023
024import java.util.ArrayList;
025import java.util.List;
026
027public abstract class AbstractNode implements Node {
028
029    private Node parentNode;
030
031    private List<Node> childrenNodes = new ArrayList<Node>();
032
033    public void clearParent() {
034        parentNode = null;
035    }
036
037    public void setParent(Node parent) throws NodeException {
038        if (equals(parent)) {
039            throw new NodeException(String.format("A node cannot be made a parent of itself: %s.", this));
040        }
041        if (parent != null && parent.isChildOf(this)) {
042            throw new NodeException(String.format("Cycle detected while trying to make %s a parent of %s.", parent,
043                    this));
044        }
045        if (parentNode != null) {
046            List<Node> siblings = parentNode.getChildren();
047            siblings.remove(this);
048            parentNode.setChildren(siblings);
049        }
050        parentNode = parent;
051    }
052
053    public Node getParent() {
054        return parentNode;
055    }
056
057    public Node addChild(Node node) throws NodeException {
058        if (equals(node)) {
059            throw new NodeException(String.format("A node cannot be made a child of itself: %s.", this));
060        }
061        if (isChildOf(node)) {
062            throw new NodeException(String.format("Cycle detected while trying to add child %s to %s.", node, this));
063        }
064        childrenNodes.add(node);
065        node.setParent(this);
066        return node;
067    }
068
069    public void removeChild(Node node) throws NodeException {
070        if (!childrenNodes.contains(node)) {
071            throw new NodeException(String.format("Trying to remove unexisting child %s of %s", node, this));
072        }
073        childrenNodes.remove(node);
074        node.setParent(null);
075    }
076
077    public List<Node> getChildren() {
078        return childrenNodes;
079    }
080
081    public void setChildren(List<Node> children) throws NodeException {
082        for (Node child : children) {
083            if (equals(child)) {
084                throw new NodeException(String.format("Node %s cannot be made a child of itself", child));
085            }
086            if (isChildOf(child)) {
087                throw new NodeException(String.format("Cycle detected while trying to set children of %s.", this));
088            }
089        }
090        childrenNodes = children;
091    }
092
093    public abstract NodeTypeFamily getNodeTypeFamily();
094
095    public boolean isLeaf() {
096        return getNodeTypeFamily() == NodeTypeFamily.LEAF;
097    }
098
099    public Integer getOrder() {
100        Integer order = null;
101        if (parentNode != null) {
102            order = parentNode.getChildren().indexOf(this);
103        }
104        return order;
105    }
106
107    public void setOrder(Integer order) throws NodeException {
108        if (order == null) {
109            throw new NodeException(String.format("Cannot set node order to null on %s", this));
110        }
111        if (parentNode == null) {
112            throw new NodeException(String.format("Cannot set order on node %s unless it has a parent", this));
113        }
114        List<Node> siblings = parentNode.getChildren();
115        siblings.remove(this);
116        if (order < 0 || (order > 0 && order > siblings.size())) {
117            throw new NodeException(String.format("Incorrect node order value (%s) for %s", order, this));
118        }
119        siblings.add(order, this);
120        parentNode.setChildren(siblings);
121    }
122
123    public void moveTo(Node container, Integer order) throws NodeException {
124        setParent(container);
125        setOrder(order);
126    }
127
128    public void insertAfter(Node node) throws NodeException {
129        node.getParent().addChild(this);
130        moveTo(node.getParent(), node.getOrder() + 1);
131    }
132
133    public boolean hasSiblings() {
134        if (parentNode == null) {
135            return false;
136        }
137        return parentNode.getChildren().size() > 1;
138    }
139
140    public Node getNextNode() {
141        int order = getOrder();
142        List<Node> siblings = parentNode.getChildren();
143        if (order + 1 >= siblings.size()) {
144            return null;
145        }
146        return siblings.get(order + 1);
147    }
148
149    public Node getPreviousNode() {
150        int order = getOrder();
151        if (order == 0) {
152            return null;
153        }
154        List<Node> siblings = parentNode.getChildren();
155        return siblings.get(order - 1);
156    }
157
158    public boolean hasChildren() {
159        return !childrenNodes.isEmpty();
160    }
161
162    public boolean isChildOf(Node node) {
163        boolean res = false;
164        Node parent = parentNode;
165        while (parent != null) {
166            if (parent == node) {
167                res = true;
168                break;
169            }
170            parent = parent.getParent();
171        }
172        return res;
173    }
174
175    public void removeDescendants() throws NodeException {
176        for (Node child : childrenNodes) {
177            child.removeDescendants();
178            child.clearParent();
179        }
180        childrenNodes.clear();
181    }
182
183    public List<Node> getDescendants() {
184        List<Node> descendants = new ArrayList<Node>();
185        collectDescendants(descendants);
186        return descendants;
187    }
188
189    public void collectDescendants(List<Node> nodes) {
190        for (Node child : childrenNodes) {
191            nodes.add(child);
192            child.collectDescendants(nodes);
193        }
194    }
195
196}