/* stringHistory.c */

#include "stringHistory.h"


/* Create an empty string history on the heap.
 * !! Constraint:            maxStringCount >= 2, not enforced,
 *                            not tested
 * Params:
 *   int maxStringCount      the maximum number of strings
 *                            in this queue
 * Return:
 *   void
 */
StringHistory *createStringHistory(int maxStringCount) {
 // Allocate memory for StringHistory:
  StringHistory *strHist = (StringHistory *)malloc(sizeof(StringHistory));
  if (!strHist) {
    onErrorOutOfMemory();
    return NULL;
  }

  // Initialize members:
  strHist->nextStringCount = 0;
  strHist->maxStringCount = maxStringCount;
  strHist->string = NULL;
  return strHist;
}



/* Empty the string history.
 * Params:
 *   StringHistory *strHist  pointer to string history
 * Return:
 *   void
 */
void clearStringHistory(StringHistory *strHist) {
  int i;
  if (!strHist) {
    onNullPointer();
    return;
  }

  // Release all char arrays:
  for (i = 0; i < strHist->nextStringCount; ++i) {
    free(*(strHist->string + i));
  }

  // Release pointer array to arrays of char:
  free(strHist->string);

  // Reflect new situation in changing the members:
  strHist->string = NULL;
  strHist->nextStringCount = 0;
}



/* Add a string to the string history.
 * Params:
 *   StringHistory *strHist  pointer to string history
 *   char *str               pointer to string to be added
 * Return:
 *   int                     true if successful, else false with
 *                            history unchanged
 */
int addStringHistory(StringHistory *strHist, char *str) {
  char *s;
  char **ss;

  if (!strHist) {
    onNullPointer();
    return 0;
  }

  // History full (fifo behaviour)?
  if (strHist->nextStringCount == strHist->maxStringCount) {
    int i;

  // Reallocate memory for new string and copy:
  s = (char *)realloc(*(strHist->string), (strlen(str) + 1) * sizeof(char));
  if (!s) {
    onErrorOutOfMemory();
    return 0;
  }
  strcpy(s, str);

    // Copy pointers towards index 0:
    for (i = 1; i < strHist->maxStringCount; i++) {
      *(strHist->string + i - 1) = *(strHist->string + i);
    }

    // Initialize pointer with highest index:
    *(strHist->string + strHist->maxStringCount - 1) = s;
    return 1;
  }

  // History is growing, enlarge array for another pointer:
  ss = (char **)realloc(
    strHist->string, (strHist->nextStringCount + 1) * sizeof(char *));
  if (!ss) {
    onErrorOutOfMemory();
    return 0;
  }
  strHist->string = ss;

 s = (char *)malloc((strlen(str) + 1) * sizeof(char));
 if (!s) {
  onErrorOutOfMemory();
  return 0;
 }
 strcpy(s, str);

  // Initialize pointer with currently highest index:
  *(strHist->string + strHist->nextStringCount) = s;
  strHist->nextStringCount++;
  return 1;
}



/* Set the new maxStringCount of the string history. If necessary
 * discard oldest strings.
 * !! Constraint:            maxStringCount >= 2, not enforced,
 *                            not tested
 * Params:
 *   StringHistory *strHist  pointer to string history
 *   int maxStringCount      new maximum number of strings in this queue
 * Return:
 *   void
 */
void setStringCount(StringHistory *strHist, int maxStringCount) {
  if (!strHist) {
    onNullPointer();
    return;
  }

  if (strHist->nextStringCount > maxStringCount) {
    // Go and discard oldest entries:
    int i;
    int diff = strHist->nextStringCount - maxStringCount;

    // Release oldest string/s:
    for (i = 0; i < diff; ++i) {
      free(*(strHist->string + i));
    }

    // Copy pointers towards index 0:
    for (i = diff; i < strHist->nextStringCount; i++) {
      *(strHist->string + i - diff) = *(strHist->string + i);
    }

    // Reallocate for a smaller pointer array:
    strHist->string = (char **)realloc(
      strHist->string, maxStringCount * sizeof(char *));

    // Adjust member:
    strHist->nextStringCount = maxStringCount;
  }

  // New count:
  strHist->maxStringCount = maxStringCount;
}



/* Release heap memory used by the string history.
 * Params:
 *   StringHistory *strHist  pointer to string history
 * Return:
 *   void
 */
void deleteStringHistory(StringHistory *strHist) {
  if (!strHist) {
    onNullPointer();
    return;
  }

  // Release all strings:
  clearStringHistory(strHist);

  // Release the history itself:
  free(strHist);
}



/* Clone the string history. Perform a deep copy on the heap.
 * Params:
 *   StringHistory *strHist  pointer to source string history
 * Return:
 *   StringHistory *         pointer to new string history
 */
StringHistory *cloneStringHistory(StringHistory *strHist) {
  int i;
  StringHistory *cloneHist;
  if (!strHist) {
    onNullPointer();
    return NULL;
  }

 // Allocate memory for clone:
  cloneHist = createStringHistory(strHist->maxStringCount);
  if (!cloneHist) {
    // onErrorOutOfMemory() handled in createStringHistory above
  return NULL;
 }

  // Add all available strings:
  for (i = 0; i < strHist->nextStringCount; ++i) {
    if (!addStringHistory(cloneHist, *(strHist->string + i))) {
      // onErrorOutOfMemory() handled in addStringHistory above
    clearStringHistory(strHist);
    free(cloneHist);
    return NULL;
  }
  }

  return cloneHist;
}



/*
 * Print all the strings in the history to stdout, the first line
 * designating the oldest entry, the last line the youngest.
 * *strHist         - pointer to string history
 */
void printStringHistory(StringHistory *strHist) {
  int i;

  if (!strHist) {
    onNullPointer();
    return;
  }

  printf("String history; maxStringCount: %i\n", strHist->maxStringCount);

  if (strHist->nextStringCount == 0) {
    printf("empty\n");
  }
  else {
    for (i = 0; i < strHist->nextStringCount; ++i) {
      printf("%i: %s\n", i + 1, *(strHist->string + i));
    }
  }
  puts("");
}
