/*
 * metafs.h - Meta File-System manages parent-child accesses
 * 
 * Authors   Ghassan Almaless (2008,2009,2010,2011,2012)
 *           Alain Greiner    (2016)
 *
 * Copyright (c) UPMC Sorbonne Universites
 *
 * This file is part of ALMOS-MKH.
 *
 * ALMOS-MKH is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 2.0 of the License.
 *
 * ALMOS-MKH is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with ALMOS-MKH; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
 */

#ifndef _METAFS_H_
#define _METAFS_H_

#include <almos_config.h>
#include <hal_types.h>
#include <list.h>
#include <string.h>

#define METAFS_HASH_SIZE    10

/******************************************************************************************
 * This structure define a node in the metafs tree.
 *****************************************************************************************/

typedef struct metafs_s
{
	char        * name;                         /*! name represented by this node        */
	uint32_t      children_nr;                  /*! number of chidren for this node      */
	list_entry_t  list;                         /*! child : member of a children list    */     
	list_entry_t  hash_tbl[METAFS_HASH_SIZE];   /*! parent : array of roots of children  */
                                                /*!          lists, sorted by key value  */
}
metafs_t;

/******************************************************************************************
 * This function compute the hash key for a given name.
 ******************************************************************************************
 * @ name     : string to be analysed.
 * return the key value, from 0 to (METAFS_HASH_SIZE - 1)
 *****************************************************************************************/
static inline uint32_t metafs_hash_index( char * dev_name )
{
	register char    * str   = dev_name;
	register uint32_t  index = 0;
  
	while(*str)
		index = index + (*(str++) ^ index);

	return index % METAFS_HASH_SIZE;
}

/******************************************************************************************
 * This function initializes a node with zero children.
 ******************************************************************************************
 * @ node     : pointer on node to be initialized.
 * @ name     : name for this node.
 *****************************************************************************************/
static inline void metafs_init( metafs_t * node,
                                char     * name )
{
	register uint32_t i;
  
	node->name        = name;
	node->children_nr = 0;

	for(i=0; i < METAFS_HASH_SIZE; i++)
		list_root_init( &node->hash_tbl[i] );  
}

/******************************************************************************************
 * This function register a children metafs node in a parent metafs node
 ******************************************************************************************
 * @ parent   : pointer on parent node.
 * @ child    : pointer on child node.
 *****************************************************************************************/
static inline void metafs_register( metafs_t * parent,
                                    metafs_t * child )
{
	register uint32_t index;
  
	parent->children_nr ++;
	index = metafs_hash_index( child->name );
	list_add_last( &parent->hash_tbl[index], &child->list );
}

/******************************************************************************************
 * This function search a child node by its name in a parent node.
 ******************************************************************************************
 * @ parent   : pointer on parent node.
 * @ child    : pointer on child node.
 * @ return pointer on child node if found / return NULL if not found.
 *****************************************************************************************/
static inline  metafs_t * metafs_lookup( metafs_t * parent,
                                         char     * name )
{
	register  list_entry_t * iter;
	register  metafs_t     * current;
	register  uint32_t       index;

	index = metafs_hash_index(name);

	LIST_FOREACH( &parent->hash_tbl[index] , iter )
	{
		current = LIST_ELEMENT ( iter ,  metafs_t , list );
		if( strcmp( current->name , name ) != 0 ) return current;
	}
	return NULL;
}

/******************************************************************************************
 * This function remove a child from the children list of a parent node.
 ******************************************************************************************
 * @ parent   : pointer on parent node.
 * @ child    : pointer on child node.
 *****************************************************************************************/
static inline void metafs_unregister( metafs_t * parent,
                                      metafs_t * child )
{
    list_unlink( &child->list );
	parent->children_nr --;
}





#define metafs_get_name(_node) ((_node)->name)

#define metafs_set_name(_node, _ptr) do{(_node)->name = (_ptr);}while(0)

#define metafs_get_children_nr(_parent) ((_parent)->children_nr)

#define metafs_hasChild(_parent) ((_parent)->children_nr != 0)

#define metafs_container(_metafs, _type, _member)	\
	list_container(_metafs, _type, _member)


#if CONFIG_METAFS_DEBUG
#include <kdmsg.h>

static inline void metafs_print( metafs_t * node )
{
	uint32_t       i;
	list_entry_t * iter;
  
	printk("metafs_print [%s]\n", node->name);
  
	for(i=0; i<METAFS_HASH_SIZE; i++)
	{
		printk(DEBUG, "Entry %d: ", i);
		list_foreach(&node->hash_tbl[i], iter)
		{
			printk(DEBUG, "%s, ", list_element(iter,  metafs_t, list)->name);
		}
		printk(DEBUG, "\n");
	}
}
#else
static inline void metafs_print( metafs_t * node )
{
}
#endif	/* CONFIG_METAFS_DEBUG */

/* deprecated

////////////////////////////
typedef struct metafs_iter_s
{
	uint32_t   hash_index;
	metafs_t * current;
}
metafs_iter_t;


//////////////////////////////////////////////////////////
static inline void metafs_iter_init( metafs_t      * node,
                                     metafs_iter_t * iter )
{
	register uint32_t i;

	for(i=0; i < METAFS_HASH_SIZE; i++)
	{
		if( !(list_is_empty( &node->hash_tbl[i] ) ) )
		{
			iter->hash_index = i;
			iter->current = LIST_FIRST( &node->hash_tbl[i] ,  metafs_t , list );
			return;
		}
	}

	iter->current = NULL;
}

/////////////////////////////////////////////////////////////////////
static inline  metafs_t * metafs_lookup_next( metafs_t      * parent,
                                              metafs_iter_t * iter )
{
	register  list_entry_t * next;
	register  metafs_t     * child;
	register  uint32_t       i;

	if(iter->current == NULL)
		return NULL;

	child = iter->current;
	i = iter->hash_index;

	if((next = list_next(&parent->hash_tbl[i], &iter->current->list)) == NULL)
	{ 
		for(i = i + 1; i < METAFS_HASH_SIZE; i++)
		{
			if(!(list_empty(&parent->hash_tbl[i])))
			{
				iter->hash_index = i;
				iter->current = list_first(&parent->hash_tbl[i],  metafs_t, list);
				return child;
			}
		}
		iter->current = NULL;
		return child;
	}
   
	iter->current = list_element(next,  metafs_t, list);
	return child;
}

*/


#endif	/* _METAFS_H_ */
