/* 
 * sorter4.c - sort the lines from stdin
 *   (derived from sorter2.c)
 *   (linked list version instead of array)
 *
 * usage: sorter < infile
 * stdin: lines of text
 * stdout: lines of text, in arbitrary order.
 * 
 * David Kotz, April 2016, 2017, 2019, 2021
 * CS 50, Fall 2022
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include "readlinep.h"

// A structure for each node in linked list
struct listnode {
  char* line;
  struct listnode* next;
};

bool list_insert(struct listnode* headp, char* line);
struct listnode* listnode_new(char* line);

/* ******************* main ************************************** */
int main()
{
  struct listnode head = {NULL, NULL}; // dummy node at head of empty list
  int n = 0;                           // number of lines read

  // read the list of lines - any number of lines!
  while (!feof(stdin)) {
    char* line = readlinep();
    if (line != NULL) {
      if (list_insert(&head, line)) {
        n++; // only increment if no error
      }
    }
  }
  
  printf("%d lines:\n", n);
  // print the list of lines
  for (struct listnode* nodep = head.next; nodep != NULL; nodep = nodep->next)
    printf("%s\n", nodep->line);

  // here we are lazy and do not free the list. 

  exit(0);
}

/* ******************* list_insert ************************************** */
/* list_insert: insert the given line into the list.
 *
 * We assume:
 *   caller provides pointer to dummy list header node, 
 *   and a pointer 'line' to malloc'd string.
 * We return:
 *   true if success, false if failure for any reason.
 * We allocate:
 *   new listnode to hold the pointer 'line'.
 * Caller is responsible for:
 *   later free()ing the listnode.
 *   not otherwise deallocating the 'line' string.
 * Notes:
 *   The 'line' contents are *not* copied; the pointer is used in the list.
 */
bool
list_insert(struct listnode* headp, char* line) 
{
  struct listnode* nodep = listnode_new(line);

  if (headp == NULL || nodep == NULL) {
    return false;
  } else {
    // insert the new node at head of the list
    nodep->next = headp->next;
    headp->next = nodep;
  }
  return true;
}

/* ******************* listnode_new ************************************** */
/* listnode_new: create a new node to store the given line.
 * 
 * We assume:
 *   caller provides a pointer 'line' to malloc'd string.
 * We return:
 *   pointer to new node, if successful, else returns NULL.  
 * Caller is responsible for:
 *   later calling listnode_delete(nodep).
 * Notes:
 *   The 'line' contents are *not* copied; the pointer is used in the list.
 */
struct listnode* 
listnode_new(char* line) 
{
  // allocate memory for the new node
  struct listnode* nodep = malloc(sizeof(struct listnode));
  
  if (nodep == NULL) {
    return NULL;
  } else {
    // initialize node contents
    nodep->next = NULL;
    nodep->line = line;
  }

  return nodep;
}