/*
 *
 * Copyright (C) 1987 	Pehong Chen	(phc@renoir.berkeley.edu)
 * Computer Science Division
 * University of California, Berkeley
 *
 */

#include		"mkind.h"
#include		"genind.h"

static	FIELD_PTR	curr = NULL;
static	FIELD_PTR	prev = NULL;
static	FIELD_PTR	begin = NULL;
static	FIELD_PTR	end = NULL;
static	FIELD_PTR	range_ptr;
static	int		level = 0;
static	int		prev_level = 0;
static	char		*encap = NULL;
static	char		*prev_encap = NULL;
static	int		in_range = FALSE;
static	int		encap_range = FALSE;
static	int		range_lc;
static	char		buff[2*LINE_MAX];
static	char		line[2*LINE_MAX];	/* output buffer */
static	int		ind_lc = 0;		/* overall line count */
static	int		ind_ec = 0;		/* erroneous line count */
static	int		ind_indent;


void
gen_ind()
{
	int		n;
	int		tmp_lc;

	MESSAGE("Generating output file %s...", ind_fn);
	PUT(preamble);
	ind_lc += prelen;
	if (init_page)
		insert_page();

	/* reset counters for putting out dots */
	idx_dc = 0;
	for (n = 0; n < idx_gt; n++) {
		if (idx_key[n]->type != DUPLICATE)
			if (make_entry(n)) {
				IDX_DOT(DOT_MAX);
			}
	}

	tmp_lc = ind_lc;
	if (in_range) {
		curr = range_ptr;
		IND_ERROR("Unmatched range opening operator %c.\n", idx_ropen);
	}

	prev = curr;
	flush_line(TRUE);
	PUT(postamble);
	tmp_lc = ind_lc + postlen;
	if (ind_ec == 1) {
		DONE(tmp_lc, "lines written", ind_ec, "warning");
	} else {
		DONE(tmp_lc, "lines written", ind_ec, "warnings");
	}
}


static int
make_entry(n)
	int    		n;
{
	int    		let;

	/* determine current and previous pointer */
	prev = curr;
	curr = idx_key[n];

	/* check if current entry is in range */
	if ((*curr->encap == idx_ropen) || (*curr->encap == idx_rclose))
		encap = &(curr->encap[1]);
	else
		encap = curr->encap;

	/* determine the current nesting level */
	if (n == 0) {
		prev_level = level = 0;
		make_item();
		let = *curr->sf[0];
		LETTERHEAD;
	} else {
		prev_level = level;
		for (level = 0; level < FIELD_MAX; level++)
		        if (STRNEQ(curr->sf[level], prev->sf[level]) ||
		    	    STRNEQ(curr->af[level], prev->af[level]))
				    break;
		if (level < FIELD_MAX)
			new_entry();
		else
			old_entry();
	}

	if (*curr->encap == idx_ropen)
		if (in_range) {
			IND_ERROR("Extra range opening operator %c.\n", idx_ropen);
		} else {
			in_range = TRUE;
			range_ptr = curr;
			range_lc = ind_lc;
		}
	else if (*curr->encap == idx_rclose)
		if (in_range) {
			in_range = FALSE;
			if (STRNEQ(&(curr->encap[1]), "") &&
			    STRNEQ(prev_encap, &(curr->encap[1]))) {
				IND_ERROR("Range closing operator has an inconsitent encapsulator %s.\n", &(curr->encap[1]));
			}
		} else {
			IND_ERROR("Unmatched range closing operator %c.\n", idx_rclose);
		}
	else if ((*curr->encap != NULL) &&
		 STRNEQ(curr->encap, prev_encap) && in_range)
		IND_ERROR("Inconsistent page encapsulator %s within range.\n", curr->encap);
	return (1);
}


static void
make_item()
{
	int 		i;

	if (level > prev_level) {
		/* ascending level */
		if (*curr->af[level] == NULL)
			sprintf(line, "%s%s", item_u[level], curr->sf[level]);
		else
			sprintf(line, "%s%s", item_u[level], curr->af[level]);
		ind_lc += ilen_u[level];
	} else {
		/* same or descending level */
		if (*curr->af[level] == NULL)
			sprintf(line, "%s%s", item_r[level], curr->sf[level]);
		else
			sprintf(line, "%s%s", item_r[level], curr->af[level]);
		ind_lc += ilen_r[level];
	}

	i = level + 1;
	while (i < FIELD_MAX && *curr->sf[i] != NULL) {
		PUT(line);
		if (*curr->af[i] == NULL)
			sprintf(line, "%s%s", item_x[i], curr->sf[i]);
		else
			sprintf(line, "%s%s", item_x[i], curr->af[i]);
		ind_lc += ilen_x[i];
		i++;
	}

	ind_indent = 0;
	strcat(line, delim_p[level]);
	SAVE;
}


static void
new_entry()
{
	char			let;
	FIELD_PTR		ptr;
#ifdef KANJI
	int	kinda, kindb, new;
	char	newchar[3];
	char	newcharstr[128];
#endif

	if (in_range) {
		ptr = curr;
		curr = range_ptr;
		IND_ERROR("Unmatched range opening operator %c.\n", idx_ropen);
		in_range = FALSE;
		curr = ptr;
	}

	flush_line(TRUE);

	/* beginning of a new group? */
#ifdef KANJI
	/*
	**  Check whether if index entry is begin with Kanji Character
	*/
	kinda = curr->sf[0][0]&0200;
	kindb = prev->sf[0][0]&0200;
	if(kinda){
		newchar[0]=curr->sf[0][0];
		newchar[1]=curr->sf[0][1];
		newchar[2]='\0';
	}else{
		newchar[0]=curr->sf[0][0];
		newchar[1]='\0';
	}
	if (kinda == 0 && kindb == 0) /* Both entries are ASCII */
		new = (((let = TOLOWER(curr->sf[0][0])) != (TOLOWER(prev->sf[0][0]))) &&
	    (! ISSYMBOL(*curr->sf[0])));
	else if (kinda != kindb) {
		/* ASCII and Kanji. We should start new group */
		new = 1;
	} else {
		/*
		** Both entries are begin with Kanji letter.
		** We have to check second byte to determine that
		** they belong to same group.
		*/
		new = (curr->sf[0][1] != prev->sf[0][1]);
	}
	if (new) {
#else
	if (((curr->group != ALPHA) && (curr->group != prev->group)) ||
	    ((curr->group == ALPHA) &&
	     ((let = TOLOWER(curr->sf[0][0])) != (TOLOWER(prev->sf[0][0]))))) {
#endif
		PUT(group_skip);
/*
#ifdef KANJI
		if(putnewchar){
			tohiragana(&newchar);
			sprintf(newcharstr,"\\idxsec{%s}\n", newchar);
			PUT(newcharstr);
		}
#endif
*/
		ind_lc += skiplen;
		/* beginning of a new letter? */
		LETTERHEAD;
	}
	make_item();
}


static void
old_entry()
{
	int		diff;

	/* current entry identical to previous one: append pages */
	diff = page_diff(end, curr);
	if ((prev->type == curr->type) && (diff != -1) &&
	    (((diff == 0) && (prev_encap != NULL) && STREQ(encap, prev_encap)) ||
	     (merge_page && (diff == 1) &&
	      (prev_encap != NULL) && STREQ(encap, prev_encap)) ||
	     in_range)) {
		end = curr;
		/* extract in-range encaps out */
		if (in_range &&
		    (*curr->encap != NULL) &&
		    (*curr->encap != idx_rclose) &&
		    STRNEQ(curr->encap, prev_encap)) {
			sprintf(buff, "%s%s%s%s%s", encap_p, curr->encap,
				encap_i, curr->lpg, encap_s);
			wrap_line(FALSE);
		}
		if (in_range)
			encap_range = TRUE;
	} else {
		flush_line(FALSE);
		if ((diff == 0) && (prev->type == curr->type)) {
			IND_ERROR("Conflicting entries: multiple encaps for the same page under same key.\n", "");
		} else if (in_range && (prev->type != curr->type)) {
			IND_ERROR("Illegal range formation: starting & ending pages are of different types.\n", "");
		} else if (in_range && (diff == -1)) {
			IND_ERROR("Illegal range formation: starting & ending pages cross chap/sec breaks.\n", "");
		}
		SAVE;
	}
}


static int
page_diff(a, b)
	FIELD_PTR	a;
	FIELD_PTR	b;
{
	short		i;

	if (a->count != b->count)
		return (-1);
	for (i = 0; i < a->count-1; i++)
		if (a->npg[i] != b->npg[i])
			return (-1);
	return (b->npg[b->count-1] - a->npg[a->count-1]);
}


static void
flush_line(print)
	int		print;
{
	char		tmp[LINE_MAX];

	if (page_diff(begin, end) != 0)
		if (encap_range || (page_diff(begin, prev) > 1)) {
			sprintf(buff, "%s%s%s", begin->lpg, delim_r, end->lpg);
			encap_range = FALSE;
		} else
			sprintf(buff, "%s%s%s", begin->lpg, delim_n, end->lpg);
	 else
		strcpy(buff, begin->lpg);

	if (*prev_encap != NULL) {
		strcpy(tmp, buff);
		sprintf(buff, "%s%s%s%s%s", encap_p, prev_encap, encap_i, tmp, encap_s);
	}

	wrap_line(print);
}


static void
wrap_line(print)
	int		print;
{
	int		len;

	len = strlen(line) + strlen(buff) + ind_indent;
	if (print) {
		if (len > linemax) {
			PUTLN(line);
			PUT(indent_space);
			ind_indent = indent_length;
		} else
			PUT(line);
		PUT(buff);
	} else {
		if (len > linemax) {
			PUTLN(line);
			sprintf(line, "%s%s%s", indent_space, buff, delim_n);
			ind_indent = indent_length;
		} else {
			strcat(buff, delim_n);
			strcat(line, buff);
		}
	}
}


static void
insert_page()
{
	int		i = 0;
	int		j = 0;
	int		page = 0;

	if (even_odd >= 0) {
		/* find the rightmost digit */
		while (pageno[i++] != NULL);
		j = --i;
		/* find the leftmost digit */
		while (isdigit(pageno[--i]) && i > 0);
		if (! isdigit(pageno[i]))
			i++;
		/* convert page from literal to numeric */
		page = strtoint(&pageno[i]) + 1;
		/* check even-odd numbering */
		if (((even_odd == 1) && (page%2 == 0)) || ((even_odd == 2) && (page%2 == 1)))
				page++;
		pageno[j+1] = NULL;
		/* convert page back to literal */
		while (page >= 10) {
			pageno[j--] = TOASCII(page%10);
			page = page / 10;
		}
		pageno[j] = TOASCII(page);
		if (i < j) {
			while (pageno[j] != NULL)
				pageno[i++] = pageno[j++];
			pageno[i] = NULL;
		}
	}

	PUT(setpage_open);
	PUT(pageno);
	PUT(setpage_close);
	ind_lc += setpagelen;
}

