/*

libusearch - microlib for searching/graph traversal

Copyright (c) 2020 Tibor 'Igor2' Palinkas
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
   notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
   notice, this list of conditions and the following disclaimer in the
   documentation and/or other materials provided with the distribution.
3. Neither the name of the Author nor the names of contributors
   may be used to endorse or promote products derived from this software
   without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.

Source code: svn://svn.repo.hu/libusearch/trunk
Contact the author: http://igor2.repo.hu/contact.html

*/

#ifndef LIBUSEARCH_A_STAR_API_H
#define LIBUSEARCH_A_STAR_API_H

#include <stddef.h>
#include <stdlib.h>
#include <limits.h>
#include <genprique/fibheap.h>
#include <libusearch/common.h>

typedef struct usrch_a_star_s usrch_a_star_t;
typedef struct usrch_a_star_node_s usrch_a_star_node_t;


struct usrch_a_star_s {
	/* user provided callbacks */
	void *(*malloc)(usrch_a_star_t *ctx, long size);                     /* NULL to use stdlib malloc() */
	void *(*free)(usrch_a_star_t *ctx, void *ptr);                       /* NULL to use stdlib free() */

	long (*heuristic)(usrch_a_star_t *ctx, void *node);                  /* expected cost from node to finish (cost between node -> target) */
	long (*cost)(usrch_a_star_t *ctx, void *from, void *to);             /* actual cost between nodes from -> to */

	void *(*neighbor_pre)(usrch_a_star_t *ctx, void *curr);              /* prepare for listing neighbors; returns nctx; if NULL, nctx is initialized to NULL */
	void *(*neighbor)(usrch_a_star_t *ctx, void *curr, void *nctx);      /* return the next neighbor of curr or NULL if there are no more; nctx is neighbor iteration context used by the callee */
	void (*neighbor_post)(usrch_a_star_t *ctx, void *curr, void *nctx);  /* finished listing neighbors; may be NULL */

	int (*is_target)(usrch_a_star_t *ctx, void *curr);                   /* optional: when not NULL, this function is used to check if curr is target (instead of a simple comparison on pointer). Useful when there are multiple targets */

	void (*set_mark)(usrch_a_star_t *ctx, void *node, usrch_a_star_node_t *mark); /* store mark in node so a get_mark() call can return it later */
	usrch_a_star_node_t *(*get_mark)(usrch_a_star_t *ctx, void *node);            /* returns the mark set by set_mark() or NULL if there was no previous set_mark() */

	void *user_data;   /* the caller is free to use this field */

	/* internal, private data; init to all zero */
	fbh_t open;
	void *target;              /* user_node we are trying to reach */
	usrch_a_star_node_t *all;  /* all allocated nodes (so they can be free'd) */
	usrch_a_star_node_t *last; /* when a path is found: last node before target */
} ;


/* Blocking call: initialize and iterate until a path is found or until no
   path is possible. The former returns USRCH_RES_FOUND, the latter returns
   USRCH_RES_ERROR. */
USRCH_INLINE usrch_res_t usrch_a_star_search(usrch_a_star_t *ctx, void *start_node, void *target_node);

/* Non-blocking calls: initialize the search by calling start() then keep
   calling iter() as long as it is returning USRCH_RES_CONTINUE. A caller
   implemented loop gives the caller a chance to stop the search after
   some timeout or to poll/do other tasks as well in a single thread. */
USRCH_INLINE usrch_res_t usrch_a_star_start(usrch_a_star_t *ctx, void *start_node);
USRCH_INLINE usrch_res_t usrch_a_star_start_arr(usrch_a_star_t *ctx, void **start_nodes, int len);
USRCH_INLINE usrch_res_t usrch_a_star_iter(usrch_a_star_t *ctx);


/* Once the search returns USRCH_RES_FOUND, the path can be reconstructed
   by starting an loop with first() and call next() until it returns NULL.
   The path will be returned from backward, from target to start. */
USRCH_INLINE void *usrch_a_star_path_first(usrch_a_star_t *ctx, usrch_a_star_node_t **it);
USRCH_INLINE void *usrch_a_star_path_next(usrch_a_star_t *ctx, usrch_a_star_node_t **it);

/* Start an iteration back from a given user node (reverse track of the
   currently known best path from user node to start) */
USRCH_INLINE void *usrch_a_star_path_first_from(usrch_a_star_t *ctx, void *user_node, usrch_a_star_node_t **it);


/* Call this at the end to set_mark() NULL on all nodes and free all memory */
USRCH_INLINE void usrch_a_star_uninit(usrch_a_star_t *ctx);

#endif
