#ifndef FIFO_INCLUDE_H
#define FIFO_INCLUDE_H

#ifdef __cplusplus
extern "C" {
#endif

#include "iterator.h"

typedef struct FIFO_INFO FIFO_INFO;
typedef struct FIFO_ITER FIFO_ITER;
typedef struct FIFO FIFO;

struct FIFO_INFO {
	void *data;     
	FIFO_INFO *prev;    
	FIFO_INFO *next;
};

struct FIFO_ITER {
	FIFO_INFO *ptr;
};

struct FIFO {
	FIFO_INFO *head;
	FIFO_INFO *tail;
	int   cnt;

	/* Ӽ */

	/* βӶ̬ */
	void  (*push_back)(struct FIFO*, void*);
	/* ͷӶ̬ */
	void  (*push_front)(struct FIFO*, void*);
	/* β̬ */
	void *(*pop_back)(struct FIFO*);
	/* ͷ̬ */
	void *(*pop_front)(struct FIFO*);

	/* for iterator */

	/* ȡͷ */
	void *(*iter_head)(ITER*, struct FIFO*);
	/* ȡһ */
	void *(*iter_next)(ITER*, struct FIFO*);
	/* ȡβ */
	void *(*iter_tail)(ITER*, struct FIFO*);
	/* ȡһ */
	void *(*iter_prev)(ITER*, struct FIFO*);
	/* ȡĵǰԱṹ */
	FIFO_INFO *(*iter_info)(ITER*, struct FIFO*);
};

/**
 * ʼһУӦÿջϷУøúгʼ
 * @param fifo {FIFO *}
 * @example:
 *   void test(void) {
 	FIFO fifo;

	fifo_init(&fifo);
 *   }
 */
void fifo_init(FIFO *fifo);

/**
 * ڴзһж
 * @return {FIFO*}
 */
FIFO *fifo_new(void);

/**
 * ڴзһж󲢴ڴضΪ
 * @return {FIFO*}
 */
FIFO *fifo_new(void);

/**
 * ӶɾֵͬĶ
 * @param fifo {FIFO*}
 * @param data {const void*}
 */
int fifo_delete(FIFO *fifo, const void *data);
void fifo_delete_info(FIFO *fifo, FIFO_INFO *info);

/**
 * ͷԶѷĶж
 * @param fifo {FIFO*}
 * @param free_fn {void (*)(void*)}, úָ벻Ϊ
 *  ͷŶж̬Ķ
 */
void fifo_free(FIFO *fifo, void (*free_fn)(void *));
void fifo_free2(FIFO *fifo, void (*free_fn)(FIFO_INFO *));

/**
 * һ̬Ѷ
 * @param fifo {FIFO*}
 * @param data {void*} ̬
 * @return {FIFO_INFO*}  data ǿ򷵻ضеӶ, 򷵻 NULL
 */
FIFO_INFO *fifo_push_back(FIFO *fifo, void *data);
#define fifo_push	fifo_push_back
void fifo_push_info_back(FIFO *fifo, FIFO_INFO *info);
#define fifo_push_info	fifo_push_info_back
FIFO_INFO *fifo_push_front(FIFO *fifo, void *data);

/**
 * ӶȽȳʽһ̬, ͬʱöӶɾ
 * @param fifo {FIFO*}
 * @return {void*}, ΪգʾΪ
 */
void *fifo_pop_front(FIFO *fifo);
#define fifo_pop	fifo_pop_front
FIFO_INFO *fifo_pop_info(FIFO *fifo);

/**
 * ӶԺȳʽһ̬ ͬʱöӶɾ
 * @param fifo {FIFO*}
 * @return {void*}, ΪգʾΪ
 */
void *fifo_pop_back(FIFO *fifo);

/**
 * ضͷĶ̬
 * @param fifo {FIFO*}
 * @return {void*}, ΪգʾΪ
 */
void *fifo_head(FIFO *fifo);
FIFO_INFO *fifo_head_info(FIFO *fifo);

/**
 * ضβĶ̬
 * @param fifo {FIFO*}
 * @return {void*}, ΪգʾΪ
 */
void *fifo_tail(FIFO *fifo);
FIFO_INFO *fifo_tail_info(FIFO *fifo);

/**
 * ضж̬ܸ
 * @param fifo {FIFO*}
 * @return {int}, >= 0
 */
int fifo_size(FIFO *fifo);

#ifdef __cplusplus
}
#endif

#endif
