/**
 * @file dep_list.h
 * @brief Utlity functions for dependency lists 
 *
 * Dependency lists and small general functions
 *
 * @copyright Copyright  (C)  2013 Moritz Hanke <hanke@dkrz.de>
 *                                 Thomas Jahns <jahns@dkrz.de>
 *
 * @version 1.0
 * @author Moritz Hanke <hanke@dkrz.de>
 *         Thomas Jahns <jahns@dkrz.de>
 */
/*
 * Keywords:
 * Maintainer: Moritz Hanke <hanke@dkrz.de>
 *             Thomas Jahns <jahns@dkrz.de>
 * URL: https://doc.redmine.dkrz.de/YAC/html/index.html
 *
 * This file is part of YAC.
 *
 * YAC 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, either version 3 of the License, or
 * (at your option) any later version.
 *
 * YAC 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 YAC.  If not, see <http://www.gnu.org/licenses/gpl.txt>.
 */

#ifndef DEP_LIST_H
#define DEP_LIST_H

#include <stdlib.h>

// forward declaration
struct communicator;

/** \example test_dep_list.c
 * This contains examples on how to use struct dep_list.
 */

/**
 * allocates and initialises a new dependency list
 * @param[in] num_elements         number of elements in the dependency list
 * @param[in] num_deps_per_element array of size num_elements that contains for
 *                                 each element the number of associated
 *                                 dependencies
 * @param[in] dependencies         array that contains all dependencies, entries
 *                                 0 to num_deps_per_element[0]-1 contain
 *                                 dependencies for element 0, entries
 *                                 num_deps_per_element[0] to
 *                                 num_deps_per_element[0]+num_deps_per_element[1]-1
 *                                 contain the dependencies for element 1, etc.
 * @return list dependency list
 * @remark This routine makes no copy of the array passed to it. The array are
 *         assumed to be on the heap and will be freed by a call to
 *         \ref yac_dep_list_delete.
 */
struct dep_list * yac_dep_list_new(size_t num_elements,
                                   size_t * num_deps_per_element,
                                   unsigned * dependencies);

/**
 * gets number of elements of a given element dependency list
 * @param[in] list dependency list
 * @return number of elements in list
 */
size_t yac_get_num_elements(struct dep_list * list);

/**
 * adds dependencies to an existing dependency list
 * @param[in,out] list dependency list to be edited
 * @param[in] element element of the list to be changed
 * @param[in] num_dependencies number of dependencies to be added
 * @param[in] dependencies array containing the dependencies, which are supposed to be added to the list
 */
void yac_add_dependencies (struct dep_list * list, unsigned element,
                           size_t num_dependencies, unsigned * dependencies);

/**
 * gets number of dependencies for a given element
 * @param[in] list dependency list
 * @param[in] index element index
 * @return number of dependencies for the given element index
 */
size_t yac_get_num_dependencies_of_element (
  struct dep_list * list, size_t index);

/**
 * gets all dependencies for a given element
 * @param[in] list dependency list
 * @param[in] index element index
 * @return pointer to a constant array containing the dependencies for the given element index
 *
 * \remark the number of dependencies for the respective element can be retrieved from list.num_deps_per_element[index]
 */
unsigned const * yac_get_dependencies_of_element (struct dep_list * list, size_t index);

/**
 * gets the total number of dependencies stored in the given list
 * @param[in] list dependency list
 * @return total number of dependencies in list
 */
size_t yac_get_total_num_dependencies(struct dep_list * list);

/**
 * gets the position of a dependency for a given element in the dep_list::dependencies array
 * @param[in] list dependency list
 * @param[in] index element index
 * @param[in] dependency dependency of provided element
 * @return position of dependency in dep_list::dependencies array \n -1 in case index and/or dependency is invalid
 */
size_t yac_get_dependency_index(struct dep_list * list, size_t index, unsigned dependency);

/**
 * gets the position of the first dependency of an element in the dep_list::dependencies array
 * @param[in] list dependency list
 * @param[in] index element index
 * @return position of the first dependency of an element in the dep_list::dependencies array
 */
size_t yac_get_dependency_offset(struct dep_list * list, size_t index);

/**
 * search for a given dependency in a dependency list
 * @param[in] list dependency list
 * @param[in] dependency dependency that is to be searched for
 * @return 0 if the list does not contain the respective dependency
 */
int yac_list_contains_dependency(struct dep_list * list, unsigned dependency);

/**
 * gets the element and dependency associated to a given position in the dep_list::dependencies array
 * @param[in] list dependency list
 * @param[in] dep_index position in dep_list::dependencies
 * @param[out] index element index associated to dep_index
 * @param[out] dependency dependency associated to dep_index
 */
void yac_get_dependency(struct dep_list * list, size_t dep_index,
                        size_t * index, unsigned * dependency);

/**
 * generates an inverted dependency list
 * @param[in] list dependency list that is to be inverted
 * @return inverted version of list
 */
struct dep_list * yac_invert_dep_list(struct dep_list * list);

/**
 * removes all dependencies of the provided elements
 * @param[in,out] dep dependency list
 * @param[in] element_indices array with all element indices for which the dependencies have to be removed from dep
 * @param[in] num_elements number of indices in element_indices array
 * \remark element indices == -1 are being ignored
 */
void yac_remove_dependencies_of_elements(
  struct dep_list * dep, size_t * element_indices, size_t num_elements);

/**
 * removes all given dependencies
 * @param[in,out] dep dependency list
 * @param[in] dependencies array containing the dependencies that have to be removed
 * @param[in] num_dependencies number of dependencies in dependencies array
 * \remark dependencies == -1 are being ignored
 */
void yac_remove_dependencies(
  struct dep_list * dep, unsigned * dependencies, size_t num_dependencies);

/**
 * makes a copy of a dependency list
 * @param[in] list source dependency list
 * @return copy of provided dependency list
 */
struct dep_list * yac_copy_dep_list(struct dep_list * list);

/**
 * packs a dependency list into a buffer that can be sent to other processes via the MPI library for example
 * @param[in]     list        dependency list to be packed
 * @param[in,out] buffer      pointer to buffer into which the dependency list will be packed
 * @param[in,out] buffer_size size of the pack buffer
 * @param[in,out] position    current write position in the buffer
 * @param[in]     comm
 * @see \ref yac_dep_list_pack_size
 * @see \ref yac_unpack_dep_list
 * \remark the size of the buffer provided must be sufficiently large to hold
 *         the packed dependency list
 */
void yac_pack_dep_list(struct dep_list * list, void * buffer, int buffer_size,
                       int * position, struct communicator * comm);
/**
 * unpacks a packed dependency list
 * @param[in]     buffer      unpack buffer
 * @param[in]     buffer_size size of unpack buffer
 * @param[in,out] position    current read position in the buffer
 * @param[in]     comm
 * @return dependency list
 * @see \ref yac_pack_dep_list
 */
struct dep_list * yac_unpack_dep_list(void * buffer, int buffer_size,
                                      int * position, struct communicator * comm);

/**
 * computes the number of bytes required in a pack buffer by
 * \ref yac_pack_dep_list to pack the provided dependency list
 * @param[in] list dependency list
 * @param[in] comm
 * @return number of bytes required for packing
 * @see \ref yac_pack_dep_list
 */
int yac_dep_list_pack_size(struct dep_list * list, struct communicator * comm);

/**
 * deletes a dependency list
 * @param[in,out] list dependency list to be deleted
 */
void yac_dep_list_delete(struct dep_list * list);

#endif // DEP_LIST_H

