#include <stdio.h>
#include <string.h>
#include <starlet.h>
#include <str$routines.h>
#include <strdef.h>
#include <stdlib.h>
#include <descrip.h>
#include "bboard.h"

struct note_log {
    char conf_name[40]; 		/* Name of the conference (not list) */
    long close_date;			/* Last possible date of posting */
    SYSTIM last_post;			/* Last time list was posted to */
};

static int search_log_file(FILE * i, struct note_log * ent, char * conf,
    int case_sense);
static sort_log_file(void);
static int log_compare(struct note_log * x, struct note_log * y);

/* Figure out if we need a new topic since we're at the beginning of an
    interval */

void fondle_note_log_file(FILE * out, char interval, char * conf, char * hdr)
{
    struct note_log file_entry; 	/* Need one of our own */

    SYSTIM cur_time;			/* Now - begin of period */
    struct $NUMTIM start_time;		/* Now - begin of period */
    SYSTIM end_time;			/* Later - end of period */
    struct $NUMTIM time;		/* Later - end of period */
    FILE * note_log_file;		/* Where our info gets stuffed */
    long cur_date;			/* Temporary date value */

    static char * month_list[] = { "January", "February", "March", "April",
	"May", "June", "July", "August", "September", "October", "November",
	"December" };

    /* Setup */

    get_time(cur_time); 		/* When are we now? */
    get_numtim(&start_time, cur_time);	/* Full format, please */

    /* Open the file in append mode */

    note_log_file = fopen(log_file.dsc$a_pointer, "a+");

    /* See if it already exists */

    if (!search_log_file(note_log_file, &file_entry, conf, TRUE)) {
	memset(&file_entry, 0, sizeof(struct note_log));    /* Zap it */
	strcpy(file_entry.conf_name, conf);	/* Save the conf name */
	goto fondle_note_log_file_new_topic;	/* We know that it's new */
    }

#ifdef DEBUG
    printf("fondle_note_log_file: Processing for %s\n", file_entry.conf_name);
#endif

    /* What's today's date? */

    cur_date = (long) (start_time.year * 10000L) +
	    (long) (start_time.month * 100L) + (long) (start_time.day);

    /* How does that compare to the last posting date? */

    if (cur_date <= file_entry.close_date) {
#ifdef DEBUG
	printf("fondle_note_log_file: Updating last posting date\n");
#endif
	memcpy(file_entry.last_post, cur_time, sizeof (SYSTIM));
	fwrite(&file_entry, sizeof(struct note_log), 1, note_log_file);
	fclose(note_log_file);		    /* Just close the info file */
	return; 			    /* And run away */
    }

    /* We need a new topic */

fondle_note_log_file_new_topic:

    /* Get the first and last dates of the interval */

    start_end_time(interval, cur_time, end_time);

    /* Convert close date to NUMTIM for use */

    get_numtim(&time, end_time);

    /* Save the info */

    file_entry.close_date = (long) (time.year * 10000L) +
	    (long) (time.month * 100L) + (long) (time.day);

    /* Write it back to the log file */

    fwrite(&file_entry, sizeof(struct note_log), 1, note_log_file);
    fclose(note_log_file);

    /* Before doing anything else, make sure the log file is sorted... */

    sort_log_file();

    /* Now let's fondle inside NOTES */

#ifdef DEBUG
    printf("fondle_note_log_file: Building new topic commands\n");
#endif

    if (setuname_used) {
	fputs("$ setuname 'oldname'\n", out);
    }

    fprintf(out, "$ notes/nonotebook 0::%s\n", conf);
    fputs("set moderator\n", out);

    /* The topic is written by BBOARD itself */

    fputs("set prof/temp/pers=\"Notes Poster Daemon\"\n", out);
    fputs("write/noedit nl:\n", out);

    /* Now let's set up the subject of the new topic */

    fprintf(out, "%s Postings", hdr);

    if (interval == 'w' || interval == 'W') {

	/* Weekly get start and end dates */

	get_numtim(&start_time, cur_time);
	fprintf(out, " for %02d/%02d/%02d - %02d/%02d/%02d",
		start_time.month, start_time.day, start_time.year % 100,
		time.month, time.day, time.year % 100);

    } else if (interval == 'm' || interval == 'M') {

	/* Monthly just get month and year */

	fprintf(out, " for %s, %04d", month_list[time.month-1], time.year);
    }

    /* Yes, we want the note entered */

    fputs("\nyes\n", out);

    /* And it's time to get out of NOTES again */

    fputs("exit\n", out);

    return;
}

/* Reset a particular entry in the log file */

void reset_log_file_entry(char * conf, char * node, char * user)
{
    struct note_log cur;		/* current entry */
    FILE * logf;			/* log file itself */

    /* Play with the conference name */

    scrunch(conf);

    /* Did they want a wild card mayhap? */

    if (strchr(conf, '*')) {
	send_msg(node, user, "Not allowed to RESET wildcarded names.");
	return;
    }

    /* Need to open the file */

    logf = fopen(log_file.dsc$a_pointer, "a+");

    /* Now let's see if we can find what they're talking about */

#ifdef DEBUG
    printf("reset_log_file_entry: About to search for %s\n", conf);
#endif

    if (!search_log_file(logf, &cur, conf, FALSE)) {

	/* Not found. Tell them that it didn't work */

	sprintf(temp, "Unable to find conference '%s'.", conf);
	send_msg(node, user, temp);

	/* Close the file */

	fclose(logf);

	/* And just go away */

	return;
    }

    /* Ok. So let's just zap the close date back to zero. That'll do it */

#ifdef DEBUG
    printf("reset_log_file_entry: Okay to zap %s\n", conf);
#endif

    cur.close_date = 0L;
    fwrite(&cur, sizeof(struct note_log), 1, logf);
    fclose(logf);

    /* Tell them about it */

    sprintf(temp, "I '%s' reset.", conf);
    send_msg(node, user, temp+2);

    /* Also log the event */

    send_log_file(temp);
}

/* Display info on a conference to a user */

void display_log_file_entry(char * conf, char * node, char * user)
{
    struct note_log cur;		/* Current entry */
    struct dsc$descriptor_s pat;	/* Pattern (passed to us) */
    char temp_conf[40]; 		/* For uppercasing name */
    struct dsc$descriptor_s cand;	/* Candidate (from entry) */
    FILE * logf;
    int found_any;
    static char time_str[24];		/* For when we started */
    static struct dsc$descriptor_s time_buf =
	{ 23, DSC$K_DTYPE_T, DSC$K_CLASS_S, &time_str };
    int time_len;			/* How long is returned string? */

    static char * mon_list[] = {
	"JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP",
	"OCT", "NOV", "DEC"
    };

    /* Setup */

    found_any = FALSE;

    /* Play with the conference name */

    scrunch(conf);

    /* And shove it into a descriptor */

    str_desc(&pat, conf);

    /* Need to open the file */

    logf = fopen(log_file.dsc$a_pointer, "a+");

    /* And jump to the beginning */

    rewind(logf);

    /* Now let's start searching through */

#ifdef DEBUG
    printf("display_log_file_entry: About to search for >%s<\n", conf);
#endif

    while (TRUE) {

	/* Read the next record */

	if (!fread(&cur, sizeof(struct note_log), 1, logf)) {
	    break;			/* EOF */
	}

	/* Let's fondle the conference name */

	strcpy(temp_conf, cur.conf_name);
	strupr(temp_conf);

#ifdef DEBUG
	printf("display_log_file_entry: current conf: >%s<\n", temp_conf);
#endif

	/* Now build a descriptor of it */

	str_desc(&cand, temp_conf);

	/* Try for a match */

	if (str$match_wild(&cand, &pat) == STR$_NOMATCH) {
	    continue;
	}

	/* Got a match. Say something about it */

	found_any = TRUE;

	/* Format the outgoing message */

	if (cur.close_date) {
	    sprintf(temp, "     close:       %02d-%s-%4d",
		    (int) (cur.close_date % 100),
		    mon_list[(int) ((cur.close_date / 100) % 100) - 1],
		    (int) (cur.close_date / 10000L));
	} else {
	    sprintf(temp, "     close:       conference RESET", cur.conf_name);
	}

	strcpy(temp+256, "     last posted: ");

	if (cur.last_post[0] || cur.last_post[1]) {

	    /* Format the time that we started */

	    sys$asctim(&time_len, &time_buf, cur.last_post, 0);

	    /* Chop off the trailing hundredths of a second (silly) */

	    time_str[20] = '\0';

	    /* Now tack on the rest of the message */

	    strcat(temp+256, time_str);
	} else {
	    strcat(temp+256, "N/A");
	}

	/* Finally we get to tell them */

	send_msg(node, user, cur.conf_name);
	send_msg(node, user, temp);
	send_msg(node, user, temp+256);
    }

    /* Did we tell them ANYTHING? */

    if (!found_any) {
	sprintf(temp, "No matches found for '%s'", conf);
	send_msg(node, user, temp);
    }

    /* Remember to close the file, please */

    fclose(logf);
}

/* Sort the log file whenever there are any additions */

static sort_log_file(void)
{
    struct note_log * log_entries;
    struct note_log temp_ent;
    FILE * log_f;
    int num_items;

    log_f = fopen(log_file.dsc$a_pointer, "r");

    for (num_items = 0; ; num_items++) {
	if (!fread(&temp_ent, sizeof(struct note_log), 1, log_f)) {
	    break;
	}
    }

    rewind(log_f);

    log_entries = (struct note_log *) xmalloc(num_items *
	    sizeof(struct note_log));

    fread(log_entries, sizeof(struct note_log), num_items, log_f);

    fclose(log_f);

    qsort(log_entries, num_items, sizeof(struct note_log), log_compare);

    log_f = fopen(log_file.dsc$a_pointer, "w");

    fwrite(log_entries, sizeof(struct note_log), num_items, log_f);

    fclose(log_f);

    xfree(log_entries);
}

/* Compare two log_file entries */

static int log_compare(struct note_log * x, struct note_log * y)
{
    return(strcmp(x->conf_name, y->conf_name));
}

/* Search through until we find the conference name, or fall off the end */

static int search_log_file(FILE * i, struct note_log * ent, char * conf,
    int case_sense)
{
    fpos_t cur_pos;			/* For backing up */
    char temp_conf[40]; 		/* In case we need to upper-case */
    int match_made;			/* Did the names match */

    /* Start looking at the beginning */

    rewind(i);

    /* Let's scan through until we find the conference name */

    while (TRUE) {

	/* Save where we are in case we find it */

	fgetpos(i, &cur_pos);

	/* Read next record */

	if (!fread(ent, sizeof(struct note_log), 1, i)) {
	    ent->conf_name[0] = '\0';   /* EOF, not found */
	    return (FALSE);		/* That'll flag that it wasn't found */
	}

	/* If we're not being case sensitive, copy and uppercase the name */

	if (!case_sense) {
	    strcpy(temp_conf, ent->conf_name);
	    strupr(temp_conf);
	    match_made = !strcmp(temp_conf, conf);
	} else {
	    match_made = !strcmp(ent->conf_name, conf);
	}

	/* Check if we have a winner */

	if (match_made) {
	    fsetpos(i, &cur_pos);	/* Yup, back up for updating */
	    return (TRUE);		/* We found it... */
	}
    }
}
