/*
 * Copyright (c) 1992, Bruno Grossniklaus, grossnik@iam.unibe.ch
 * 
 * I added new features for special use at the IAM and fixed some bugs.
 * 
 */

/*
 * Copyright (c) 1990, William C. Ogden, ogden@nmsu.edu
 * 
 * Permission is granted to copy and distribute this file in modified or
 * unmodified form, for noncommercial use, provided (a) this copyright notice
 * is preserved, (b) no attempt is made to restrict redistribution of this
 * file, and (c) this file is not distributed as part of any collection whose
 * redistribution is restricted by a compilation copyright.
 */



#include <stdio.h>
#include <sys/param.h>
#include <sys/types.h>
#include <xview/xview.h>
#include <xview/canvas.h>
#include <xview/panel.h>
#include <xview/scrollbar.h>
#include <xview/svrimage.h>
#include <xview/termsw.h>
#include <xview/text.h>
#include <xview/tty.h>
#include <xview/xv_xrect.h>
#include <xview/dragdrop.h>
#include <xview/cursor.h>
#include <xview/notice.h>
#include <gdd.h>

#include <math.h>

#include "bc_view.h"

/* local globals */
int             find_index;
int             show_selected_pos = -1;
int             sort_count;
int             gauge_old_val;
int             sort_old_val;



/*
 * void ReassignListEntries(Panel_item list, char **entries)
 * 
 * Replaces all of the entries in 'list' with the strings in the null-terminated
 * array 'entries'. + only replaces entries if they are different + buffers
 * replacements for efficiency + manipulates the scrollbar correctly +
 * deactivates the list if it is empty + works around several XView bugs
 * 
 * Copyright (c) 1990 Elan Computer Group, Inc. All Rights Reserved.
 * 
 * This is published non-proprietary source code of Elan Computer Group, Inc.
 * Any and all parties are free to distribute this code or include it in any
 * product or program, whether for sale or free distribution. This source
 * code is not under any warranty or guarantee, explicitly or implicitly, by
 * Elan Computer Group Inc. or its employees.
 */

/*
 * #include <xview/xview.h> #include <xview/panel.h> #include
 * <xview/scrollbar.h>
 */

typedef unsigned char Boolean;
#if ! defined(TRUE)
#define TRUE	(1)
#define FALSE	(0)
#endif

/* limit for ATTR_LIST including a pad */
#define MAX_XVIEW_ATTRIBUTES    (255 - 20)

extern char    *malloc();
extern int      free();
extern int      strcmp();


static void
ReassignListEntries(list, entries)
	Panel_item      list;
	char          **entries;
{
	register int    newNumItems, currentNumItems, attrIndex, entryIndex;
	int             attrListSize;
	Xv_opaque      *attrList;
	Boolean         listInactive, scrollbarInactive;

	xv_set(Bc_list_popup->list_popup, FRAME_BUSY, TRUE, NULL);
	xv_set(Bc_base_window->base_window, FRAME_BUSY, TRUE, NULL);

	currentNumItems = (int) xv_get(list, PANEL_LIST_NROWS);
	if ((entries == (char **) 0) || (entries[0] == (char *) 0)) {
		newNumItems = 0;
		listInactive = TRUE;
	} else {
		for (newNumItems = 0; entries[newNumItems] != 0; newNumItems++);
		listInactive = FALSE;
	}

	/* see if the lists are the same */
	if (currentNumItems == newNumItems) {
		register int    i;
		register char  *itemStr;
		Boolean         same = TRUE;

		for (i = 0; i < newNumItems; i++) {
			itemStr = (char *) xv_get(list, PANEL_LIST_STRING, i);
			if (strcmp(itemStr, entries[i]) != 0) {
				same = FALSE;
				break;
			}
		}


		if (same) {
		  xv_set(Bc_list_popup->list_popup, FRAME_BUSY, FALSE, NULL);
		  xv_set(Bc_base_window->base_window, FRAME_BUSY, FALSE, NULL);
		  
		  return;
		}
	}
	if (newNumItems == 0) {
		/* must have at least one entry to hold selection (XView bug) */
		newNumItems = 1;
	}
	/* for each element: ATTR + index + string */
	attrListSize = newNumItems * 3;
	if (currentNumItems > newNumItems) {
		/* ATTR + indexx for each extra element */
		attrListSize += (currentNumItems - newNumItems) * 2;
	}
	/* null terminator for ATTR_LIST */
	attrListSize++;

	attrList = (Xv_opaque *)
		malloc((unsigned) (attrListSize * sizeof(Xv_opaque)));
	attrIndex = 0;
	/* delete excess entries */
	while (currentNumItems > newNumItems) {
		attrList[attrIndex] = (Xv_opaque) PANEL_LIST_DELETE;
		attrList[attrIndex + 1] = (Xv_opaque) currentNumItems - 1;
		currentNumItems--;
		attrIndex += 2;

		/* see if we have overflowed XView limit */
		if (attrIndex > MAX_XVIEW_ATTRIBUTES) {
			/* terminate and flush ATTR_LIST */
			attrList[attrIndex] = (Xv_opaque) 0;
			xv_set(list, ATTR_LIST, attrList, 0);
			attrIndex = 0;
		}
	}

	/* add new entries */
	if (newNumItems != 0) {
		for (entryIndex = 0; entryIndex < newNumItems; entryIndex++) {
			attrList[attrIndex++] = (Xv_opaque) PANEL_LIST_STRING;
			attrList[attrIndex++] = (Xv_opaque) entryIndex;
			if ((entries == (char **) 0) ||
			    (entries[entryIndex] == (char *) 0)) {
				/* can happen if list is empty */
				attrList[attrIndex++] = (Xv_opaque) "";
			} else
				attrList[attrIndex++] = (Xv_opaque) entries[entryIndex];

			/* see if we have overflowed XView limit */
			if (attrIndex > MAX_XVIEW_ATTRIBUTES) {
				/* terminate and flush ATTR_LIST */
				attrList[attrIndex] = (Xv_opaque) 0;
				xv_set(list, ATTR_LIST, attrList, PANEL_PAINT, PANEL_NONE, 0);
				attrIndex = 0;
			}
		}
	}
	attrList[attrIndex] = (Xv_opaque) 0;	/* terminate ATTR_LIST */

	xv_set(list, ATTR_LIST, attrList,
	       PANEL_INACTIVE, (Xv_opaque) listInactive,
	       0);
	/* must do this as separate call to avoid XView bug (2.0) */
	xv_set(list, PANEL_LIST_SELECT, 0, TRUE, 0);
	if (listInactive)
		xv_set(list, PANEL_LIST_SELECT, 0, FALSE, 0);

	/* zero and disable scrollbar manually (XView should do these) */
	scrollbarInactive = (listInactive ||
	      (newNumItems <= (int) xv_get(list, PANEL_LIST_DISPLAY_ROWS)));
	xv_set(xv_get(list, PANEL_LIST_SCROLLBAR),
	       SCROLLBAR_VIEW_START, 0,
	       SCROLLBAR_INACTIVE, (int) scrollbarInactive,
	       0);

	free((char *) attrList);

	xv_set(Bc_list_popup->list_popup, FRAME_BUSY, FALSE, NULL);
	xv_set(Bc_base_window->base_window, FRAME_BUSY, FALSE, NULL);
}




extern void
get_total()
{
	Ref             ref;

	total = 0;
	ref = first_item;
	while (ref) {
		total++;
		ref = ref->next;
	}
}



extern void
update_cite_list()
{
	Ref             ref;
	int             i, n;
	char          **item_list;
	char            message[BUFSIZ];

	get_total();

	if (total <= max_total_for_list) {

	xv_set(Bc_list_popup->list_popup, FRAME_RIGHT_FOOTER, "", NULL);

	item_list = (char **) malloc((total + 1) * sizeof(char *));
	ref = first_item;

	if ((!ref) || (!ref->field[citekey_id])) {
		free(item_list);
		return;
	}
	n = 0;
	while (ref) {
		item_list[n++] = (char *) strdup(ref->field[citekey_id]);
		ref = ref->next;
	}

	item_list[n] = (char *) NULL;
	ReassignListEntries(Bc_list_popup->list_popup_list, item_list);

	for (i = n - 1; i >= 0; i--)
		free(item_list[i]);

	free(item_list);

	if (mod_for_find_flag == TRUE) {
	  xv_set(Bc_list_popup->list_popup_list, XV_SHOW, TRUE, NULL);
	}

	xv_set(Bc_list_popup->list_popup, FRAME_RIGHT_FOOTER, "", NULL);
	xv_set(Bc_list_popup->list_popup, FRAME_LEFT_FOOTER, "", NULL);

      } else {
	
	xv_set(Bc_list_popup->list_popup_list, XV_SHOW, FALSE, NULL);
	xv_set(Bc_list_popup->list_popup, FRAME_RIGHT_FOOTER, "List is too big.", NULL);
	sprintf (message,"%d > %d (Max Total)",total, max_total_for_list);
	xv_set(Bc_list_popup->list_popup, FRAME_LEFT_FOOTER, message, NULL);
      }

	return;
}





static double
nlogn(n)
	int             n;
{
	return (double) (n) * (log((double) n));
}



static void
update_sort_gauge()
{
	double          value = sort_count / (nlogn(total));
	int             val;

	val = (int) (value * (double) 100);

	if (sort_old_val != val) {
		xv_set(Bc_sort_popup->sort_popup_gauge,
		       PANEL_PAINT, PANEL_NO_CLEAR,
		       PANEL_VALUE, val, 0);
		XFlush((Display *) xv_get(Bc_sort_popup->sort_popup, XV_DISPLAY));
		sort_old_val = val;
	}
}



static void
update_find_gauge()
{

	int             val = (int) ((double) find_index / (double) total * (double) 100);

	if (gauge_old_val != val) {
		xv_set(Bc_find_popup->find_popup_gauge,
		       PANEL_PAINT, PANEL_NO_CLEAR,
		       PANEL_VALUE, val, 0);
		XFlush((Display *) xv_get(Bc_find_popup->find_popup, XV_DISPLAY));
		gauge_old_val = val;
	}
}


static          Ref
merge_Refs(a, b)
	Ref             a, b;
{
	int             sort_field = (int) xv_get(Bc_sort_popup->sort_popup_sort_field_setting, PANEL_VALUE);
	int             sort_field_a, sort_field_b;

	int             direction = (int) xv_get(Bc_sort_popup->sort_popup_sort_order, PANEL_VALUE);
	Ref             r, p;

	if (!a)
		return (b);

	if (!b)
		return (a);

	sort_field_a = sort_field;
	sort_field_b = sort_field;

	if ((strcmp(a->ref_type, ref_types_show_fct[book_id].ref_type_token) == NULL) ||
	    (strcmp(a->ref_type, ref_types_show_fct[inbook_id].ref_type_token) == NULL)) {
		if ((sort_field_a == author_id) && !a->field[author_id]) {
			sort_field_a = editor_id;
		} else if ((sort_field_a == editor_id) && !a->field[editor_id]) {
			sort_field_a = author_id;
		}
	}
	if ((strcmp(b->ref_type, ref_types_show_fct[book_id].ref_type_token) == NULL) ||
	    (strcmp(b->ref_type, ref_types_show_fct[inbook_id].ref_type_token) == NULL)) {
		if ((sort_field_b == author_id) && !b->field[author_id]) {
			sort_field_b = editor_id;
		} else if ((sort_field_b == editor_id) && !b->field[editor_id]) {
			sort_field_b = author_id;
		}
	}
	if (!a->field[sort_field_a]) {
		if (direction) {
			r = p = a;
			a = a->next;
			p->next = NULL;
		} else {
			r = p = b;
			b = b->next;
			p->next = NULL;
		}

	} else if (!b->field[sort_field_b]) {
		if (direction) {
			r = p = b;
			b = b->next;
			p->next = NULL;
		} else {
			r = p = a;
			a = a->next;
			p->next = NULL;
		}

	} else if (direction ? strcasecmp(a->field[sort_field_a], b->field[sort_field_b]) >= 0 :
	  strcasecmp(a->field[sort_field_a], b->field[sort_field_b]) <= 0) {
		r = p = a;
		a = a->next;
		p->next = NULL;

	} else {
		r = p = b;
		b = b->next;
		p->next = NULL;
	}

	while (a && b) {
		sort_count++;
		update_sort_gauge();

		if ((strcmp(a->ref_type, ref_types_show_fct[book_id].ref_type_token) == NULL) ||
		    (strcmp(a->ref_type, ref_types_show_fct[inbook_id].ref_type_token) == NULL)) {
			if ((sort_field_a == author_id) && !a->field[author_id]) {
				sort_field_a = editor_id;
			} else if ((sort_field_a == editor_id) && !a->field[editor_id]) {
				sort_field_a = author_id;
			}
		}
		if ((strcmp(b->ref_type, ref_types_show_fct[book_id].ref_type_token) == NULL) ||
		    (strcmp(b->ref_type, ref_types_show_fct[inbook_id].ref_type_token) == NULL)) {
			if ((sort_field_b == author_id) && !b->field[author_id]) {
				sort_field_b = editor_id;
			} else if ((sort_field_b == editor_id) && !b->field[editor_id]) {
				sort_field_b = author_id;
			}
		}
		if (!a->field[sort_field_a]) {
			if (direction) {
				p->next = a;
				a = a->next;
				p = p->next;
				p->next = NULL;
			} else {
				p->next = b;
				b = b->next;
				p = p->next;
				p->next = NULL;
			}

		} else if (!b->field[sort_field_b]) {
			if (direction) {
				p->next = b;
				b = b->next;
				p = p->next;
				p->next = NULL;
			} else {
				p->next = a;
				a = a->next;
				p = p->next;
				p->next = NULL;
			}

		} else if (direction ? strcasecmp(a->field[sort_field_a], b->field[sort_field_b]) >= 0 :
			   strcasecmp(a->field[sort_field_a], b->field[sort_field_b]) <= 0) {
			p->next = a;
			a = a->next;
			p = p->next;
			p->next = NULL;

		} else {
			p->next = b;
			b = b->next;
			p = p->next;
			p->next = NULL;
		}
	}

	if (!a) {
		p->next = b;
	}
	if (!b) {
		p->next = a;
	}
	return (r);
}



static          Ref
merge_sort(a)
	Ref             a;
{
	if (!a || !a->next) {
		return a;

	} else {
		Ref             p1, p2;

		p1 = a;
		p2 = a->next;

		while (p2 && p2->next) {
			sort_count++;
			update_sort_gauge();
			p1 = p1->next;
			p2 = p2->next->next;
		}

		p2 = p1->next;
		p1->next = NULL;
		return merge_Refs(merge_sort(a), merge_sort(p2));
	}
}



extern void
clear_all_selections()
{
	int             i;
	int             nItems = (int) xv_get(Bc_list_popup->list_popup_list, PANEL_LIST_NROWS);
	int             list_popup_show_flag = (int) xv_get(Bc_list_popup->list_popup_list, XV_SHOW);

	xv_set(Bc_list_popup->list_popup_list, XV_SHOW, FALSE, NULL);

	xv_set(Bc_list_popup->list_popup, FRAME_BUSY, TRUE, NULL);
	xv_set(Bc_base_window->base_window, FRAME_BUSY, TRUE, NULL);

	for (i = 0; i < nItems; i++)
		xv_set(Bc_list_popup->list_popup_list, PANEL_LIST_SELECT, i, FALSE, NULL);

	xv_set(Bc_list_popup->list_popup_list, XV_SHOW, list_popup_show_flag, NULL);

	xv_set(Bc_list_popup->list_popup, FRAME_BUSY, FALSE, NULL);
	xv_set(Bc_base_window->base_window, FRAME_BUSY, FALSE, NULL);

	show_selected_pos = -1;

}


extern void
select_all()
{
	int             i;
	int             nItems = (int) xv_get(Bc_list_popup->list_popup_list, PANEL_LIST_NROWS);
	int             list_popup_show_flag = (int) xv_get(Bc_list_popup->list_popup_list, XV_SHOW);

	xv_set(Bc_list_popup->list_popup_list, XV_SHOW, FALSE, NULL);

	xv_set(Bc_list_popup->list_popup, FRAME_BUSY, TRUE, NULL);
	xv_set(Bc_base_window->base_window, FRAME_BUSY, TRUE, NULL);

	for (i = 0; i < nItems; i++)
		xv_set(Bc_list_popup->list_popup_list, PANEL_LIST_SELECT, i, TRUE, PANEL_PAINT, PANEL_NONE, 0);

	xv_set(Bc_list_popup->list_popup_list, XV_SHOW, list_popup_show_flag, NULL);

	xv_set(Bc_list_popup->list_popup, FRAME_BUSY, FALSE, NULL);
	xv_set(Bc_base_window->base_window, FRAME_BUSY, FALSE, NULL);
	
}



/*
 * FSF_strstr - find first occurrence of wanted in s Copyright (C) 1989, Free
 * Software Foundation.
 * 
 */


#define CONST
#ifdef size_t
#define SIZET size_t
#else
#define SIZET unsigned int
#endif

static char    *		/* found string, or NULL if none */
FSF_strstr(s, wanted)
	CONST char     *s;
	CONST char     *wanted;
{
	register CONST char *scan;
	register SIZET  len;
	register char   firstc;
	extern int      strcmp();

	/*
	 * The odd placement of the two tests is so "" is findable. Also, we
	 * inline the first char for speed. The ++ on scan has been moved
	 * down for optimization.
	 */
	firstc = *wanted;
	len = strlen(wanted);
	for (scan = s; *scan != firstc || strncmp(scan, wanted, len) != 0;)
		if (*scan++ == '\0')
			return (NULL);
	return (scan);
}



static char    *		/* A case insensitive version */
FSF_strcasestr(s, wanted)
	CONST char     *s;
	CONST char     *wanted;
{
	register CONST char *scan;
	register SIZET  len;
	register char   firstc;
	extern int      strcmp();

	firstc = (isupper(*wanted) ? tolower(*wanted) : *wanted);
	len = strlen(wanted);
	for (scan = s; strncasecmp(scan, wanted, len) != 0;) {

		if (*scan++ == '\0')
			return (NULL);
	}
	return (scan);
}




extern void
find()
{
	char           *find_source[NUM_OF_FIND_FIELDS - 2];
	char            find_string[NUM_OF_FIND_FIELDS][BUFSIZ];
	char           *nul_string = (char *) '\0';

	int             i, j, first, clear_flag;
	int             find_field_setting[NUM_OF_FIND_FIELDS - 2];

	int             find_ref_type = (int)
	xv_get(Bc_find_popup->find_popup_ref_type, PANEL_VALUE);
	int             find_connect = (int)
	xv_get(Bc_find_popup->find_popup_connect, PANEL_VALUE);
	int             find_findmethod = (int)
	xv_get(Bc_find_popup->find_popup_findmethod, PANEL_VALUE);
	int             find_ignore_case = (int)
	xv_get(Bc_find_popup->find_popup_ignore_case, PANEL_VALUE);
	int             find_fuzzy_distance = (int)
	xv_get(Bc_find_popup->find_popup_fuzzy_distance, PANEL_VALUE);

	int             select_in_list = (int)
	xv_get(Bc_find_popup->find_popup_select_in_list, PANEL_VALUE);
	
	Ref             ref, first_found;

	char            message[BUFSIZ];

#ifdef PRINT_FIND_NUM
	int             find_count = 0;
#endif

	xv_set(Bc_find_popup->find_popup, FRAME_BUSY, TRUE, NULL);

	ref = first_item;
	find_index = 0;
	gauge_old_val = 0;
	first = -1;

	find_field_setting[0] = (int)
		xv_get(Bc_find_popup->find_popup_find_field_setting1,
		       PANEL_VALUE);
	find_field_setting[1] = (int)
		xv_get(Bc_find_popup->find_popup_find_field_setting2,
		       PANEL_VALUE);
	find_field_setting[2] = (int)
		xv_get(Bc_find_popup->find_popup_find_field_setting3,
		       PANEL_VALUE);
	find_field_setting[3] = (int)
		xv_get(Bc_find_popup->find_popup_find_field_setting4,
		       PANEL_VALUE);
	find_field_setting[4] = (int)
		xv_get(Bc_find_popup->find_popup_find_field_setting5,
		       PANEL_VALUE);

	get_total();

	free((char *) found_flag);
	found_flag = (int *) malloc(total * sizeof(int));
	for (i = 0; i < total; i++)
	  found_flag[i] = FALSE;

	mod_for_find_flag = FALSE;

	for (i = 0; i < NUM_OF_FIND_FIELDS; i++)
		strcpy(find_string[i], "");

	strcpy(find_string[0], (char *)
	       xv_get(Bc_find_popup->find_popup_from_year, PANEL_VALUE));
	strcpy(find_string[1], (char *)
	       xv_get(Bc_find_popup->find_popup_to_year, PANEL_VALUE));


	if (find_connect != 0) {
		/* OR */
		if ((strlen(find_string[0]) > 0) || (strlen(find_string[1]) > 0)) {
			if (strlen(find_string[1]) == 0)
				strcpy(find_string[0], "0000");
			if (strlen(find_string[1]) == 0)
				strcpy(find_string[1], "9999");
		}
	}
	strcpy(find_string[2], (char *)
	    xv_get(Bc_find_popup->find_popup_find_textfield1, PANEL_VALUE));
	strcpy(find_string[3], (char *)
	    xv_get(Bc_find_popup->find_popup_find_textfield2, PANEL_VALUE));
	strcpy(find_string[4], (char *)
	    xv_get(Bc_find_popup->find_popup_find_textfield3, PANEL_VALUE));
	strcpy(find_string[5], (char *)
	    xv_get(Bc_find_popup->find_popup_find_textfield4, PANEL_VALUE));
	strcpy(find_string[6], (char *)
	    xv_get(Bc_find_popup->find_popup_find_textfield5, PANEL_VALUE));

	if ( (total <= max_total_for_list) && (select_in_list == 1) ) {
	  clear_all_selections();
	    xv_set(Bc_list_popup->list_popup_list, XV_SHOW, TRUE, NULL);
	} else {
	  if ( (total > max_total_for_list) && (select_in_list == 1) ) {
	    sprintf (message,"%d > %d",total, max_total_for_list);
	    notice_prompt(Bc_find_popup->find_popup_controls, NULL,
			  NOTICE_MESSAGE_STRINGS,
			  "Total > max_total_for_list",
			  message, 
			  "Change in Settings",
			  NULL,
			  NOTICE_BUTTON_YES, "Don't select in list",
			  NULL);
	  }
	  if (total > max_total_for_list) {
	    xv_set(Bc_list_popup->list_popup_list, XV_SHOW, FALSE, NULL);
	  }
	  if (select_in_list == 0) {
	    xv_set(Bc_list_popup->list_popup_list, XV_SHOW, FALSE, NULL);
	  }
	}


	if (find_findmethod == 0) {
		/* normal find method */

		xv_set(Bc_find_popup->find_popup_gauge,
		       PANEL_VALUE, NULL, XV_SHOW, TRUE, NULL);
		panel_paint(Bc_find_popup->find_popup_gauge,
			    PANEL_NO_CLEAR);
		XFlush((Display *) xv_get(Bc_find_popup->find_popup,
					  XV_DISPLAY));

		while (ref) {

			for (i = 0; i < NUM_OF_FIND_FIELDS - 2; i++)
				find_source[i] = nul_string;

			for (i = 0; i < NUM_OF_FIND_FIELDS - 2; i++) {
				if (find_field_setting[i] == num_of_fields) {
					/* annotation */
					SET_STR(find_source[i], ref->annote);

				} else if (find_field_setting[i] == num_of_fields + 1) {
					/* all fields */
					SET_STR(find_source[i], ref->annote);
					ADD_TO(find_source[i], ref->nsfield);
					for (j = 0; j < num_of_fields; j++) {
						ADD_TO(find_source[i], ref->field[j]);
					}

				} else if (find_field_setting[i] == num_of_fields + 2) {
					/* none */

				} else {
					/* field */
					SET_STR(find_source[i], ref->field[find_field_setting[i]]);
				}

			}


			if (find_connect == 0) {
				/* AND */

				found_flag[find_index] = TRUE;
				for (i = 0; i < NUM_OF_FIND_FIELDS - 2; i++)
					if (found_flag[find_index] && find_string[i + 2])
						if (strlen(find_string[i + 2]) > 0)
							if (find_ignore_case == 0) {
								if (find_source[i]) {
									if (FSF_strstr(find_source[i], find_string[i + 2]) == NULL)
										found_flag[find_index] = FALSE;
								} else
									found_flag[find_index] = FALSE;
							} else {
								if (find_source[i]) {
									if (FSF_strcasestr(find_source[i], find_string[i + 2]) == NULL)
										found_flag[find_index] = FALSE;
								} else
									found_flag[find_index] = FALSE;
							}

				if (found_flag[find_index]) {

					/* year in range ? */
					if ((ref->field[year_id]) && (strlen(ref->field[year_id]) > 0)) {
						if (find_string[0])
							if (strlen(find_string[0]) > 0) {
								SET_STR(find_source[0], ref->field[year_id]);
								if (find_source[0][0] == ABBREVCODE)
									find_source[0]++;
								if (strcmp(find_string[0], find_source[0]) > 0)
									found_flag[find_index] = FALSE;
							}
						if (find_string[1])
							if (strlen(find_string[1]) > 0) {
								SET_STR(find_source[0], ref->field[year_id]);
								if (find_source[0][0] == ABBREVCODE)
									find_source[0]++;
								if (strcmp(find_string[1], find_source[0]) < 0)
									found_flag[find_index] = FALSE;
							}
					} else {
						if ((!ref->field[year_id]) && ((strlen(find_string[0]) > 0) || (strlen(find_string[1]) > 0)))
							found_flag[find_index] = FALSE;
					}

					/* all types ? */
					if (find_ref_type != NUM_OF_REF_TYPES)
						if (strcmp(ref_types_show_fct[find_ref_type].ref_type_token, ref->ref_type) != NULL)
							found_flag[find_index] = FALSE;

				}
				if (found_flag[find_index]) {
					if (first == -1) {
						first = find_index;
						first_found = ref;
					}
					if ( (total <= max_total_for_list) && (select_in_list == 1) ) {
					  xv_set(Bc_list_popup->list_popup_list, PANEL_LIST_SELECT, find_index, TRUE, PANEL_PAINT, PANEL_NONE, NULL);
					}
				}
			} else {
				/* OR */

				found_flag[find_index] = FALSE;
				for (i = 0; i < NUM_OF_FIND_FIELDS - 2; i++)
					if (!found_flag[find_index] && find_string[i + 2])
						if (strlen(find_string[i + 2]) > 0)
							if (find_ignore_case == 0) {
								if (find_source[i]) {
									if (FSF_strstr(find_source[i], find_string[i + 2]) != NULL)
										found_flag[find_index] = TRUE;
								} else
									found_flag[find_index] = FALSE;
							} else {
								if (find_source[i]) {
									if (FSF_strcasestr(find_source[i], find_string[i + 2]) != NULL)
										found_flag[find_index] = TRUE;
								} else
									found_flag[find_index] = FALSE;
							}

				if (!found_flag[find_index]) {

					/* year in range ? */
					if ((strlen(find_string[0]) > 0) && (ref->field[year_id]) && (strlen(ref->field[year_id]) > 0)) {
						SET_STR(find_source[0], ref->field[year_id]);
						if (find_source[0][0] == ABBREVCODE)
							find_source[0]++;
						if ((strcmp(find_string[0], find_source[0]) <= 0) && (strcmp(find_string[1], find_source[0]) >= 0))
							found_flag[find_index] = TRUE;
					}
					/* all types ? */
					if (find_ref_type != NUM_OF_REF_TYPES)
						if (strcmp(ref_types_show_fct[find_ref_type].ref_type_token, ref->ref_type) == NULL)
							found_flag[find_index] = TRUE;

				}
				if (found_flag[find_index]) {
					if (first == -1) {
						first = find_index;
						first_found = ref;
					}
					if ( (total <= max_total_for_list) && (select_in_list == 1) ) {
					  xv_set(Bc_list_popup->list_popup_list,
						 PANEL_LIST_SELECT, find_index, TRUE, PANEL_PAINT, PANEL_NONE, NULL);
					}

				}
			}

#ifdef PRINT_FIND_NUM
			if (found_flag[find_index])
				find_count++;
#endif
			ref = ref->next;
			find_index++;
			update_find_gauge();

		}		/* while */

		xv_set(Bc_find_popup->find_popup_gauge, XV_SHOW, FALSE, NULL);


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


	} else {
		/* fuzzy and regular find */

		FILE           *tmp_data_file, *tmp_result_file;
		char           *tmp_data_name, *tmp_result_name;
		char            sys_command[BUFSIZ], tmp_str[BUFSIZ];
		int            *line_nr;
		int             k, l;

		if ((line_nr = (int *) malloc((total + 1) * sizeof(int))) == NULL) {
			fprintf(PRINT_TO, "bibcard: ERROR in malloc. \n");
			exit(ERROR);
		}
		if (find_connect == 0) {
			/* AND */
			for (i = 0; i < total; i++)
				found_flag[i] = TRUE;
		}
		/* OR : FALSE allready set */

		for (i = 0; i < NUM_OF_FIND_FIELDS - 2; i++) {
			if ((find_field_setting[i] != num_of_fields + 2) && (find_string[i + 2] != NULL) && (strlen(find_string[i + 2]) > 0)) {

				if ((tmp_data_name = tempnam(TEMP_DIR, AGREP_TEMP_FILE_PFX)) == NULL) {
					fprintf(PRINT_TO, "bibcard: ERROR in tmpnam. \n");
					exit(ERROR);
				}
				if ((tmp_data_file = fopen(tmp_data_name, "w")) == NULL) {
					fprintf(PRINT_TO, "bibcard: ERROR in tmpfile. \n");
					exit(ERROR);
				}
				ref = first_item;

				if (find_field_setting[i] == num_of_fields) {
					/* annotation */
					while (ref) {
						fprintf(tmp_data_file, "%s \n", ref->annote);
						ref = ref->next;
					}

				} else if (find_field_setting[i] == num_of_fields + 1) {

					/* all fields */
					while (ref) {
						for (j = 0; j < num_of_fields; j++) {
							fprintf(tmp_data_file, "%s ", ref->field[j]);
						}
						fprintf(tmp_data_file, "%s %s \n", ref->annote, ref->nsfield);
						ref = ref->next;
					}

				} else if (find_field_setting[i] == num_of_fields + 2) {

					/* none */
					fprintf(PRINT_TO, "bibcard: ERROR in fuzzy find (none). \n");
					exit(ERROR);

				} else {

					/* field */
					while (ref) {
						fprintf(tmp_data_file, "%s \n", ref->field[find_field_setting[i]]);
						ref = ref->next;
					}

				}

				fclose(tmp_data_file);

				if ((tmp_result_name = tempnam(TEMP_DIR, "bcre")) == NULL) {
					fprintf(PRINT_TO, "bibcard: ERROR in tmpnam. \n");
					exit(ERROR);
				}
				if (find_ignore_case == 0)
					sprintf(tmp_str, "");
				else
					sprintf(tmp_str, "-i");

				sprintf(sys_command, "%s -%d %s -n -e \"%s\" %s > %s \n", AGREP_COMMAND, find_fuzzy_distance, tmp_str, find_string[i + 2], tmp_data_name, tmp_result_name);
				system(sys_command);

				for (j = 0; j < total; j++) {
					line_nr[j] = -1;
				}

				if ((tmp_result_file = fopen(tmp_result_name, "r")) == NULL) {
					fprintf(PRINT_TO, "bibcard: ERROR in fopen. \n");
					exit(ERROR);
				}
				j = 0;
				k = -1;
				while ((j < total) && (fscanf(tmp_result_file, "%d", &k) != EOF)) {
					k--;
					line_nr[j] = k;
					j++;
					l = getc(tmp_result_file);
					while ((l != '\n') && (l != EOF)) {
						l = getc(tmp_result_file);
					}
				}

				fclose(tmp_result_file);

				unlink(tmp_data_name);
				unlink(tmp_result_name);

				free(tmp_data_name);
				free(tmp_result_name);

				if (find_connect == 1) {
					/* OR */
					j = 0;
					while ((j < total) && (line_nr[j] > -1)) {
						if (line_nr[j] < total) {
							found_flag[line_nr[j]] = TRUE;
						} else {
							fprintf(PRINT_TO, "bibcard: ERROR in line_nr \n");
							exit(ERROR);
						}
						j++;
					}

				} else {
					/* AND */
					k = 0;
					for (j = 0; j < total; j++) {
						if (line_nr[k] == j) {
							k++;
						} else {
							found_flag[j] = FALSE;
						}
					}
				}
			}
		}

		free((char *) line_nr);

		ref = first_item;

		if (find_connect == 0) {
			/* AND */
			for (find_index = 0; find_index < total; find_index++, ref = ref->next) {
				if (found_flag[find_index]) {
					/* year in range ? */
					if ((ref->field[year_id]) && (strlen(ref->field[year_id]) > 0)) {
						if (find_string[0])
							if (strlen(find_string[0]) > 0) {
								SET_STR(find_source[0], ref->field[year_id]);
								if (find_source[0][0] == ABBREVCODE)
									find_source[0]++;
								if (strcmp(find_string[0], find_source[0]) > 0)
									found_flag[find_index] = FALSE;
							}
						if (find_string[1])
							if (strlen(find_string[1]) > 0) {
								SET_STR(find_source[0], ref->field[year_id]);
								if (find_source[0][0] == ABBREVCODE)
									find_source[0]++;
								if (strcmp(find_string[1], find_source[0]) < 0)
									found_flag[find_index] = FALSE;
							}
					} else {
						if ((!ref->field[year_id]) && ((strlen(find_string[0]) > 0) || (strlen(find_string[1]) > 0)))
							found_flag[find_index] = FALSE;
					}

					/* all types ? */
					if (find_ref_type != NUM_OF_REF_TYPES)
						if (strcmp(ref_types_show_fct[find_ref_type].ref_type_token, ref->ref_type) != NULL)
							found_flag[find_index] = FALSE;

				}
				if (found_flag[find_index]) {
					if (first == -1) {
						first = find_index;
						first_found = ref;
					}
					if ( (total <= max_total_for_list) && (select_in_list == 1) ) {
					  xv_set(Bc_list_popup->list_popup_list, PANEL_LIST_SELECT, find_index, TRUE, PANEL_PAINT, PANEL_NONE, NULL);
					}
#ifdef PRINT_FIND_NUM
					if (found_flag[find_index])
						find_count++;
#endif
				}
			}

		} else {
			/* OR */
			for (find_index = 0; find_index < total; find_index++, ref = ref->next) {
				if (!found_flag[find_index]) {
					/* year in range ? */
					if ((strlen(find_string[0]) > 0) && (ref->field[year_id]) && (strlen(ref->field[year_id]) > 0)) {
						SET_STR(find_source[0], ref->field[year_id]);
						if (find_source[0][0] == ABBREVCODE)
							find_source[0]++;
						if ((strcmp(find_string[0], find_source[0]) <= 0) && (strcmp(find_string[1], find_source[0]) >= 0))
							found_flag[find_index] = TRUE;
					}
					/* all types ? */
					if (find_ref_type != NUM_OF_REF_TYPES)
						if (strcmp(ref_types_show_fct[find_ref_type].ref_type_token, ref->ref_type) == NULL)
							found_flag[find_index] = TRUE;
				}
				if (found_flag[find_index]) {
					if (first == -1) {
						first = find_index;
						first_found = ref;
					}
					if ( (total <= max_total_for_list) && (select_in_list == 1) ) {
					  xv_set(Bc_list_popup->list_popup_list,
						 PANEL_LIST_SELECT, find_index, TRUE, PANEL_PAINT, PANEL_NONE, NULL);
					}
#ifdef PRINT_FIND_NUM
					if (found_flag[find_index])
						find_count++;
#endif
				}
			}
		}
	}


	if (first != -1) {
		show_selected_pos = first;
		current_item = first_found;
		show_current_item();
		xv_set(Bc_find_popup->find_popup_next_button, XV_SHOW, TRUE, NULL);
		xv_set(Bc_find_popup->find_popup_previous_button, XV_SHOW, TRUE, NULL);

#ifdef PRINT_FIND_NUM
		sprintf(message, "Total:%4d    Found:%4d", total, find_count);
		xv_set(Bc_find_popup->find_popup, FRAME_LEFT_FOOTER, message, NULL);
#endif

	} else {
		xv_set(Bc_find_popup->find_popup, FRAME_LEFT_FOOTER, "Not Found", NULL);
		xv_set(Bc_find_popup->find_popup_next_button, XV_SHOW, FALSE, NULL);
		xv_set(Bc_find_popup->find_popup_previous_button, XV_SHOW, FALSE, NULL);
	}

	free((char *) find_string);
	xv_set(Bc_find_popup->find_popup, FRAME_BUSY, FALSE, NULL);
	do_title();
}




extern void
show_next_in_list()
{
  int             i, j;
  int             nItems = (int) xv_get(Bc_list_popup->list_popup_list, PANEL_LIST_NROWS);
  
  if ( (int) xv_get(Bc_list_popup->list_popup_list, XV_SHOW, NULL) == TRUE) {
    for (i = show_selected_pos + 1; i < nItems; i++) {
      if ((int) xv_get(Bc_list_popup->list_popup_list, PANEL_LIST_SELECTED, i)) {
	current_item = first_item;
	show_selected_pos = i;
	for (j = 0; j < i; j++) {
	  current_item = current_item->next;
	}
	show_current_item();
	break;
      }
    }
  } else {
    if (mod_for_find_flag == FALSE) {
      for (i = show_selected_pos + 1; i < total; i++) {
	if (found_flag[i]) {
	  current_item = first_item;
	  show_selected_pos = i;
	  for (j = 0; j < i; j++) {
	    current_item = current_item->next;
	  }
	  show_current_item();
	  break;
	}
      }
    } else {
      notice_prompt(Bc_base_window->base_window_controls, NULL,
		    NOTICE_MESSAGE_STRINGS,
		    "No find or",
		    "Changed since last find!",
		    NULL,
		    NOTICE_BUTTON_YES, "Continue",
		    NULL);
    }
  }
}




extern void
  show_previous_in_list()
{
  int             i, j;
  int             nItems = (int) xv_get(Bc_list_popup->list_popup_list, PANEL_LIST_NROWS);
  
  
  if ( (int) xv_get(Bc_list_popup->list_popup_list, XV_SHOW, NULL) == TRUE) {
    for (i = show_selected_pos - 1; i > -1; i--) {
      if ((int) xv_get(Bc_list_popup->list_popup_list, PANEL_LIST_SELECTED, i)) {
	current_item = first_item;
	show_selected_pos = i;
	for (j = 0; j < i; j++) {
	  current_item = current_item->next;
	}
	show_current_item();
	break;
      }
    }
    
  } else {
    if (mod_for_find_flag == FALSE) {
      for (i = show_selected_pos - 1; i > -1; i--) {
	if (found_flag[i]) {
	  current_item = first_item;
	  show_selected_pos = i;
	  for (j = 0; j < i; j++) {
	    current_item = current_item->next;
	  }
	  show_current_item();
	  break;
	}
      }
    } else {
      notice_prompt(Bc_base_window->base_window_controls, NULL,
		    NOTICE_MESSAGE_STRINGS,
		    "No find or",
		    "Changed since last find!",
		    NULL,
		    NOTICE_BUTTON_YES, "Continue",
		    NULL);
    }
  } 
}






extern void
sort()
{
	Ref             temp, prev;
	sort_count = sort_old_val = 0;
	get_total();

	xv_set(Bc_sort_popup->sort_popup_gauge, PANEL_VALUE, NULL, XV_SHOW, TRUE, NULL);
	panel_paint(Bc_sort_popup->sort_popup_gauge, PANEL_NO_CLEAR);
	XFlush((Display *) xv_get(Bc_sort_popup->sort_popup, XV_DISPLAY));

	temp = merge_sort(first_item);
	if (temp) {
		first_item = temp;
		first_item->prev = NULL;
		temp = temp->next;
		prev = first_item;
	}
	while (temp) {
		temp->prev = prev;
		prev = temp;
		temp = temp->next;
	}

	if (prev)
		last_item = prev;
	else
		last_item = first_item;

	current_item = first_item;
	show_current_item();
	xv_set(Bc_sort_popup->sort_popup_gauge, XV_SHOW, FALSE, NULL);
	if (update_flag == UPDATE_ON) 
	  update_cite_list();
	mod_flag = TRUE;
	do_title();
}



extern void
next_item()
{
	if (current_item->next == NULL)
		current_item = first_item;
	else
		current_item = current_item->next;
	show_current_item();
}



extern void
prev_item()
{
	if (current_item->prev == NULL)
		current_item = last_item;
	else
		current_item = current_item->prev;
	show_current_item();
}



extern void
show_cite(key)
	char           *key;

{
	Ref             ref;

	show_selected_pos = 0;
	ref = first_item;

	while (ref) {
		if (ref->field[citekey_id])
			if (strcmp(key, ref->field[citekey_id]) == NULL) {
				current_item = ref;
				show_current_item();
				break;
			}
		ref = ref->next;
		show_selected_pos++;
	}
}
