#include "HTUtils.h"
#include "tcp.h"
#include "LYUtils.h"
#include "LYStrings.h"
#include "LYGlobalDefs.h"
#include "LYJump.h"
#include "LYKeymap.h"
#include "LYSignal.h"

#include "LYLeaks.h"

#ifdef VMS
#include <fab.h>
#endif /* VMS */

typedef struct _JumpDatum {
    char *key;
    char *url;
} JumpDatum;

PRIVATE int LYCompare PARAMS ((CONST void *e1, CONST void *e2));
PRIVATE unsigned LYRead_Jumpfile PARAMS ((JumpDatum **tpp));

PUBLIC char *LYJump NOARGS
{
    static BOOL firsttime = TRUE;
    JumpDatum seeking;
    static JumpDatum *table;
    JumpDatum *found;
    static unsigned nel;
    static char buf[120];
    char *bp;

    if (firsttime) {
	nel = LYRead_Jumpfile(&table);
	firsttime = FALSE;
    }
    if (nel == 0) {
        if(jumpfile)
	    free(jumpfile);
	return (jumpfile=NULL);
    }

    statusline("Jump to (use '?' for list): ");
    if (!jump_buffer)
        *buf = '\0';
    if (LYgetstr(buf, VISIBLE) == -1)
        return NULL;
    bp = buf;
    if (toupper(*key_for_func(LYK_JUMP)) == 'G' && strncmp(buf, "o ", 2) == 0)
	bp++;
    while (isspace(*bp))
	bp++;
    if (*bp == '\0')
        return NULL;
    seeking.key = bp;
    found = (JumpDatum *)bsearch((char *)&seeking, (char *)table,
				 nel, sizeof(JumpDatum), LYCompare);
    if (!found) {
	char msg[120];

	sprintf(msg, "Unknown target `%s'", buf);
	statusline(msg);
	sleep(2);
    }

    return found ? found->url : NULL;
}

PRIVATE unsigned LYRead_Jumpfile ARGS1(JumpDatum **,tpp)
{
    struct stat st;
    unsigned int nel;
    char *mp;
    int fd;
#ifdef VMS
    FILE *fp;
    BOOL IsStream_LF = TRUE;
#endif /* VMS */
    char *cp;
    int i;

    if (jumpfile == NULL || *jumpfile == '\0')
	return 0;
    if (stat(jumpfile, &st) < 0) {
        statusline("Cannot locate jump file");
	sleep(2);
	return 0;
    }
	
    /* allocate storage to read entire file */
    if ((mp=(char *)calloc(1, st.st_size + 1)) == NULL) {
        statusline("Out of memory reading jump file");
	sleep(2);
	return 0;
    }

#ifdef VMS
    if (st.st_fab_rfm != (char)FAB$C_STMLF) {
        /** It's a record-oriented file. **/
        IsStream_LF = FALSE;
        if ((fp = fopen(jumpfile, "r", "mbc=32")) == NULL) {
            statusline("Cannot open jump file");
	    sleep(2);
	    free(mp);
	    return 0;
	}
    } else
    if ((fd=open(jumpfile, O_RDONLY, "mbc=32")) < 0) {
#else
    if ((fd=open(jumpfile, O_RDONLY)) < 0) {
#endif /* VMS */
        statusline("Cannot open jump file");
	sleep(2);
	free(mp);
	return 0;
    }

#ifdef VMS
    if (IsStream_LF) {
    /** Handle as a stream. **/
#endif /* VMS */
    if (read(fd, mp, st.st_size) < st.st_size) {
	statusline("Error reading jump file");
	sleep(2);
	return 0;
    }
    mp[st.st_size] = '\0';
    close(fd);
#ifdef VMS
    } else {
    /** Handle as a series of records. **/
    if(fgets(mp, 1024, fp) == NULL) {
	statusline("Error reading jump file");
	sleep(2);
	return 0;
    } else
	while(fgets(mp+strlen(mp), 1024, fp) != NULL) ;
    fclose(fp);
    }
#endif /* VMS */

    /* quick scan for approximate number of entries */
    nel = 0;
    cp = mp;
    while((cp = strchr(cp, '\n')) != NULL) {
	nel++;
	cp++;
    }

    *tpp = (JumpDatum *)malloc(nel * sizeof(JumpDatum));
    if (*tpp == NULL) {
	statusline("Out of memory for jump table");
	sleep(2);
	free(mp);
	return 0;
    }

    cp = mp;
    for (i = 0; i < nel; ) {
	if (strncmp(cp, "<!--", 4) == 0 || strncmp(cp, "<dl>", 4) == 0) {
	    cp = strchr(cp, '\n');
	    if (cp == NULL)
	        break;
	    cp++;
	    continue;
	}
	cp = LYstrstr(cp, "<dt>");
	if (cp == NULL)
	    break;
	cp += 4;
	(*tpp)[i].key = cp;
	cp = LYstrstr(cp, "<dd>");
	if (cp == NULL)
	    break;
	*cp = '\0';
	cp += 4;
	cp = LYstrstr(cp, "href=\"");
	if (cp == NULL)
	    break;
	cp += 6;
	(*tpp)[i].url = cp;
	cp = strchr(cp, '"');
	if (cp == NULL)
	    break;
	*cp = '\0';
	cp++;
	cp = strchr(cp, '\n');
	if (cp == NULL)
	    break;
	cp++;
	i++;
	if (!cp)
	    break;
    }

    return i;
}

PRIVATE int LYCompare ARGS2 (CONST void *, e1, CONST void *, e2)
{
    return strcasecomp(((JumpDatum *)e1)->key, ((JumpDatum *)e2)->key);
}
