/* $XConsortium: print_ind.c,v 5.2 94/04/17 20:05:37 rws Exp $ */

/***********************************************************

Copyright (c) 1990, 1991  X Consortium

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Except as contained in this notice, the name of the X Consortium shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from the X Consortium.

Copyright (c) 1990, 1991 by Sun Microsystems, Inc.

                        All Rights Reserved

Permission to use, copy, modify, and distribute this software and its 
documentation for any purpose and without fee is hereby granted, 
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in 
supporting documentation, and that the names of Sun Microsystems,
and the X Consortium, not be used in advertising or publicity 
pertaining to distribution of the software without specific, written 
prior permission.  

SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT 
SHALL SUN MICROSYSTEMS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL 
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.

******************************************************************/



#include <stdio.h>
#include <ctype.h>
#include "indexer.h"

#define	PRIMARY_INDENT		2
#define	SECONDARY_INDENT	6

print_index(node)
	struct index_entry	*node;
{


	if (node == NULL)
		return;
	print_index(node->lesser);
	print_node(node, previous_index_entry);
	previous_index_entry = node;
	print_index(node->greater);
}


/*
 * Print out an Index entry
 */
print_node(node, previous)
struct index_entry	*node;
struct index_entry	*previous;
{

	int	level;
	char	first_char;


/*
 *  We have to decide if this index entry is a new primary term or is the
 *  continuation of a primary term with a different secondary term.  If
 *  the primary term of this index entry differs from the primary term of
 *  the previous index entry, this is a new index entry and we have to set
 *  and unset various of the troff flags and change vertical spacing and so on.
 */

	if (previous == NULL)	/*  This is the very first entry  */
		level = PRIMARY;
	else
		if (strcmp(previous->terms[PRIMARY], node->terms[PRIMARY]) == 0)
			level = SECONDARY;	/*  Secondary terms differ  */
		else
			level = PRIMARY;	/*  Primary terms differ  */

/*
 *  We only need to print the primary index term if the level is PRIMARY, that is,
 *  this is a new primary entry.  If the level is SECONDARY, it means we are
 *  printing secondary terms and the primary term has already been printed
 *  sometime in the past.  If this is a new primary term, we have to do
 *  three things:
 *  1.  We have to check for a change in the first character of the primary
 *      index term so that we print the large bold-faced character as a
 *      caption for this term -- this is what gets us the letters of the
 *      alphabet as captions in the final index.
 *  2.  We have to set a continuation string consisting of the primary index
 *      term, so that when you have a list of secondary terms that start on a
 *      new page or a new column on the same page, you get the primary entry
 *      with the word 'continued' after it so that the reader is reassured
 *      as to what the primary entry is and also to lead the eye to the
 *      fact of a continued primary term.
 *  3.  We then actually want to print the primary index term.
 */
	if (level == PRIMARY) {
		set_continuation_string("");
		print_first_character(node);
		if (string_exists(node->print_field[PRIMARY]))
			set_continuation_string(node->print_field[PRIMARY]);
		else
			set_continuation_string(node->terms[PRIMARY]);
		print_primary_terms(node);
		if (string_exists(node->terms[SECONDARY]))
			printf("\n");
	}

/*
 *  Now we print any secondary terms associated with this primary term
 */
	if (string_exists(node->terms[SECONDARY]))
		print_secondary_terms(node);


/*
 *  Finally, we print the page numbers associated with this term.
 */
	print_pages(node);
}


print_first_character(node)
struct index_entry	*node;
{

	char	first_char;

	static char	current_first_char = '\0';

				/*  check for change in first character  */
				/*  so that we can print a caption  */
	first_char = node->terms[PRIMARY][0];
	if (isalpha(first_char))
		if (islower(first_char))
			first_char = toupper(first_char);
	if (ispunct(first_char)) {
		if (current_first_char == '\0') {
			printf(".sp\n");
			printf(".ne 3\n");
			indent(SECONDARY_INDENT - PRIMARY_INDENT, 0);
			printf("\\fISpecial Characters\\fP\n");
		}
	} else if (first_char != current_first_char) {
		printf(".sp\n");
		printf(".ne 3\n");
		indent(SECONDARY_INDENT - PRIMARY_INDENT, 0);
		printf("\\fB\\s+3%c\\s-3\\fP\n", first_char);
	}
	current_first_char = first_char;
}

set_continuation_string(string)
char	*string;
{

	static  char	*current_continuation_string = "";

	if (strcmp(string, current_continuation_string) != 0)
		current_continuation_string = string;
	if (strcmp(current_continuation_string, "") == 0)
		printf(".rm iC\n");
	else
		printf(".ds iC \\&%s, \\fIcontinued\\fP\n", current_continuation_string);
}


print_primary_terms(node)
struct index_entry	*node;
{


	set_index_level(PRIMARY);
	indent(PRIMARY_INDENT, PRIMARY_INDENT);
	change_vertical_spacing(VERTICAL_CHANGE);
	if (string_exists(node->print_field[PRIMARY]))
		printf("\\&%s", node->print_field[PRIMARY]);
	else
		printf("\\&%s", node->terms[PRIMARY]);
}


print_secondary_terms(node)
struct index_entry	*node;
{

	set_index_level(SECONDARY);
	indent(SECONDARY_INDENT, SECONDARY_INDENT - PRIMARY_INDENT);
	change_vertical_spacing(-VERTICAL_CHANGE);
	if (string_exists(node->print_field[SECONDARY]))
		printf("\\&%s", node->print_field[SECONDARY]);
	else
		printf("\\&%s", node->terms[SECONDARY]);
}


set_index_level(level)
	int	level;
{

	static	int	current = 0;

	if (level == current)
		return;
	else {
		current = level;
		printf(".nr iL  %d\n", current);
	}
}

change_vertical_spacing(amount)
	int	amount;
{

	static	int	current = VERTICAL_CHANGE;

	if (amount == current)
		return;
	else {
		if (amount > 0)
			printf(".vs +%d\n", amount);
		else
			printf(".vs %d\n", amount);
		current = amount;
	}
}

/*
 * Indent a specified number of levels 
 */
indent(indent_amount, temporary_indent)
	int	indent_amount;
	int	temporary_indent;
{
	static	int	current_indent;		/* Current indent position */

	if (indent_amount != current_indent) {
		printf("'in %d\n", indent_amount);
		current_indent = indent_amount;
	}
	if (temporary_indent > 0)
		printf(".ti -%d\n", temporary_indent);
}

/*
 * Un-indent a specified number of levels 
 */
unindent()
{
	printf(".in 0\n");
}

/*
 * Put out the page numbers associated with an index node.
 */
print_pages(node)
struct index_entry	*node;
{
	struct page_entry	*page;

	for (page = node->page_entry; page != NULL; page = page->next_page) {

			/*  Print normal page references  */
		if (page->page_type == PAGE_NORMAL || page->page_type == PAGE_PRINT)
			printf(", %s", page->page_number);

			/*  Print major page references in boldface text  */
		if (page->page_type == PAGE_MAJOR)
			printf(", \\fB%s\\fP", page->page_number);

			/*  Page ranges -- if a range starts and ends on
			    the same page we just print the starting page
			    number as a normal index entry and skip over 
			    the ending page number of the range  */
		if (page->page_type == PAGE_START) {
			if (page->next_page != NULL) {
				if (page->next_page->page_type == PAGE_END) {
					if (strcmp(page->page_number,
						page->next_page->page_number) == 0)
						printf(", %s", page->page_number);
					else
						printf(", %s \\fI\\s-1thru\\s+1\\fP %s",
							page->page_number,
							page->next_page->page_number);
					page = page->next_page;
				}
			} else {
				fprintf (stderr,
					"%s: unmatched range for terms \"%s\" \"%s\"\n",
					command_name, node->terms[PRIMARY], node->terms[SECONDARY]);
			}
		}
	}
	printf ("\n");
}
