Index: trunk/nv/ecs/ecs.hh
===================================================================
--- trunk/nv/ecs/ecs.hh	(revision 535)
+++ trunk/nv/ecs/ecs.hh	(revision 536)
@@ -182,6 +182,33 @@
 			}
 
+			virtual void attach( handle_type parent, handle_type child )
+			{
+				m_handles.detach( child );
+				m_handles.attach( parent, child );
+			}
+
+			handle_type get_parent( handle_type h ) const
+			{
+				return h ? m_handles.get_parent( h ) : handle_type();
+			}
+
+			handle_type next( handle_type h ) const
+			{
+				return h ? m_handles.next( h ) : handle_type();
+			}
+
+			handle_type first( handle_type h ) const
+			{
+				return h ? m_handles.first( h ) : handle_type();
+			}
+
 			void remove( handle_type h )
 			{
+				handle_type ch = m_handles.first( h );
+				while ( handle_type r = ch )
+				{
+					ch = m_handles.next( ch );
+					remove( r );
+				}
 				for ( auto c : m_components )
 					c->remove( h );
@@ -208,5 +235,5 @@
 		protected:
 
-			handle_manager< handle_type >               m_handles;
+			handle_tree_manager< handle_type >          m_handles;
 			vector< component_interface* >              m_components;
 			vector< receiver_interface* >               m_receivers;
@@ -246,6 +273,7 @@
 			value_type& insert( handle_type h )
 			{
-				/*index_type i = */m_index.insert( h );
-				//NV_ASSERT( i == m_data.size(), "Fail!" );
+				index_type i = m_index.insert( h );
+				NV_ASSERT( i == index_type( m_data.size() ), "Fail!" );
+				NV_UNUSED( i );
 				m_data.emplace_back();
 				return m_data.back();
@@ -255,6 +283,7 @@
 			value_type& insert( handle_type h, Args&&... args )
 			{
-				/*index_type i = */m_index.insert( h );
-				//NV_ASSERT( i == m_data.size(), "Fail!" );
+				index_type i = m_index.insert( h );
+				NV_ASSERT( i == index_type( m_data.size() ), "Fail!" );
+				NV_UNUSED( i );
 				m_data.emplace_back( nv::forward<Args>( args )... );
 				return m_data.back();
@@ -302,5 +331,4 @@
 				return i >= 0 ? &( m_data[unsigned( i )] ) : nullptr;
 			}
-
 
 			virtual void remove( handle_type h )
Index: trunk/nv/stl/handle_manager.hh
===================================================================
--- trunk/nv/stl/handle_manager.hh	(revision 535)
+++ trunk/nv/stl/handle_manager.hh	(revision 536)
@@ -95,5 +95,5 @@
 			value_type counter;
 			index_type next_free;
-
+			
 			index_entry() : counter( 0 ), next_free( NONE ) {}
 		};
@@ -118,4 +118,192 @@
 	};
 
+	template < typename Handle, typename Index = sint32 >
+	class handle_tree_manager
+	{
+		typedef Index index_type;
+		static const index_type NONE = index_type( -1 );
+		static const index_type USED = index_type( -2 );
+	public:
+
+		typedef Handle handle_type;
+		typedef typename handle_type::value_type value_type;
+
+		handle_tree_manager() 
+			: m_first_free( NONE ), m_last_free( NONE ) {}
+
+		handle_type create_handle()
+		{
+			typedef handle_operator<handle_type> hop;
+			value_type i = get_free_entry();
+			m_entries[i].counter++;
+			NV_ASSERT( m_entries[i].counter != 0, "Out of handles!" );
+			m_entries[i].next_free = USED;
+			return hop::create( i, m_entries[i].counter );
+		}
+
+		void free_handle( handle_type h )
+		{
+			remove( h );
+			value_type index = h.index();
+			NV_ASSERT( m_entries[index].next_free == USED, "Unused handle freed!" );
+			NV_ASSERT( m_entries[index].counter == handle_operator<handle_type>::get_counter( h ), "Handle corruption!" );
+			m_entries[index].next_free = NONE;
+			if ( m_last_free == NONE )
+			{
+				m_first_free = m_last_free = static_cast<index_type>( index );
+				return;
+			}
+			m_entries[static_cast<value_type>( m_last_free )].next_free = static_cast<index_type>( index );
+			m_last_free = static_cast<index_type>( index );
+		}
+
+		void attach( handle_type parent, handle_type child )
+		{
+			value_type pindex = parent.index();
+			value_type cindex = child.index();
+			NV_ASSERT( m_entries[cindex].parent == NONE, "Attach called on handle with parent!" );
+			m_entries[cindex].parent = pindex;
+			m_entries[cindex].next_sibling = m_entries[pindex].first_child;
+			m_entries[cindex].prev_sibling = NONE;
+			m_entries[pindex].first_child = cindex;
+		}
+
+		handle_type get_parent( handle_type h ) const
+		{
+			NV_ASSERT( is_valid( h ), "INVALID HANDLE" );
+			value_type pindex = m_entries[h.index()].parent;
+			typedef handle_operator<handle_type> hop;
+			return pindex == NONE ? handle_type() : hop::create( pindex, m_entries[pindex].counter );
+		}
+
+		handle_type next( handle_type h ) const
+		{
+			NV_ASSERT( is_valid( h ), "INVALID HANDLE" );
+			value_type nindex = m_entries[ h.index() ].next_sibling;
+			typedef handle_operator<handle_type> hop;
+			return nindex == NONE ? handle_type() : hop::create( nindex, m_entries[nindex].counter ); 
+		}
+
+		handle_type first( handle_type h ) const
+		{
+			NV_ASSERT( is_valid( h ), "INVALID HANDLE" );
+			value_type nindex = m_entries[h.index()].first_child;
+			typedef handle_operator<handle_type> hop;
+			return nindex == NONE ? handle_type() : hop::create( nindex, m_entries[nindex].counter );
+		}
+
+
+		void remove( handle_type h )
+		{
+			NV_ASSERT( m_entries[h.index()].first_child == NONE, "Remove called on handle with children!" );
+			detach( h );
+		}
+
+		void remove_and_orphan( handle_type h )
+		{
+			detach( h );
+			value_type index = h.index();
+			while ( m_entries[index].first_child != NONE )
+			{
+				value_type child = m_entries[index].first_child;
+				m_entries[index].first_child  = m_entries[child].next_sibling;
+				m_entries[child].parent       = NONE;
+				m_entries[child].next_sibling = NONE;
+				m_entries[child].prev_sibling = NONE;
+			}
+		}
+
+		void detach( handle_type h )
+		{
+			value_type index      = h.index();
+			value_type pindex     = m_entries[index].parent;
+			value_type next_index = m_entries[index].next_sibling;
+			value_type prev_index = m_entries[index].prev_sibling;
+			
+			m_entries[index].parent       = NONE;
+			m_entries[index].next_sibling = NONE;
+			m_entries[index].prev_sibling = NONE;
+
+			if ( pindex == NONE )
+			{
+				NV_ASSERT( next_index == NONE, "Hierarchy fail! next_index" );
+				NV_ASSERT( prev_index == NONE, "Hierarchy fail! prev_index" );
+				return;
+			}
+			if ( value_type( m_entries[pindex].first_child ) == index )
+			{
+				NV_ASSERT( prev_index == NONE, "Hierarchy fail! prev_index" );
+				m_entries[pindex].first_child = next_index;
+				if ( next_index == NONE ) // only child
+					return;
+				m_entries[next_index].prev_sibling = NONE;
+			}
+			else
+			{
+				NV_ASSERT( prev_index != NONE, "Hierarchy fail! prev_index" );
+				if ( next_index != NONE )
+					m_entries[next_index].prev_sibling = prev_index;
+				if ( prev_index != NONE )
+					m_entries[prev_index].next_sibling = next_index;
+			}
+		}
+
+		bool is_valid( handle_type h ) const
+		{
+			typedef handle_operator<handle_type> hop;
+			if ( h.is_nil() ) return false;
+			if ( h.index() >= m_entries.size() ) return false;
+			const index_entry& entry = m_entries[h.index()];
+			return entry.next_free == USED && entry.counter == hop::get_counter( h );
+		}
+
+		void clear()
+		{
+			m_first_free = NONE;
+			m_last_free = NONE;
+			m_entries.clear();
+		}
+
+	private:
+		struct index_entry
+		{
+			value_type counter;
+			index_type next_free;
+
+			index_type parent;
+			index_type first_child;
+			index_type next_sibling;
+			index_type prev_sibling;
+
+			index_entry() 
+				: counter( 0 )
+				, next_free( NONE )
+				, parent( NONE )
+				, first_child( NONE )
+				, next_sibling( NONE )
+				, prev_sibling( NONE )
+			{}
+		};
+
+		value_type get_free_entry()
+		{
+			if ( m_first_free != NONE )
+			{
+				value_type result = static_cast<value_type>( m_first_free );
+				m_first_free = m_entries[result].next_free;
+				m_entries[result].next_free = USED;
+				if ( m_first_free == NONE ) m_last_free = NONE;
+				return result;
+			}
+			m_entries.emplace_back();
+			return value_type( m_entries.size() - 1 );
+		}
+
+		index_type m_first_free;
+		index_type m_last_free;
+		vector< index_entry > m_entries;
+	};
+
+
 }
 
