/*
 * Title: storage.c
 * Author: Jed Marti KI7NNP
 * Description: Storage allocation. There are two types that get allocated dynamically but we 
 *   statically garbage collect the results - they are used by the millions.
 * Revision History: (Created Tue Jan 24 07:08:42 2023)
 */


#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

#include "equations.h"
#include "indequ.h"

// Keep track of results that have been freed and can be used again.
result *FreeResults = NULL;



anInductor *newInductor(void)
/*     Create a new measured inductor. These are read once during startup and stored for 
 *   eternety.
 * Parameters: none
 * External References: none
 * Returned values: an empty one.
 * Errors detected: Out of space causes a halt.
 */
{
  anInductor *i;

  if ((i = (anInductor*) malloc(sizeof(anInductor))) == NULL)
  {
    fprintf(stderr, "Out of space for anInductor\n");
    exit(-1);
  }

  memset(i, 0, sizeof(anInductor));
  return i;
}



result *newResult(void)
/*     Create a new (or reuse an old) result - this is the polynomial coefficients and the
 *   goodness rating for a set of inductors.
 * Parameters: none
 * External References:
 *   FreeResults: A list of those returned from service. Use these instead of malloc.
 * Returned value: A zeroed out structure.
 * Errors detected: Out of space causes halt.
 */
{
  result *r;

  // Use an old one, detach from free list.
  if (FreeResults)
  {
    r = FreeResults;
    FreeResults = r->next;
  }

  // Otherwise, create a new one.
  else if ((r = (result*) malloc(sizeof(result))) == NULL)
  {
    fprintf(stderr, "Out of space for result\n");
    exit(-1);
  }

  // Clear and return.
  memset(r, 0, sizeof(result));
  return r;
}



void copyResult(result *to, result *from)
{
  memcpy(to, from, sizeof(result));
}



result *cloneResult(result *r)
{
  result *n;

  // Use an old one, detach from free list.
  if (FreeResults)
  {
    n = FreeResults;
    FreeResults = n->next;
  }

  // Otherwise, create a new one.
  else if ((n = (result*) malloc(sizeof(result))) == NULL)
  {
    fprintf(stderr, "Out of space for result\n");
    exit(-1);
  }

  memcpy(n, r, sizeof(result));
  n->next = NULL;
  return n;
}


void freeResult(result *r)
/*     When a result is crappy and not in the best, return it to the free list so it can be used
 *   again.
 * Parameters:
 *   r: A result to free up.
 * External References:
 *   FreeResults: A list of those returned from service. Use these instead of malloc.
 * Returned values: none
 * Errors detected: none
 */
{
  r->next = FreeResults;
  FreeResults = r;
}



void writeResult(result *r, FILE *fh)
/*     Write a result to a file - temporary as a way to communicate with controlling process.
 * Parameters:
 *   r: Result to write.
 *   fh: File to write to.
 * External References: none
 * Returned values: none
 * Errors detected: none - assumes no problem writing a fiole.
 */
{
  size_t rc;
  rc = fwrite(r, sizeof(result), 1, fh);
  ASSERT(rc == 1);
}


result *readResult(FILE *fh)
/*     We have an open file, read a result from it and return. 
 * Parameters:
 *   fh: file handle of open file.
 * External References: none
 * Returned values: returns the new result or NULL if EOF is reached.
 * Errors detected: none
 */
{
  result *r;
  size_t n;
  r = newResult();
  if ((n = fread(r, sizeof(result), 1, fh)) != 1)
  {
    free(r);
    return NULL;
  }
  return r;
}



// EOF
