/*
 * saveload.c : Device-independent routines for writing (ie printing),
 *	saving, and restoring the browser contents.
 *
 * George Ferguson, ferguson@cs.rochester.edu, 23 Apr 1993.
 */
#include <stdio.h>
#include "sysdefs.h"
#include "stringdefs.h"
#include "pfs.h"
#include "pprot.h"
#include "xtypes.h"
#include "db.h"
#include "query.h"
#include "browser.h"
#include "settings.h"
#include "types.h"
#include "appres.h"
#include "alert.h"
#include "status.h"

/*
 * Functions defined here
 */
int save(),load(),writeToFile();

static void writeEntry(),saveEntry();

/*	-	-	-	-	-	-	-	-	*/
/*
 * Save browser contents to FILENAME for later load.
 */
int
save(db,filename)
DbEntry *db;
char *filename;
{
    FILE *fp;
    DbEntry *hostp,*locp,*filep;

    if ((fp=fopen(filename,"w")) == NULL) {
	alert1("Can't open %s for writing",filename);
	return(0);
    }
    status1("Saving to %s...",filename);
    /* Save the settinsg first */
    fprintf(fp,"archieHost: %s\n",appResources.archieHost);
    fprintf(fp,"searchType: %s\n",searchTypeToString(appResources.searchType));
    fprintf(fp,"sortType: %s\n",sortTypeToString(appResources.sortType));
    fprintf(fp,"niceLevel: %d\n",appResources.niceLevel);
    fprintf(fp,"maxHits: %d\n",appResources.maxHits);
    fprintf(fp,"timeout: %d\n",appResources.timeout);
    fprintf(fp,"retries: %d\n",appResources.retries);
    /* Now dump the browser */
    for (hostp=db->entries; hostp != NULL; hostp = hostp->next)
	for (locp=hostp->entries; locp != NULL; locp = locp->next)
	    for (filep=locp->entries; filep != NULL; filep=filep->next)
		saveEntry(fp,filep);
    fclose(fp);
    status0("Ready");
    return(1);
}

static void
saveEntry(fp,dbp)
FILE *fp;
DbEntry *dbp;
{
    VLINK vl;
    DbEntry *entry;

    /* Sanity check */
    if ((vl=dbp->vlink) == NULL) {
	fprintf(stderr,"NULL vlink to save()\n");
	return;
    }
    /* Save the vlink info */
    fprintf(fp,"LINK %c %s '%s' %s %s %s %s %d %d ", vl->linktype,
	    vl->type, vl->name, vl->hosttype, vl->host, 
	    vl->nametype, vl->filename, vl->version,
	    vl->f_magic_no);
    /* And the relevant attributes */
    fprintf(fp,"%d ",dbp->size);
    fprintf(fp,"%s ",dbp->modes);
    fprintf(fp,"%s",dbp->gt_date);
#ifdef undef
    /* When we didn't keep gt_date (now needed for sorting), we used this: */
    for (ap = vl->lattrib; ap; ap = ap->next)
	if (strcmp(ap->aname,"LAST-MODIFIED") == 0)
	    fprintf(fp,"%s",ap->value.ascii);
#endif
    fprintf(fp,"\n");
    /* Recursively save the sub-entries */
    for (entry=dbp->entries; entry != NULL; entry=entry->next)
	saveEntry(fp,entry);
}

/*
 * Load browser from FILENAME made by save.
 */
int
load(db,filename)
DbEntry *db;
char *filename;
{
    FILE *fp;
    char buf[256];
    VLINK first_link,last_link,cur_link;
    PATTRIB cur_at;
    char l_linktype;
    char l_name[MAX_DIR_LINESIZE];
    char l_type[MAX_DIR_LINESIZE];
    char l_htype[MAX_DIR_LINESIZE];
    char l_host[MAX_DIR_LINESIZE];
    char l_ntype[MAX_DIR_LINESIZE];
    char l_fname[MAX_DIR_LINESIZE];
    int	tmp;

    if ((fp=fopen(filename,"r")) == NULL) {
	alert1("Can't open %s for reading",filename);
	return(0);
    }
    status1("Loading from %s...",filename);
    /* Load the settings */
    if (fscanf(fp,"archieHost: %s\n",appResources.archieHost) < 1 ||
	fscanf(fp,"searchType: %s\n",buf) < 1 ||
	(appResources.searchType=stringToSearchType(buf)) == GfError ||
	fscanf(fp,"sortType: %s\n",buf) < 1 ||
	(appResources.sortType=stringToSortType(buf)) == GfError ||
	fscanf(fp,"niceLevel: %d\n",&(appResources.niceLevel)) < 1 ||
	fscanf(fp,"maxHits: %d\n",&(appResources.maxHits)) < 1 ||
	fscanf(fp,"timeout: %d\n",&(appResources.timeout)) < 1 ||
	fscanf(fp,"retries: %d\n",&(appResources.retries)) < 1) {
	fclose(fp);
	alert1("Error in header of file \"%s\"!",filename);
	return(0);
    } else {
	reinitSettings();
    }
    /* Load the browser */
    first_link = last_link = NULL;
    while (!feof(fp)) {
	/* Get a new vlink */
	cur_link = vlalloc();
	/* Read the vlink fields */
	tmp = fscanf(fp,"LINK %c %s %s %s %s %s %s %d %d", &l_linktype,
		     l_type, l_name, l_htype, l_host, 
		     l_ntype, l_fname, &(cur_link->version),
		     &(cur_link->f_magic_no));
	if (tmp != 9) {
	    alert1("Load error in file %s!",filename);
	    vlfree(cur_link);
	    break;
	}
	/* Store data in vlink */
	cur_link->linktype = l_linktype;
	cur_link->type = stcopyr(l_type,cur_link->type);
	cur_link->name = stcopyr(unquote(l_name),cur_link->name);
	cur_link->hosttype = stcopyr(l_htype,cur_link->hosttype);
	cur_link->host = stcopyr(l_host,cur_link->host);
	cur_link->nametype = stcopyr(l_ntype,cur_link->nametype);
	cur_link->filename = stcopyr(l_fname,cur_link->filename);
	/* Add vlink to chain */
	if (first_link == NULL) {
	    last_link = first_link = cur_link;
	    cur_link->next = cur_link->previous = NULL;
	} else {
	    last_link->next = cur_link;
	    cur_link->previous = last_link;
	    cur_link->next = NULL;
	    last_link = cur_link;
	}
	/* Read the attributes */
	tmp = fscanf(fp,"%s %s %s\n",l_name,l_type,l_htype);
	if (tmp != 3) {
	    alert1("Load error in file %s!",filename);
	    break;
	}
	/* Put them in the vlink's attribute list */
	cur_link->lattrib = cur_at = atalloc();
	cur_at->aname = stcopyr("SIZE",cur_at->aname);
	cur_at->avtype = stcopyr("ASCII",cur_at->avtype);
	cur_at->value.ascii = stcopyr(l_name,cur_at->value.ascii);
	cur_at->next = atalloc();
	cur_at->next->previous = cur_at;
	cur_at = cur_at->next;
	cur_at->aname = stcopyr("UNIX-MODES",cur_at->aname);
	cur_at->avtype = stcopyr("ASCII",cur_at->avtype);
	cur_at->value.ascii = stcopyr(l_type,cur_at->value.ascii);
	cur_at->next = atalloc();
	cur_at->next->previous = cur_at;
	cur_at = cur_at->next;
	cur_at->aname = stcopyr("LAST-MODIFIED",cur_at->aname);
	cur_at->avtype = stcopyr("ASCII",cur_at->avtype);
	cur_at->value.ascii = stcopyr(l_htype,cur_at->value.ascii);
    }
    fclose(fp);
    if (first_link == NULL) {
	status0("No entries loaded!");
	return(0);
    }
    status0("Parsing...");
    resetBrowser();
    clearEntries(db);
    tmp = parseArchieQueryResults(db,first_link,NULL);
    displayEntries(db,0);
    status2("Loaded %d entries from \"%s\"",(char *)tmp,filename);
    return(1);
}

/*	-	-	-	-	-	-	-	-	*/
/*
 * Write browser contents to FILENAME. If ONELINE is True, each entry gets
 *	whole line.
 */
int
writeToFile(db,filename,oneline)
DbEntry *db;
char *filename;
int oneline;
{
    FILE *fp;
    DbEntry *hostp,*locp,*filep;
    char *prefix;

    if ((fp=fopen(filename,"w")) == NULL) {
	alert1("Can't open %s for writing",filename);
	return(0);
    }
    status1("Writing to %s...",filename);
    if (oneline) {
	for (hostp=db->entries; hostp != NULL; hostp = hostp->next)
	    for (locp=hostp->entries; locp != NULL; locp = locp->next)
		for (filep=locp->entries; filep != NULL; filep=filep->next) {
		    prefix = malloc(strlen(hostp->name)+strlen(locp->name)+3);
		    sprintf(prefix,"%s:%s/",hostp->name,locp->name);
		    writeEntry(fp,filep,oneline,prefix);
		    free(prefix);
		}
    } else {
	for (hostp=db->entries; hostp != NULL; hostp = hostp->next) {
	    fprintf(fp,"%s\n",hostp->name);
	    for (locp=hostp->entries; locp != NULL; locp = locp->next) {
		fprintf(fp,"\t%s\n",locp->name);
		for (filep=locp->entries; filep != NULL; filep=filep->next)
		    writeEntry(fp,filep,oneline,"");
	    }
	}
    }
    fclose(fp);
    status0("Ready");
    return(1);
}

static void
writeEntry(fp,filep,oneline,prefix)
FILE *fp;
DbEntry *filep;
int oneline;
char *prefix;
{
    DbEntry *entry;
    char *newprefix;

    /* Write this entry */
    if (oneline) {
	fprintf(fp,"%s %10d  %12s  %s%s\n",
		filep->modes,filep->size,filep->date,prefix,filep->name);
    } else {
	fprintf(fp,"\t\t%s %10d  %12s  %s%s\n",
		filep->modes,filep->size,filep->date,prefix,filep->name);
    }
    /* Add this entry to the prefix */
    newprefix = malloc(strlen(prefix)+strlen(filep->name)+2);
    sprintf(newprefix,"%s%s/",prefix,filep->name);
    /* Recursively write the sub-entries */
    for (entry=filep->entries; entry != NULL; entry=entry->next)
	writeEntry(fp,entry,oneline,newprefix);
    free(newprefix);
}
