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