/* diskbank.c   14-12-93  disk genebank manager for the Tierra Simulator */
/* Tierra Simulator V4.1: Copyright (c) 1991, 1992, 1993 */
/*  Tom Ray & Virtual Life */

#ifndef lint
static char sccsid[] = "@(#)diskbank.c	1.0        7/21/92";

#endif

#include "license.h"
#include "tierra.h"
#include "extern.h"
#include <errno.h>
#include <sys/types.h>
#ifdef unix
#include <dirent.h>
#endif               /* unix */
#ifdef __TURBOC__
#include <dir.h>
#include <dos.h>
#define d_name ff_name
#endif               /* __TURBOC__ */

#ifdef MEM_CHK
#include <memcheck.h>
#endif

void Inject(g, size, sad, tol, disk, rrpi)
FpInst  g;     /* pointer to genome */
I32s    size;  /* size of genome */
I32s    sad;   /* suggested address for placement of genome */
I32s    tol;   /* tolerance placement of genome */
I32s    disk;  /* 1 = this genome comes from the disk */
float   *rrpi; /* reap rand prop for injection */
{   float   tReapRndProp = ReapRndProp;
    I32s    j, k;
    Pcells  ce;
    FpInst  si;

#ifdef CM5
    I32u    GBPN ;
    int	    i ;
    char    buf[5000] ;
    int     flag ;
#endif

    ce = GetFreeCell();   /* get a cell structure */

    ce->ld = 1;
    ce->d.gen.size = ce->mm.s = size;
    ReapRndProp = *rrpi;   /* allocate the needed memory */
    while ((ce->mm.p = MemAlloc(size, sad, tol)) < 0)
        reaper(1,sad);
    ReapRndProp = tReapRndProp;
    si = ce->d.genome = soup + ce->mm.p;
    for (j = 0; j < ce->c.n; j++)
        ce->c.c[j].ip = ce->mm.p;

    if (ce == &cells[0][2])
    {   ce->q.p_reap = TopDummy->q.this;
        ce->q.n_reap = BottomDummy->q.this;
        TopDummy->q.n_reap = ce->q.this;
        BottomDummy->q.p_reap = ce->q.this;
    }
    else
    {   EntBotSlicer(ce);
        EntBotReaper(ce);
    }
    ce->d.is = 1;

    for (j = 0; j < size; j++, si++) /* put genome in soup */
#if PLOIDY == 1
        si[0] = mo(g[j], InstNum);
#else  /* PLOIDY == 1 */
        for (k = 0; k < PLOIDY; k++)
            si[0][k] = mo(g[j][k], InstNum);
#endif /* PLOIDY == 1 */

    if (GeneBnker) /* determine genotype, record in genebanker */
    {   
        ce->d.hash = Hash(ce->d.gen.size,ce->d.genome) ;  /* new hash due to mutation */
#ifndef CM5
        CheckGenotype(&(ce->d), 21);    /* check .gen files */
        ce->d.parent = sl[size]->g[ce->d.gi]->parent;
#else
      GBPN = hashGB(ce->d.hash) ;
      bcopy(&(ce->d),buf,sizeof(ce->d)) ;
      bcopy(ce->d.genome,&buf[ALLIGN(ce->d)],ce->d.gen.size) ;
      flag = CMMD_send_and_receive(GBPN,
				   CMMD_ANY_TAG,
				   &(ce->d.gi),
				   sizeof(ce->d.gi),
				   GBPN,
				   CMMD_CheckGenotype_TAG + 21 + (1 << 10) + (1 << 11),
				   buf,
				   ALLIGN(ce->d) + ce->d.gen.size) ;
      /* now implement ce->d.parent = sl[size]->g[ce->d.gi]->parent via message passing */
      CMMD_receive(GBPN,
		   CMMD_ANY_TAG,
		   &(ce->d.parent),
		   sizeof(ce->d.parent)) ;
#endif

        strcpy(ce->d.gen.label, Int2Lbl(ce->d.gi));

/* replace SizGen = DivGenBook(NULL, ce, InstExe, reaped, 0, 0, disk); */

#ifndef CM5
	DivGenBook(ce, InstExe, reaped, 0, 0, disk);
#else
	GBPN = hashGB(ce->d.hash) ;
	CMMD_send_block(GBPN,
			CMMD_DivGenBook_NC_TAG + ((disk << 1) & 1) + (reaped & 1),
			ce,
			sizeof(struct cell)) ;
#endif

    }
    OutDisk((I32s) 'b', ce);
    LastDiv = InstExe;
#if FRONTEND != STDIO
    FEStats();
#endif /* FRONTEND != STDIO */

}

void InjectFromBank(crit, sad, tol)
    I8s     *crit;
    I32s    sad;   /* suggested address for placement of genome */
    I32s    tol;   /* tolerance placement of genome */
{
    float  rrpi = 1;
    I32s   size;
    GList  *g;

    g = GetAGen(crit);
    sscanf(crit, "%4ld", &size);
    Inject(g->genome, size, sad, tol, 1, &rrpi);
    FreeGen(g,0);
}

void FreeGen(g,qr)
    GList  *g;
    I32s   qr;  /* flag to call qr_rem */
{   
   if (!g) return;
   if (g->genome)
           {   tfree(g->genome);
               g->genome = NULL;
           }
   if (g->gbits)
           {   tfree(g->gbits);
               g->gbits = NULL;
           }
   if (qr) gq_rem(g);
   tfree(g);
   g = NULL;
}	/* end of FreeGen */

GList * GetAGen(crit)
    I8s     *crit;
{
    I32s   size;
    I16s   n;
    GList  *g;
    char   cpath[128], gen[4];
    FILE   *fp;
    head_t head;
    indx_t *indx, *tindx, gindx;

    sscanf(crit, "%4ld%3s", &size, gen);
    sprintf(cpath, "%s%04ld.gen", GenebankPath, size);
    if (!(fp = open_ar(cpath, size, GFormat, 0)))
    {   FEError(-1306,EXIT,NOWRITE,
            "Tierra InjectFromBank() unable to open genome file %s\n",cpath);
    }
    head = read_head(fp);
#ifdef __TURBOC__
    indx = &gindx;
    n = find_gen(fp, indx, gen, head.n);
    tindx = indx;
#else  /* __TURBOC__ */
    indx = read_indx(fp, &head);
    n = find_gen(fp, indx, gen, head.n);
    tindx = &indx[n];
#endif /* __TURBOC__ */
    g = get_gen(fp, &head, tindx, n);
    fclose(fp);
#ifndef __TURBOC__
    if (indx)
    {   thfree(indx);
        indx = NULL;
    }
#endif  /* __TURBOC__ */
    return g;
}

void extract(ce)
Pcells ce;
{   Pgl g;
    FILE *fp;
    head_t head;
    indx_t *indx, gindx;

#ifdef CM5
    char        *extract_buf ;
    ExtractMsg  *extract_msg ;
#endif

#ifdef CM5
    struct gb_hash_entry *new_gb_hash_entry ;
#endif /* CM5 */

    if (!GeneBnker)
        return;
    isolate = 0;

#ifdef IBM3090
    sprintf(Buff, "%04ld.gen.d", ce->d.gen.size);
#else
    sprintf(Buff, "%s%04ld.gen", GenebankPath, ce->d.gen.size);
#endif

    g = sl[ce->d.gen.size]->g[ce->d.gi];

    sprintf(ExtrG, "%04ld%s @ %ld", g->gen.size, g->gen.label, g->pop);

#ifndef CM5
#if FRONTEND == STDIO
    sprintf(mes[0], "extract: %s", ExtrG);
    FEMessage(1);
#else /* FRONTEND == STDIO */
    if (Log) fprintf(tfp_log, "ex = %s\n", ExtrG);
#endif /* FRONTEND == STDIO */
/* open an archive, if it does not exist, create it */
    if (!(fp = open_ar(Buff, ce->d.gen.size, GFormat, -1)))
    {   FEError(-200,EXIT,NOWRITE,
            "Tierra extract() Unable to open extract file %s",Buff);
    }
    head = read_head(fp);
#ifdef __TURBOC__
    indx = &gindx;
#else  /* __TURBOC__ */
    indx = read_indx(fp, &head);
#endif /* __TURBOC__ */
    add_gen(fp, &head, &indx, g);
#ifndef __TURBOC__
    if (indx)
    {   thfree(indx);
        indx = NULL;
    }
#endif /* __TURBOC__ */
    fclose(fp);
#else /* CM5 */

    /* on the cm5, extraction happens on the front end, so we need to
       send this info (after putting it into a structure for sending) */

    /* allocated space for the structure to be sent */
    extract_buf = (char *) malloc(sizeof(ExtractMsg) + ce->d.gen.size *  (sizeof(Instruction) + sizeof(GenBits))) ;
    extract_msg = (ExtractMsg *) extract_buf ;

    /* put the genome info in the structure */
    extract_msg->g = *g ;
    strcpy(extract_msg->ExtrG,ExtrG) ;
    strcpy(extract_msg->Buff,Buff) ;
    extract_msg->size = ce->d.gen.size ;

    /* now copy the instructions into the structure */
    extract_msg->g.genome = (FpInst) (extract_buf + sizeof(ExtractMsg)) ;
    memcpy(extract_msg->g.genome, g->genome, ce->d.gen.size * sizeof(Instruction)) ;

    /* now copy the gbits into the structure */
    extract_msg->g.gbits = (FpGenB) (extract_buf + sizeof(ExtractMsg) + ce->d.gen.size * sizeof(Instruction)) ;
    memcpy(extract_msg->g.gbits, g->gbits, ce->d.gen.size * sizeof(GenBits)) ;

    CMMD_send_noblock(CMMD_host_node(),
		      EXTRACT_tag,
		      extract_msg,
		      sizeof(ExtractMsg) + ce->d.gen.size * (sizeof(Instruction) + sizeof(GenBits))) ;

    tfree(extract_buf) ;

#endif /* CM5 */

#ifdef CM5

    /* now put the extracted genome's hash value in the list of genebank hash values */

    new_gb_hash_entry = (struct gb_hash_entry *) malloc(sizeof(struct gb_hash_entry)) ;

    new_gb_hash_entry->hash = ce->d.hash ;
    new_gb_hash_entry->next = gb_hash_list ;

    gb_hash_list = new_gb_hash_entry ;
#endif /* CM5 */
  
    NumGenDG++;

}
