/*
 * Copyright (c) 2000 Silicon Graphics, Inc.  All Rights Reserved.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of version 2 of the GNU General Public License as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it would be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *
 * Further, this software is distributed without any warranty that it is
 * free of the rightful claim of any third person regarding infringement
 * or the like.  Any license provided herein, whether implied or
 * otherwise, applies only to this software file.  Patent licenses, if
 * any, provided herein do not apply to combinations of this program with
 * other software, or any other product whatsoever.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
 * Mountain View, CA  94043, or:
 *
 * http://www.sgi.com
 *
 * For further information regarding this notice, see:
 *
 * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
 *
 */
/* $Id: reporter.c,v 1.1 2000/09/21 21:35:06 alaffin Exp $ */
/*
 * This is the report generator half of the scanner program.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "reporter.h"
#include "symbol.h"
#include "tag_report.h"
#include "splitstr.h"

/************************************************************************
 *                      Report Generation                               *
 ************************************************************************/

static int scanner_reporter(SYM);
static int iscanner_reporter(SYM);
static int scanner_test_end(SYM, SYM, SYM);
static int iscanner_test_end(SYM, SYM, SYM);

static int (*reporter_func) (SYM) = scanner_reporter;
static int (*test_end_func) (SYM, SYM, SYM) = scanner_test_end;

/*
 * Do the report generation.
 *
 * A problem: I really need multiple cursors.  I'd rather not look into
 * the depths of the current symbol table implimentation (there are the
 * cursors there that I could use) so that a different (faster!) symbol
 * table can be used in the future.
 *
 * I could get a key (tag), get it's sub-keys (TCIDs), then get the key
 * again to reset to the top level, _then_ get the next key.  That would
 * be very inefficient.
 *
 * The solution I chose is to extract all tags into a list (char array),
 * then go thru that list with the cursor free for other levels to use.
 *
 *  (1) make a list (2d char array) of all Tags
 *  (2) search for the first tag that has a "stime" record, and use that as
 *      the date (MMDDYY) that the tests were run.
 *  (3) print the report header
 *  (4) go thru all tags and report each as described at the beginning of
 *      this file
 */
static int scanner_reporter(tags)
SYM tags;
{
	DBT Key, Data;
	SYM Tag, Keys;

	time_t clock;
	struct tm *tm;

	/* a list of tags, a count of the number of tags allocated to the list,
	   and a pointer to go thru the list */
	char **taglist, **tl;
	int ntags;
	int tagcount;		/* how many tags used */

	char key_get[KEYSIZE];
	char *info;

	/*
	 * extract tag names from data
	 */
	ntags = NTAGS_START;
	taglist = (char **)malloc(sizeof(char *) * ntags);
	tagcount = 0;

	tl = taglist;
	sym_seq(tags, &Key, &Data, R_FIRST);
	do {
		if (tagcount == ntags) {
			/* exceeded tag array size -- realloc */
			ntags += NTAGS_START;
			taglist =
			    (char **)realloc(taglist, sizeof(char *) * ntags);
			tl = taglist + tagcount;
		}

		*tl++ = Key.data;
		tagcount++;
	} while (sym_seq(tags, &Key, &Data, R_NEXT) == 0);

	if (tagcount == ntags) {
		/* exceeded tag array size -- realloc */
		ntags += NTAGS_START;
		taglist = (char **)realloc(taglist, sizeof(char *) * ntags);
		tl = taglist + tagcount;
	}

	*tl++ = NULL;
	ntags = tagcount;
	/* Retrieve one "stime" to get the date. */
	for (tl = taglist; *tl != NULL; tl++) {
		strcpy(key_get, *tl);
		strcat(key_get, ",_keys,stime");
		if ((info = (char *)sym_get(tags, key_get)) != NULL) {
			clock = atoi(info);
			tm = gmtime(&clock);
			strftime(key_get, KEYSIZE, "%x", tm);
			sym_put(tags, strdup("_RTS,date"), strdup(key_get), 0);
			break;
		}
	}

	print_header(tags);

	/*
	 * The way that I am using 'Keys' and 'Tag' makes assumptions about the
	 * internals of the sym_* data structure.
	 */
	/* dump 'em all */
	for (tl = taglist; *tl != NULL; tl++) {
		if (!strcmp(*tl, "_RTS"))
			continue;

		strcpy(key_get, *tl);
		strcat(key_get, ",_keys");
		if ((Keys = sym_get(tags, key_get)) == NULL) {
			return 0;
		}

		strcpy(key_get, *tl);
		if ((Tag = sym_get(tags, key_get)) != NULL) {
			tag_report(NULL, Tag, Keys);
		}
	}
	free(taglist);

	return 0;
}

/*
 * End-Of-Test seen, insert this tag into the global tag data.
 * (1) Get the test's tag
 * (2) insert the keywords in the "_keys" tag
 * (3) insert it into the global data under this tag, replacing any existing
 *      data.
 *
 * a "feature" of the key implimentation: I can insert a key tree
 * under another key tree with almost zero brainwork because a SYM
 * is what the DATA area points to.
 */
static int scanner_test_end(alltags, ctag, keys)
SYM alltags, ctag, keys;
{
	static int notag = 0;	/* counter for records with no tag (error) */
	char tagname[KEYSIZE];	/* used when creating name (see above) */
	char *tag;		/* tag name to look things up in */
	char *status;		/* initiation status of old tag */
	SYM rm;			/* pointer to old tag -- to remove it */

	if (alltags == NULL || keys == NULL || ctag == NULL)
		return -1;	/* for really messed up test output */

	/* insert keys into tag */
	sym_put(ctag, "_keys", (void *)keys, 0);

	/* get the tag, or build a new one */
	if ((tag = (char *)sym_get(keys, "tag")) == NULL) {
		/* this is an "impossible" situation: test_output checks for this
		 * and creates a dummy tag. */
		sprintf(tagname, "no_tag_%d", notag++);
		fprintf(stderr, "No TAG key!  Using %s\n", tagname);
		sym_put(keys, "tag", strdup(tagname), 0);
		tag = strdup(tagname);
	}

	/*
	 * Special case: duplicate tag that has an initiation_status failure
	 * is thrown away.
	 */
	if ((rm = (SYM) sym_get(alltags, tag)) != NULL) {
		if ((status =
		     (char *)sym_get(keys, "initiation_status")) != NULL) {
			if (strcmp(status, "ok")) {
				/* do not take new data.  remove new data */
				sym_rm(ctag, RM_KEY | RM_DATA);
				return 1;
			} else {
				/* remove old data in alltags */
				sym_rm(rm, RM_KEY | RM_DATA);
			}
		} else {
			/* new data does not have an initiation_status -- throw it away */
			sym_rm(ctag, RM_KEY | RM_DATA);
			return 1;
		}
	}

	/* put new data.. replaces existing "tag" key if it exists
	 * (it's data should have been removed above) */
	sym_put(alltags, tag, ctag, PUT_REPLACE);

	return 0;
}

static int iscanner_reporter(tags)
SYM tags;
{
	return 0;
}

static int iscanner_test_end(alltags, ctag, keys)
SYM alltags, ctag, keys;
{
	if (alltags == NULL || keys == NULL || ctag == NULL)
		return -1;	/* for really messed up test output */

	/* insert keys into tag */
	sym_put(ctag, "_keys", (void *)keys, 0);

	return tag_report(alltags, ctag, keys);
}

int reporter(SYM s)
{
	return reporter_func(s);
}

int test_end(SYM a, SYM b, SYM c)
{
	return test_end_func(a, b, c);
}

void set_scanner(void)
{
	reporter_func = scanner_reporter;
	test_end_func = scanner_test_end;
}

void set_iscanner(void)
{
	reporter_func = iscanner_reporter;
	test_end_func = iscanner_test_end;
}
