ch.thn.datatree.core.GenericMapTreeNode.java Source code

Java tutorial

Introduction

Here is the source code for ch.thn.datatree.core.GenericMapTreeNode.java

Source

/**
 *    Copyright 2015 Thomas Naeff (github.com/thnaeff)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 */
package ch.thn.datatree.core;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Set;

import com.google.common.collect.LinkedListMultimap;
import com.google.common.collect.Multimap;

/**
 * 
 * 
 *
 * @author Thomas Naeff (github.com/thnaeff)
 *
 * @param <K>
 * @param <V>
 * @param <N>
 * @param <C>
 */
public abstract class GenericMapTreeNode<K, V, N extends GenericMapTreeNode<K, V, N, C>, C extends Collection<N>>
        extends GenericCollectionTreeNode<V, N, C> implements MapTreeNodeInterface<K, V, N> {

    private Multimap<K, N> map = null;

    private K key = null;

    /**
     * 
     * 
     * @param childrenMap
     * @param childrenCollection
     * @param key
     * @param value
     */
    public GenericMapTreeNode(LinkedListMultimap<K, N> childrenMap, K key, V value) {
        super(null, value);
        this.key = key;
        this.map = childrenMap;
    }

    /**
     * <i><b>For internal use only!</b></i>
     * 
     * @return
     */
    @Override
    protected abstract N internalGetThis();

    /**
     * 
     * 
     * @param childrenMap
     */
    protected void internalSetChildrenMap(Multimap<K, N> childrenMap) {
        this.map = childrenMap;
    }

    /**
     * <i><b>For internal use only!</b></i>
     * <br />
     * Sets the key for this node. The key of a node always has to match the key of the
     * map where the node is added as a child. This means that once a node is added
     * as a child, the key should not be modified any more!
     * 
     * @param key
     */
    protected void internalSetNodeKey(K key) {
        this.key = key;
    }

    /**
     * 
     * 
     * @return
     */
    protected Multimap<K, N> internalGetMap() {
        return map;
    }

    /**
     * 
     * 
     * @param key
     * @return
     */
    @SuppressWarnings("unchecked")
    protected C internalGetChildren(K key) {
        return (C) map.get(key);
    }

    @Override
    public abstract N nodeFactory(K key, V value);

    @Override
    public K getNodeKey() {
        return key;
    }

    @Override
    public Collection<N> getChildNodes(K key) {
        return Collections.unmodifiableCollection(map.get(key));
    }

    @Override
    public Collection<N> getChildNodes() {
        return Collections.unmodifiableCollection(internalGetChildren());
    }

    @Override
    public N addChildNode(N node) {
        if (node.getParentNode() != null) {
            throw new TreeNodeError(
                    "The node already has a parent node set (which " + "means it is from another tree)");
        }

        return internalAddChildNode(node, true);
    }

    @Override
    protected N internalAddChildNode(N node, boolean notify) {
        map.put(node.getNodeKey(), node);
        node.internalSetParentNode(internalGetThis(), true);

        if (notify) {
            fireNodeEvent(TreeEventType.CHILD_ADDED, node, internalGetThis(), node.getNodeIndex(), null);
        }

        return node;
    }

    @Override
    public N addChildNode(V value) {
        return internalAddChildNode(nodeFactory(value), true);
    }

    @Override
    public N addChildNode(K key, V value) {
        N node = nodeFactory(key, value);
        node.internalSetParentNode(internalGetThis(), true);
        map.put(key, node);

        fireNodeEvent(TreeEventType.CHILD_ADDED, node, internalGetThis(), node.getNodeIndex(), null);

        return node;
    }

    @Override
    public N addChildNodeCopy(N node) {
        return internalAddChildNode(node.nodeFactory(node), true);
    }

    @Override
    public boolean addChildNodes(Collection<N> nodes) {
        for (N node : nodes) {
            internalAddChildNode(node, true);
        }

        return true;
    }

    @Override
    public boolean addChildNodes(Multimap<K, N> nodes) {
        if (map.putAll(nodes)) {
            for (N node : nodes.values()) {
                node.internalSetParentNode(internalGetThis(), true);

                fireNodeEvent(TreeEventType.CHILD_ADDED, node, internalGetThis(), node.getNodeIndex(), null);
            }

            return true;
        }

        return false;
    }

    @Override
    public Collection<N> removeChildNodes(K key) {
        //The removed children might or might not be in an ordered list. Create an
        //ordered list here in whatever order the children are.
        ArrayList<N> tempChildren = new ArrayList<N>(map.get(key));

        //Remove children in reverse order with the last one first.
        //This is important because when removing
        //the first child, the indexes of all the following children change.
        for (int i = tempChildren.size() - 1; i >= 0; i--) {
            N node = tempChildren.get(i);
            int oldIndex = node.getNodeIndex();
            node.internalSetParentNode(null, true);

            fireNodeEvent(TreeEventType.CHILD_REMOVED, node, internalGetThis(), oldIndex, null);
        }

        map.removeAll(key);

        return tempChildren;
    }

    @Override
    public boolean removeChildNode(K key, N node) {
        int oldIndex = node.getNodeIndex();
        boolean ret = map.remove(key, node);

        node.internalSetParentNode(null, true);

        fireNodeEvent(TreeEventType.CHILD_REMOVED, node, internalGetThis(), oldIndex, null);

        return ret;
    }

    /**
     * Replaces this node with a new node which contains the given key and value.
     * 
     * @param key
     * @param value
     * @return
     */
    public N replaceNode(K key, V value) {
        return super.replaceNode(nodeFactory(key, value));
    }

    @Override
    public int getChildNodesCount(K key) {
        return internalGetChildren(key).size();
    }

    @Override
    public Set<K> getChildNodeKeys() {
        return map.keySet();
    }

    @Override
    public boolean hasChildNodes(K key) {
        return map.containsKey(key);
    }

    @Override
    public String toString() {
        return "[" + key + "] " + getNodeValue();
    }

}