/*
    c99tree - parse tree output layer
    Copyright (C) 2010  Tibor Palinkas

    This program 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.

    This program 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 this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "tree.h"
#include "tree_print.h"
#include "c99tree.h"
#include "pathgrow.h"
#include "escaping.h"

int Nprint_ind(void **nprint_ctx, const char *prefix, const node_t *node, print_state_t state)
{
	char *tmp;
	int t;

	switch(state) {
		case PS_OPENING:
			tmp = escape(node->name);
			if (node->loc.twin_parent != NULL)
				t = node->loc.twin_parent->uid;
			else
				t = -1;
			printf("%s%s %s [%d:%d] (%s)\n", prefix, node_type_names[node->type], tmp, node->uid, t, loc_print(node));
			free(tmp);
			break;
		case PS_HEAD:
			printf("FILE  (%s)\n", loc_format);
			break;
		case PS_TAIL:
		case PS_CLOSING:
			break;
	}
	return 0;
}

int Nprint_xml(void **nprint_ctx, const char *prefix, const node_t *node, print_state_t state)
{
	char *loc_tmp;

	switch(state) {
		case PS_OPENING:
			printf("%s<%s", prefix, node_type_names[node->type]);
			if (node->name != NULL) {
				char *tmp;
				tmp = escape_xml(node->name);
				printf(" name=\"%s\"", tmp);
				free(tmp);
			}

			loc_tmp = escape_xml(loc_print(node));
			printf(" location=\"%s\"", loc_tmp);
			free(loc_tmp);

			printf(" uid=\"%d\"", node->uid);
			if (node->loc.twin_parent != NULL)
				printf(" twin_parent=\"%d\"", node->loc.twin_parent->uid);

			if ((node->children == NULL) && (!format_long))
				printf("/");
			printf(">\n");
		break;
		case PS_CLOSING:
			if ((node->children != NULL) || (format_long))
				printf("%s</%s>\n", prefix, node_type_names[node->type]);
			break;
		case PS_HEAD:
			printf("<?xml version=\"1.0\" ?>\n");
			printf("<FILE location_format=\"%s\">\n", escape_xml(loc_format));
			break;
		case PS_TAIL:
			printf("</FILE>\n");
			break;
	}
	return 0;
}

int Nprint_plist(void **nprint_ctx, const char *prefix, const node_t *node, print_state_t state)
{
	switch(state) {
		case PS_OPENING:
			printf("%s%s = {\n", prefix, node_type_names[node->type]);
			if (node->name != NULL) {
				char *tmp;
				tmp = escape(node->name);
				printf("%s name = \"%s\";\n", prefix, tmp);
				free(tmp);
			}
			printf("%s location = \"%s\";\n", prefix, loc_print(node));

			printf("%s uid = \"%d\";\n", prefix, node->uid);
			if (node->loc.twin_parent != NULL)
				printf("%s twin_parent = \"%d\";\n", prefix, node->loc.twin_parent->uid);

			break;
		case PS_CLOSING:
			printf("%s};\n", prefix);
			break;
		case PS_HEAD:
			printf("FILE = {\n");
			printf(" globals = {\n");
			printf("  location_format = \"%s\";\n", escape(loc_format));
			printf(" };\n");
			break;
		case PS_TAIL:
			printf("};\n");
			break;

	}
	return 0;
}

int Nprint_json(void **nprint_ctx, const char *prefix, const node_t *node, print_state_t state)
{
	switch(state) {
		case PS_OPENING:
			printf("%s{ \"type\": \"%s\", ", prefix, node_type_names[node->type]);
			if (node->name != NULL) {
				char *tmp;
				tmp = escape(node->name);
				printf("\"name\": \"%s\", ", tmp);
				free(tmp);
			}
			printf("\"uid\": \"%d\", ", node->uid);
			if (node->loc.twin_parent != NULL)
				printf("\"twin_parent\": \"%d\", ", node->loc.twin_parent->uid);

			printf("\"location\": \"%s\"%s ", loc_print(node), (node->children ? "," : ""));
		
			if (node->children)
				printf("\"children\": [\n");
			else
				printf("}%s\n", (node->next ? "," : ""));
			break;

		case PS_CLOSING:
			if (node->children)
				printf("%s]}%s\n", prefix, (node->next ? "," : ""));
			break;

		case PS_HEAD:
			printf("%s[\n", prefix);
			break;

		case PS_TAIL:
			printf("%s]\n", prefix);
			break;
	}
	return 0;
}

int Nprint_perl(void **nprint_ctx, const char *prefix, const node_t *node, print_state_t state)
{
	switch(state) {
		case PS_OPENING:
			printf("%s{ \"type\" => \"%s\", ", prefix, node_type_names[node->type]);
			if (node->name != NULL) {
				char *tmp;
				tmp = escape(node->name);
				printf("\"name\" => \"%s\", ", tmp);
				free(tmp);
			}

			printf("\"uid\" => \"%d\", ", node->uid);
			if (node->loc.twin_parent != NULL)
				printf("\"twin_parent\" => \"%d\", ", node->loc.twin_parent->uid);

			printf("\"location\" => \"%s\"%s ", loc_print(node), (node->children ? "," : ""));
			if (node->children)
				printf("\"children\" => [\n");
			else
				printf("}%s\n", (node->next ? "," : ""));
			break;

		case PS_CLOSING:
			if (node->children)
				printf("%s]}%s\n", prefix, (node->next ? "," : ""));
			break;

		case PS_HEAD:
			printf("%s[\n", prefix);
			break;

		case PS_TAIL:
			printf("%s]\n", prefix);
			break;
	}
	return 0;
}

int Nprint_web3(void **nprint_ctx, const char *prefix, const node_t *node, print_state_t state)
{
	static pathgrow_t *tpath, *ipath;
	static int uid;
	char uids[64];

	switch(state) {
		case PS_HEAD:
			uid = 0;
			tpath = pathgrow_alloc('/');
			ipath = pathgrow_alloc('/');
			printf("|ID=0|TAG=globals|TPATH=/globals|IPATH=/globals|location_format=%s\n", loc_format);
			break;
		case PS_OPENING:
			uid++;
			sprintf(uids, "%d", uid);
			pathgrow_append(tpath, node_type_names[node->type]);
			pathgrow_append(ipath, uids);
			printf("|ID=%d|TAG=%s|TPATH=%s|IPATH=%s|", uid, node_type_names[node->type], tpath->path, ipath->path);
			if (node->name != NULL) {
				char *tmp;
				tmp = escape(node->name);
				printf("name=%s|", tmp);
				free(tmp);
			}

			printf("uid=%d|", node->uid);
			if (node->loc.twin_parent != NULL)
				printf("twin_parent=%d|", node->loc.twin_parent->uid);

			printf("loc=%s|loc_file=%s|loc_line=%d|\n", loc_print(node), filename, node->loc.sline);
			break;
		case PS_CLOSING:
			pathgrow_truncate(tpath);
			pathgrow_truncate(ipath);
			break;
		case PS_TAIL:
			pathgrow_free(tpath);
			pathgrow_free(ipath);
			break;
	}
	return 0;
}

int format_long = 0;
int (*Nprint_cb)(void **nprint_ctx, const char *prefix, const node_t *node, print_state_t state) = Nprint_ind;
