#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <syslog.h>

#include "pldstr.h"
#include "boundary-stack.h"

#define _SL 1

#define BS_STRLEN_MAX 1024

struct BS_globals {
	int debug;
	int verbose;
	int syslogging;
	int errlogging;
};

struct BS_node {
	char *boundary;
	struct BS_node *next;
};

static struct BS_node *boundarystack = NULL;

static struct BS_globals glb;

char boundarystacksafe[BS_STRLEN_MAX];




int BS_init( void )
{
	glb.debug = 0;
	glb.verbose = 0;
	glb.syslogging = 1;
	glb.errlogging = 0;

	return 0;
}

int BS_set_verbose( int level )
{
	glb.verbose = level;

	return glb.verbose;
}

int BS_set_debug( int level )
{
	glb.debug = level;

	return glb.debug;
}


/*------------------------------------------------------------------------
Procedure:     BS_clear ID:1
Purpose:       Pops all items off the stack and free's the memory
Input:         none
Output:
Errors:
------------------------------------------------------------------------*/
int BS_clear( void )
{
	struct BS_node *next;

	while (boundarystack)
	{
		next = boundarystack->next;
		free(boundarystack->boundary);
		free(boundarystack);
		boundarystack = next;
	}

	return 0;
}



/*----------------------------------------------------------
* BS_push()
*
 * Push a boundary onto the stack */
int BS_push( char *boundary )
{

	struct BS_node *node = malloc(sizeof(struct BS_node));


	if (node)
	{
		node->next = boundarystack;
		boundarystack = node;
		boundarystack->boundary = strdup(boundary);
	}
	else
	    {
		if (glb.syslogging > 0) syslog(_SL,"BS_push(): Cannot allocate memory for PUSH(), %s",strerror(errno));
	}

	return 0;
}


/*----------------------------------------------------------
* BS_pop()
*
 * pop's the top boundar off */
char *BS_pop( void )
{

	struct BS_node *node = boundarystack;

	if (boundarystack)
	{
		boundarystack = boundarystack->next;
		PLD_strncpy(boundarystacksafe,node->boundary, BS_STRLEN_MAX);
		free(node->boundary);
		free(node);
	}

	return boundarystacksafe;
}

/*----------------------------------------------------------
* BS_top()
*
 * returns the top item in the stack, without popping off */
char *BS_top( void )
{

	if (boundarystack)
	{
		return boundarystack->boundary;
	}
	else return NULL;
}

/*----------------------------------------------------------
* BS_cmp()
*
 */
int BS_cmp( char *boundary, int len )
{

	char *top, *spot;
	char testspace[1024];
	int testspacelen=1023;
	int spin=1;
	struct BS_node *node=boundarystack;
	struct BS_node *nodetmp=NULL, *nodedel=NULL;

	if (!boundary) return 0;

	if (len > testspacelen) len = testspacelen;

	snprintf(testspace, testspacelen, "%s", boundary);

	// First, search through the stack looking for a boundary that matches
	// our search criterion
	//
	// When we do find one, we will jump out of this WHILE loop by setting
	// 'spin' to 0.

	while((node)&&(spin))
	{
		top = node->boundary;
		spot = strstr(testspace,top);
		if (spot) spin = 0;
		else node = node->next;
	}

	// If we have a hit on the matching, then, according
	// to nested MIME rules, we must "remove" any previous
	// boundaries
	//
	// We know that we had a HIT in matching if spin == 0, because
	// in our previous code block that's what we set spin to if
	// we find a match

	if (spin == 0)
	{

		// If our "HIT" node is /NOT/ the one on the top of the
		// stack, then we need to pop off and deallocate the nodes
		// PRIOR/Above the hit node.
		//
		// ie, if "NODE" is not the top, then pop off until we
		// do get to the node

		if (node != boundarystack)
		{
			nodetmp = boundarystack;
			while ((nodetmp)&&(nodetmp != node))
			{
				// - Set the node to delete (nodedel) to the current temp
				// node (notetmp)
				// - Increment the nodetmp to the next node in the stack
				// - Free the node to delete (nodedel)

				nodedel = nodetmp;
				nodetmp = nodetmp->next;
				free(nodedel);
			}
			boundarystack = node;
		}
		return 1;

	}
	else return 0;
}



