/*
 *	$Source$
 *	$Author$
 *	$Header$
 */

#ifndef lint
static char *rcsid_verse_c = "$Header$";
#endif lint

#include <stdio.h>
#include <strings.h>
#include <string.h>
#include <sys/types.h>
#include <ctype.h>
#include "bible.h"

print_verse_cite(v)
	VERSE	*v;
{
	printf("%s %d:%d", v->bk->name, v->c, v->v);
}

free_verse(v)
	VERSE	*v;
{
	if (v->s)
		free(v->s);
	free(v);
}

VERSE	*alloc_verse()
{
	VERSE	*v;

	if ((v = (struct verse *) malloc(sizeof(VERSE))) == NULL) {
		fflush(stdout);
		fprintf(stderr, "Out of memory in parse_verse!\n");
		abort();
	}
	return(v);
}


VERSE *parse_verse(line)
	char	*line;
{
	char	*cp;
	register char	*book_name;
	int	i, chapter, verse;
	BOOK	*b = NULL;
	VERSE	*v = NULL;
	char	*tmp;
	
	tmp = cp = strdup(line);
	while (*cp && isspace(*cp))
		cp++;
	if (!(book_name = strtok(cp, " \n")))
		return(NULL);
	if (current_book &&
	    (!strcasecmp(book_name, current_book->name) ||
	     !strcasecmp(book_name, current_book->abbrev) ||
	     !strcasecmp(book_name, current_book->key)))
		b = current_book;
	else for (i = 0; i <NUMBOOKS; i++) 
		if (!strcasecmp(book_name, booktab[i].name) ||
		    !strcasecmp(book_name, booktab[i].abbrev) ||
		    !strcasecmp(book_name, booktab[i].key)) {
			b = &booktab[i];
			break;
		}
	if (!b)
		return(NULL);
	if (cp = strtok(NULL, ":\n")) {
		chapter = atoi(cp);
		if (cp = strtok(NULL, "")) {
			verse = atoi(cp);
			v = alloc_verse();
			v->bk = b;
			v->c = chapter;
			v->v = verse;
			v->s = 0;
			free(tmp);
			return(v);
		}
	}
	free(tmp);
	return(NULL);
}

/*
 * Try to find a given verse and fill its contents into the verse
 * structure.  If found, that verse becomes the current verse.
 * Otherwise, the current verse remains the same.
 */
lookup_verse(v)
	VERSE	*v;
{
	FILE	*f;
	int	high, low, mid, midptr;
	int	num = 0;
	char	buf[128];
	VERSE	*vbuf;
	
	if (v->s)
		return;		/* We're done */
	if (v->c > v->bk->numchap)
		return;		/* The chapter number is illegal */
	open_book(v->bk);
	f = v->bk->f;
	low = 0;
	fseek(f, 0, 2);
	high = ftell(f);
	while (1) {
#ifdef LOOKUP_VERSE_DEBUG
		printf("low = %d, high = %d\n", low, high);
#endif
		num++;
		if (high - low < 256)
			mid = low;
		else 
			mid = (high+low) / 2;
		fseek(f, mid, 0);
		while (1) {
			midptr = ftell(f);
			if (!fgets(buf, sizeof(buf), f)) {
				return;	/* Hit EOF, we failed */
			}
#ifdef LOOKUP_VERSE_DEBUG
			fputs(buf, stdout);
#endif
			if (buf[0] == '\037')
				break;
		}
		if (midptr > high) {
			high = mid;
			continue;
		}
		buf[sizeof(buf)-1] = '\0';
		if (!(vbuf = parse_verse(buf+1)))
			errout("Bad verse citation found in lookup_verse");
#ifdef LOOKUP_VERSE_DEBUG
		printf("Mid = ");
		print_verse_cite(vbuf);
		printf("\n");
#endif
		if (vbuf->c == v->c) {
			if (vbuf->v == v->v)
				break;
			else if (vbuf->v < v->v)
				low = ftell(f);
			else
				high = mid;
		} else {
			if (vbuf->c < v->c)
				low = ftell(f);
			else
				high = mid;
		}
		free_verse(vbuf);
		if (high <= low)
			return;
	}
#ifdef LOOKUP_VERSE_DEBUG
	printf("%d interations used\n", num);
#endif
	v->bk->current_pos = midptr;
	if (fseek(f, midptr, 0)) {
		perror("lookup_verse: fseek");
		abort();
	}
	read_verse(f, v);
}

VERSE *goto_rel_verse(offset)
	int	offset;
{
	register BOOK	*b = current_book;
	FILE	*f;
	VERSE	*v = NULL;
	char	buf[1024];
	int	new_pos;

	if (!b)
		return(NULL);	/* No current book */
	if (offset <= 0)
		return(NULL);	/* Not implemeneted yet */
	open_book(b);
	f = b->f;
	if (fseek(f, b->current_pos+1, 0)) {
		perror("lookup_verse: fseek");
		abort();
	}
	while (offset > 0) {
		new_pos = ftell(f);
		if (!fgets(buf, sizeof(buf), f)) {
			return(NULL);	/* Hit EOF, we failed */
		}
		if (buf[0] == '\037')
			offset--;
	}
	b->current_pos = new_pos;
	if (fseek(f, new_pos, 0)) {
		perror("lookup_verse: fseek");
		abort();
	}
	if (!(v = parse_verse(buf+1)))
		errout("Bad verse parsed in goto_rel_verse");
	read_verse(b->f, v);
	return(v);
}


VERSE *read_verse(f, v)
	FILE	*f;
	VERSE	*v;
{
	char	*lines[64];	/* 64 lines for one verse?!? */
	int	i, num = 0, size = 0;
	register char	*cp, *dp;
	
	fgets(tmp, sizeof(tmp), f);
	cp = tmp;
	if (*cp != '\037') {
		fprintf(stderr, "Programming error in read_verse...\n");
		fprintf(stderr, "Not positioned correctly;  Contact help!\n");
		abort();
	}
	if (!v) {
		v = parse_verse(tmp+1);
		if (!v)
			problem();
	}
	cp = index(cp, ':');
	if (!cp)
		problem();
	while (*cp && *cp != ' ') cp++;
	while (*cp && *cp == ' ') cp++;
	if (!*cp)
		problem();
	lines[num++] = strdup(cp);
	size = strlen(cp);
	while (!feof(f)) {
		fgets(tmp, sizeof(tmp), f);
		if (tmp[0] == '\n')
			break;
		lines[num++] = strdup(tmp);
		size += strlen(tmp);
	}
	cp = malloc(size+1);
	*cp = '\n';
	for (i=0; i <num; i++) {
		if (dp = index(cp, '\n'))
			*dp = '\0';
		strcat(cp, lines[i]);
		free(lines[i]);
	}
	v->s = cp;
	return(v);
}

problem()
{
	fflush(stdout);
	fprintf(stderr, "There is a problem with the database!!!!\n");
	fprintf(stderr, "Contact help!\n");
	fflush(stderr);
	abort();
}	
	
