/*
    This file is part of lorcon

    lorcon 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 2 of the License, or
    (at your option) any later version.

    lorcon 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 lorcon; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

    Copyright (c) 2005 dragorn and Joshua Wright
*/

/*
 * LORCON packet assembly system
 *
 * Relatively naive system for assembling packets from a list of components
 * which are then frozen into a uint8_t array for injection.
 *
 * Packet components may be named.  No enforcement of name duplication
 * is made.
 *
 * Basic manipulation functions are provided for assembling packet
 * content.
 *
 */

#ifndef __PACKET_ASSEMBLY_H__
#define __PACKET_ASSEMBLY_H__

#include <stdint.h>

/*
 * Basically a big linked list which gets frozen into a static
 * uint8_t for transmission.
 *
 * Functions are included for searching and replacing components, freezing
 * the list to a uint8, and freeing the structures
 *
 */

struct lcpa_metapack {
	/* Linked list */
	struct lcpa_metapack *prev;
	struct lcpa_metapack *next;

	/* String name for this packet component */
	char type[24];

	/* Length of the chunk */
	int len;

	/* Pointer to chunk of data */
	uint8_t *data;

	/* Do we free this data when we free the list, or is it controlled
	 * by the user application? */
	int freedata;
};
typedef struct lcpa_metapack lcpa_metapack_t;

/* Initialize a packet list */
struct lcpa_metapack *lcpa_init();

/* Append a copied data item to a list.  This copied data will be freed when
 * the list is freed, and the caller can destroy the original data in the meantime.
 * in_pack may be any component of the list, the new element will be appended
 * to the end of the list.
 *
 * The new component is returned.
 */
struct lcpa_metapack *lcpa_append_copy(struct lcpa_metapack *in_pack, 
                                       const char *in_type, 
									   int in_len, uint8_t *in_data);

/* Append a data item to a list.  This is NOT copied, will NOT be freed when
 * the list is freed, and the caller MUST NOT destroy the data until the list
 * is destroyed.
 * in_pack may be any component of the list, the new element will be appended
 * to the end of the list.
 *
 * The new component is returned.
 */
struct lcpa_metapack *lcpa_append(struct lcpa_metapack *in_pack, 
                                  const char *in_type,
								  int in_len, uint8_t *in_data);

/* Insert a component into the packet.  This copied data will be freed when the list
 * is freed, and the caller may destroy the original data at will.
 * in_pack may be any component of the list.  Data will be inserted after
 * the component and the remainder of the list will be shuffled to make
 * room.
 *
 * The new component is returned.
 */
struct lcpa_metapack *lcpa_insert_copy(struct lcpa_metapack *in_pack, 
                                       const char *in_type,
									   int in_len, uint8_t *in_data);

/* Insert a component into the packet.  This data is NOT copied and will NOT
 * be freed when the packet list is freed.  The caller MUST NOT destroy this data
 * until the list is freed.
 *
 * The component is added after the component provided in in_pack.
 *
 * The new component is returned.
 */
struct lcpa_metapack *lcpa_insert(struct lcpa_metapack *in_pack, 
                                  const char *in_type,
								  int in_len, uint8_t *in_data);

/* Find a component by name.  Can be used for iterative searching by passing
 * a non-head component as the start position
 *
 * If no value is found, NULL is returned
 */
struct lcpa_metapack *lcpa_find_name(struct lcpa_metapack *in_head, 
                                     const char *in_type);

/* Replace a component in the packet.  The data is copied and will be freed when the
 * packet list is freed.  If the packet being replaced contains copied data, it 
 * will be freed.
 *
 * All pointers to the component remain valid, however any pointers to the
 * component data must be treated as invalid if the original component data 
 * was copied.
 */
void lcpa_replace_copy(struct lcpa_metapack *in_pack, 
                       const char *in_type, 
					   int in_len, uint8_t *in_data);

/* Replace a component in the packet.  The data is NOT copied and will NOT be freed
 * when the packet list is freed.  The caller MUST NOT destroy the data before the
 * packet list is freed.
 *
 * All pointers to the component remain valid, however any pointers to the
 * component data bust me treated as invalid if the original component data
 * was copied
 */
void lcpa_replace(struct lcpa_metapack *in_pack, const char *in_type,
				  int in_len, uint8_t *in_data);

/* Free a metapacket list.  
 *
 * Any element of the list may be passed as in_head, however the entire list
 * will be removed.
 *
 * No element of the list (including in_head) will be valid and all external
 * reference to them must be treated as freed memory.
 *
 * For a list to be re-used after lcpa_free(), it must be initialized anew with
 * lcpa_init().
 */
void lcpa_free(struct lcpa_metapack *in_head);

/* Get the size of an assembled LCPA packet */
int lcpa_size(struct lcpa_metapack *in_head);

/* Freeze a LCPA fragment packet into a bytestream.  The caller is responsible
 * for providing a bytestream of sufficient length. */
void lcpa_freeze(struct lcpa_metapack *in_head, u_char *bytes);

#endif

