/* File: sortlist.c

   Sort the items of a linked list using Mergesort.
*/

#include <assert.h>
#include <stdio.h>
#include <string.h>
#include "sortlist.h"


/* Type definitions. We are sorting pointers to nodes */

typedef node *data ;
typedef int index ;


/* Private functions */

static void merge(data *, index, index, index, index) ;
static void mergesort(data *, index, index) ;

/* Global variable temp must be allocated the same
   amount of space as the array to be sorted
*/

static data *temp ;

void SortList(list L) {
   index n, i ;
   data *A ;
   node *current ;
 
   n = L->count ;
   if (n == 0) return ;

   /* Allocate memory for sorting */
   temp = (data *) malloc(n * sizeof(data)) ;
   A = (data *) malloc(n * sizeof(data)) ;
   if (temp == NULL || A == NULL) {
      printf("Could allocate temporary space for sorting\n") ;
      exit(1) ;
   }

   /* Load list into an array */
   current = L->header.next ;
   i = 0 ;
   while(current != NULL) {
      A[i] = current ; 
      current = current->next ;
      i++ ;
   }

   mergesort(A, 0, n-1) ;

   /* Reconnect linked list */
   L->header.next = A[0] ;
   for(i = 0 ; i < n-1 ; i++) {
      A[i]->next = A[i+1] ;
   }
   A[n-1]->next = NULL ;

   free(A) ;
   free(temp) ;
}


static void merge(data *A, index low1, index high1, 
		  index low2, index high2) {
   index t, i1, i2 ;

   /* Sanity check */
   assert(low2 == high1 + 1) ;
  
   /* while there are elements in both halves, copy the lowest one */
   i1 = low1 ;
   i2 = low2 ;
   t = 0 ;
   while (i1 <= high1 && i2 <= high2) {
      if (strcmp(A[i1]->item,  A[i2]->item) < 0) {
         temp[t] = A[i1] ;
         i1++ ;
         t++ ;
      } else {
         temp[t] = A[i2] ;
         i2++ ;
         t++ ;
      }
   }

   /* copy any remaining elements */
   while (i1 <= high1) {
    temp[t] = A[i1] ;
    t++ ;
    i1++ ;
   }
   while (i2 <= high2) {
     temp[t] = A[i2] ;
     t++ ;
     i2++ ;
   }

   /* copy the now-sorted elements back into the original array */
   for (t = low1; t <= high2; t++) {
      A[t] = temp[t - low1] ;
   }
}


static void mergesort(data *A, index low, index high) {
  index mid ;
  
  if (low >= high) return ;
  
   mid = (low + high)/2 ;
   mergesort(A, low, mid) ;
   mergesort(A, mid + 1, high) ;
   
   merge(A, low, mid, mid + 1, high) ;
}

