/* SPDX-License-Identifier: BSD-3-Clause
 * Copyright 2016, Olivier MATZ <zer0@droids-corp.org>
 */

/**
 * @defgroup ecoli_node_subset Subset node
 * @ingroup ecoli_nodes
 * @{
 *
 * @brief A node that matches any subset of its children in any order.
 */

#pragma once

#include <ecoli/node.h>

/**
 * Create a subset node from a list of child nodes.
 *
 * A subset node matches any permutation of a subset of its children.
 * All child nodes passed as arguments are consumed and will be freed
 * when the subset node is freed, or immediately on error.
 *
 * Example:
 *
 * @code{.c}
 * EC_NODE_SUBSET("mysubset", child1, child2, child3)
 * @endcode
 */
#define EC_NODE_SUBSET(args...) __ec_node_subset(args, EC_VA_END)

/* list must be terminated with EC_VA_END */
/* all nodes given in the list will be freed when freeing this one */
/* avoid using this function directly, prefer the macro EC_NODE_SUBSET() or
 * ec_node_subset() + ec_node_subset_add() */
struct ec_node *__ec_node_subset(const char *id, ...);

/**
 * Create an empty subset node.
 *
 * Use ec_node_subset_add() to add children.
 *
 * @param id
 *   The node identifier.
 * @return
 *   The node, or NULL on error (errno is set).
 */
struct ec_node *ec_node_subset(const char *id);

/**
 * Create an empty subset node with a minimum number of children that must match.
 *
 * Use ec_node_subset_add() to add children.
 *
 * @param id
 *   The node identifier.
 * @param min
 *   The minimum number of children that must match.
 * @return
 *   The node, or NULL on error (errno is set).
 */
struct ec_node *ec_node_subset_min(const char *id, unsigned int min);

/**
 * Add a child to a subset node.
 *
 * @param node
 *   The subset node.
 * @param child
 *   The child node to add. It is consumed and will be freed when the
 *   parent is freed, or immediately on error.
 * @return
 *   0 on success, -1 on error (errno is set).
 */
int ec_node_subset_add(struct ec_node *node, struct ec_node *child);

/**
 * Set the minimum number of children that must match.
 *
 * By default, a subset node accepts zero matching children. Use this
 * function to require a minimum number of children to match for the
 * parse to succeed.
 *
 * @param node
 *   The subset node.
 * @param min
 *   The minimum number of children that must match.
 * @return
 *   0 on success, -1 on error (errno is set).
 */
int ec_node_subset_set_min(struct ec_node *node, unsigned int min);

/**
 * Get the minimum number of children that must match.
 *
 * @param node
 *   The subset node.
 * @return
 *   The minimum number, or 0 if the node is not a subset.
 */
unsigned int ec_node_subset_get_min(const struct ec_node *node);

/** @} */
