/* -------------------------------------------------------------------- */
/* SMS Client, send messages to mobile phones and pagers		*/
/*									*/
/* gs_parser.c								*/
/*									*/
/*  Copyright (C) 1997,1998 Angelo Masci				*/
/*									*/
/*  This library is free software; you can redistribute it and/or	*/
/*  modify it under the terms of the GNU Library General Public		*/
/*  License as published by the Free Software Foundation; either	*/
/*  version 2 of the License, or (at your option) any later version.	*/
/*									*/
/*  This library 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	*/
/*  Library General Public License for more details.			*/
/*									*/
/*  You should have received a copy of the GNU Library General Public	*/
/*  License along with this library; if not, write to the Free		*/
/*  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.	*/
/*									*/
/*  You can contact the author at this e-mail address:			*/
/*									*/
/*  angelo@styx.demon.co.uk						*/
/*									*/
/* -------------------------------------------------------------------- */
/* $Id$
   -------------------------------------------------------------------- */

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>

#include "common/common.h"
#include "logfile/logfile.h"
#include "gs_token.h"
#include "gs_parser.h"

#include "gs_private.h"


/* -------------------------------------------------------------------- */

static int parse_list(int fd, TOKEN_HEAP *heap);
static int parse_list_items(int fd, TOKEN_HEAP *heap, int depth);
static int parse_dictionary_items(int fd, TOKEN_HEAP *heap);

/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
int parse_dictionary(int fd, TOKEN_HEAP *heap)
{
	TOKEN_ID
		token_id;


	lprintf(LOG_VERYVERBOSE, "Entering parse_dictionary()\n");

	token_id = get_next_token(fd, heap);
	if (token_id == lcurly_tok)
	{
		if (parse_dictionary_items(fd, heap))
		{
			token_id = get_next_token(fd, heap);
			if (token_id == rcurly_tok)
			{	return TRUE;
			}
			else
			{	lprintf(LOG_ERROR, "Line %d Expecting '}'\n", gs_get_linenumber());
				return FALSE;
			}
		}
		else
		{	lprintf(LOG_ERROR, "Line %d Expecting Dictionary items\n", gs_get_linenumber());
			return FALSE;
		}		
	}
	else
	{
		lprintf(LOG_ERROR, "Line %d Expecting '{'\n", gs_get_linenumber());
		return FALSE;
	}

	return TRUE;
}


/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
static int parse_list(int fd, TOKEN_HEAP *heap)
{
	TOKEN_ID	
		token_id;


	lprintf(LOG_VERYVERBOSE, "Entering parse_list()\n");


	token_id = get_next_token(fd, heap);
	if (token_id == lparen_tok)
	{
		if (parse_list_items(fd, heap, 0))
		{
			token_id = get_next_token(fd, heap);
			if (token_id == rparen_tok)
			{	return TRUE;
			}
			else
			{	lprintf(LOG_ERROR, "Line %d Expecting ')'\n", gs_get_linenumber());
				return FALSE;
			}
		}
		else
		{	lprintf(LOG_ERROR, "Line %d Expecting List items\n", gs_get_linenumber());
			return FALSE;
		}		
	}
	else
	{
		lprintf(LOG_ERROR, "Line %d Expecting '('\n", gs_get_linenumber());
		return FALSE;
	}

	return TRUE;
}


/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
static int parse_list_items(int fd, TOKEN_HEAP *heap, int depth)
{
	TOKEN_ID	
		token_id,
		identifier;


	TOKEN_HEAP
		*dictionary,
		*list;

	long	value;

	char	buf[64],
		*string;



	lprintf(LOG_VERYVERBOSE, "Entering parse_list_items()\n");

	sms_snprintf(buf, 64, "[%d]", depth);
	identifier = add_token(heap, buf, T_IDENTIFIER, TP_NULL, NULL);
	if (identifier == NULL)
	{	return FALSE;
	}


	depth++;

	token_id = get_next_token(fd, heap);
	if (token_id == lcurly_tok)
	{
		dictionary = generate_new_heap();
		if (dictionary == NULL)
		{	lprintf(LOG_ERROR, "Allocating memory\n");
			return FALSE;
		}

		token_assign_dictionary(heap, identifier, dictionary);

		push_back_token(token_id);
		if (parse_dictionary(fd, dictionary))
		{	
			token_id = get_next_token(fd, heap);
			if (token_id == comma_tok)
			{	
				return parse_list_items(fd, heap, depth);
			}
			else
			{	push_back_token(token_id);
				return TRUE;
			}
		}
		else
		{	lprintf(LOG_ERROR, "Failed parsing Dictionary\n");
			return FALSE;
		}
	}
	else
	if (token_id == lparen_tok)
	{
		list = generate_new_heap();
		if (list == NULL)
		{	lprintf(LOG_ERROR, "Allocating memory\n");
			return FALSE;
		}
			
		token_assign_list(heap, identifier, list);

		push_back_token(token_id);
		if(parse_list(fd, list))
		{	
			token_id = get_next_token(fd, heap);
			if (token_id == comma_tok)
			{	
				return parse_list_items(fd, heap, depth);
			}
			else
			{	push_back_token(token_id);
				return TRUE;
			}
		}
		else
		{	lprintf(LOG_ERROR, "Failed parsing List\n");
			return FALSE;
		}
	}
	else
	if (get_token_type(heap, token_id) == T_STRING)
	{
		string = get_token_strvalue(heap, token_id);
		token_assign_strvalue(heap, identifier, string);

		token_id = get_next_token(fd, heap);
		if (token_id == comma_tok)
		{	
			return parse_list_items(fd, heap, depth);
		}
		else
		{	push_back_token(token_id);
			return TRUE;
		}
	}
	else
	if (get_token_type(heap, token_id) == T_NUMERIC)
	{
		string = get_token_strvalue(heap, token_id);
		value  = get_token_numvalue(heap, token_id);

		token_assign_strvalue(heap, identifier, string);
		token_assign_numvalue(heap, identifier, value);

		token_id = get_next_token(fd, heap);
		if (token_id == comma_tok)
		{	
			return parse_list_items(fd, heap, depth);
		}
		else
		{	push_back_token(token_id);
			return TRUE;
		}
	}
	else
	{
		lprintf(LOG_ERROR, "Line %d Expecting Identifier, Dictionary or List\n", gs_get_linenumber());
		return FALSE;
	}

	return TRUE; 
}


/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
static int parse_dictionary_items(int fd, TOKEN_HEAP *heap)
{
	TOKEN_ID	
		token_id,
		identifier;

	TOKEN_HEAP
		*dictionary,
		*list;

	char	*string;
	long	value;


	lprintf(LOG_VERYVERBOSE, "Entering parse_dictionary_items()\n");

	token_id = get_next_token(fd, heap);
	if (get_token_type(heap, token_id) == T_IDENTIFIER)
	{
		identifier = token_id;

		token_id = get_next_token(fd, heap);
		if (token_id == assignment_tok)
		{	
			token_id = get_next_token(fd, heap);
			if (token_id == lcurly_tok)
			{
				dictionary = generate_new_heap();
				if (dictionary == NULL)
				{	lprintf(LOG_ERROR, "Allocating memory\n");
					return FALSE;
				}

				token_assign_dictionary(heap, identifier, dictionary);

				push_back_token(token_id);
				if (parse_dictionary(fd, dictionary))
				{	
					token_id = get_next_token(fd, heap);
					if (token_id != rcurly_tok)
					{
						push_back_token(token_id);
						return parse_dictionary_items(fd, heap);
					}
					else
					{	push_back_token(token_id);
						return TRUE;
					}
				}
				else
				{	lprintf(LOG_ERROR, "Failed parsing Dictionary\n");
					return FALSE;
				}

			}
			else
			if (token_id == lparen_tok)
			{
				list = generate_new_heap();
				if (list == NULL)
				{	lprintf(LOG_ERROR, "Allocating memory\n");
					return FALSE;
				}
			
				token_assign_list(heap, identifier, list);

				push_back_token(token_id);
				if(parse_list(fd, list))
				{	
					token_id = get_next_token(fd, heap);
					if (token_id != rcurly_tok)
					{
						push_back_token(token_id);
						return parse_dictionary_items(fd, heap);
					}
					else
					{	push_back_token(token_id);
						return TRUE;
					}
				}
				else
				{	lprintf(LOG_ERROR, "Failed parsing List\n");
					return FALSE;
				}
			}
			else
			if (get_token_type(heap, token_id) == T_STRING)
			{
				string = get_token_strvalue(heap, token_id);
				token_assign_strvalue(heap, identifier, string);

				token_id = get_next_token(fd, heap);
				if (token_id != rcurly_tok)
				{
					push_back_token(token_id);
					return parse_dictionary_items(fd, heap);
				}
				else
				{	push_back_token(token_id);
					return TRUE;
				}
			}
			else
			if (get_token_type(heap, token_id) == T_NUMERIC)
			{
				string = get_token_strvalue(heap, token_id);
				value  = get_token_numvalue(heap, token_id);

				token_assign_strvalue(heap, identifier, string);
				token_assign_numvalue(heap, identifier, value);

				token_id = get_next_token(fd, heap);
				if (token_id != rcurly_tok)
				{
					push_back_token(token_id);
					return parse_dictionary_items(fd, heap);
				}
				else
				{	push_back_token(token_id);
					return TRUE;
				}
			}
			else
			{
				lprintf(LOG_ERROR, "Line %d Expecting Identifier, Dictionary or List\n", gs_get_linenumber());
				return FALSE;
			}
		}		
		else
		{
			lprintf(LOG_ERROR, "Line %d Expecting '='\n", gs_get_linenumber());
			return FALSE;
		}
	}
	else
	{
		lprintf(LOG_ERROR, "Line %d Expecting Identifier\n", gs_get_linenumber());
		return FALSE;
	}

	return TRUE;
}
