view src/treecms/tree/util/NodeChildrenImpl.java @ 26:9cb971a68cc5

added CachedForest.java
author Shoshi TAMAKI <shoshi@cr.ie.u-ryukyu.ac.jp>
date Mon, 18 Jul 2011 20:22:53 +0900
parents c1e7ec6b3d44
children
line wrap: on
line source

package treecms.tree.util;

import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArrayList;

import treecms.api.NodeAttributes;
import treecms.api.NodeChildren;
import treecms.api.NodeContext;
import treecms.api.NodeID;

public class NodeChildrenImpl<T extends NodeContext & NodeAttributes & NodeChildren<T>> implements NodeChildren<T>
{
	private final ConcurrentMap<String,T> m_map;
	private final List<T> m_list;
	private final List<T> m_readOnlyList;
	
	public NodeChildrenImpl()
	{
		m_map = new ConcurrentHashMap<String,T>();
		m_list = new CopyOnWriteArrayList<T>();
		m_readOnlyList = Collections.unmodifiableList(m_list);
	}
	
	public NodeChildrenImpl(T... _args)
	{
		this();
		for(T i : _args){
			String fid = i.getID().getFamilyID();
			if(!m_map.containsKey(fid)){
				m_map.put(fid,i);
				m_list.add(i);
			}
		}
	}
	
	public NodeChildrenImpl(NodeChildren<T> _list)
	{
		this();
		
		if(_list != null){
			addAll(_list);
		}else{
			throw new NullPointerException("_list is null");
		}
	}
	
	@Override
	public synchronized List<T> getList()
	{
		return m_readOnlyList;
	}
	
	@Override
	public T create(NodeAttributes _attr)
	{
		throw new UnsupportedOperationException();
	}
	
	public synchronized T replace(T _node)
	{
		String fid = _node.getID().getFamilyID();
		
		T old = m_map.get(fid);
		
		if(old != null){
			m_map.put(fid,_node);
			
			//find index of _node , better put index with node in the map?
			int size = m_list.size();
			for(int i = 0;i < size;i ++){
				T n = m_list.get(i);
				NodeID nid = n.getID();
				if(nid.isFamily(_node.getID())){
					m_list.set(i,_node);
					return old;
				}
			}
			
			throw new IllegalStateException("FamilyID is found on the map but not found on the list");
		}
		return null;
	}
	
	public synchronized boolean add(T _n)
	{
		if(!m_map.containsKey(_n.getID().getFamilyID())){
			m_map.put(_n.getID().getFamilyID(),_n);
			return m_list.add(_n);
		}
		return false;
	}
	
	public synchronized boolean addAll(NodeChildren<T> _list)
	{
		if(_list == this){
			return false;
		}
		
		if(Collections.disjoint(getFamilyIDSet(),_list.getFamilyIDSet())){
		
			for(T item : _list.getList()){
				NodeID id = item.getID();
				m_map.put(id.getFamilyID(),item);
			}
			
			return m_list.addAll(_list.getList());
		}
		return false;
	}
	
	@Override
	public synchronized T get(int _index)
	{
		return m_list.get(_index);
	}
	
	@Override
	public synchronized T get(String _familyID)
	{
		return m_map.get(_familyID);
	}
	
	@Override
	public synchronized T remove(int _index)
	{
		T n = m_list.remove(_index);
		NodeID id = n.getID();
		if(m_map.remove(id.getFamilyID()) != null){
			return n; 
		}
		
		throw new IllegalStateException("");
	}
	
	@Override
	public synchronized boolean contains(NodeID _id)
	{
		T n = m_map.get(_id.getFamilyID());
		if(n == null){
			return false;
		}
		
		NodeID id = n.getID();
		
		String fid1 = id.getFamilyID();
		String fid2 = _id.getFamilyID();
		return fid1.equals(fid2);
	}
	
	@Override
	public synchronized void clearChildren()
	{
		m_map.clear();
		m_list.clear();
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public synchronized boolean equals(Object _o)
	{
		NodeChildrenImpl<T> list = (NodeChildrenImpl<T>)_o;
		return m_list.equals(list.m_list);
	}
	
	@Override
	public synchronized int hashCode()
	{
		int result = 17;
		result = 37*result + m_list.hashCode();
		result = 37*result + m_map.hashCode();
		return result;
	}

	@Override
	public synchronized Set<String> getFamilyIDSet()
	{
		return m_map.keySet();
	}

	@Override
	public synchronized T remove(String _fid)
	{
		return m_map.remove(_fid);
	}

	@Override
	public synchronized boolean swap(String _fid1, String _fid2)
	{
		if(m_map.containsKey(_fid1) && m_map.containsKey(_fid2)){
			int index1,index2;
			index1 = index2 = -1;
			int size = m_list.size();
			for(int i = 0;i < size;i ++){
				T n = m_list.get(i);
				String fid = n.getID().getFamilyID();
				
				if(fid.equals(_fid1)){
					index1 = i;
				}else if(fid.equals(_fid2)){
					index2 = i;
				}
				
				if(index1 != -1 && index2 != -1){
					Collections.swap(m_list, index1, index2);
					return true;
				}
			}
		}
		return false;
	}
	
	@Override
	public String toString()
	{
		return m_list.toString();
	}
}