/*
 * Copyright 2011 Steven Gribble
 *
 *  This file is part of the UW CSE 333 course project sequence
 *  (333proj).
 *
 *  333proj is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  333proj is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with 333proj.  If not, see <http://www.gnu.org/licenses/>.
 */

// Lecture 10 exercise 2

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

#include "sort.h"

// This declares comparator function we pass in to
// our sort routines.
static int IntComparator(void *el1, void *el2);

// This function reads a file into memory and returns
// a pointer to the allocated memory buffer.
static unsigned char *ReadFile(char *fname, int *retlen);

// Converts the string to an int array, and returns a
// pointer to the allocated int array.
static int *StringToIntArray(unsigned char *filecontent, int *arrlen);

#define BUBBLESORT 0
#define QUICKSORT 1
static void SortFile(char *fname, int whichsort);

// Reads the file in, converts to int array, bubblesorts, frees
// all of the resources.
static void BubbleSortFile(char *fname) {
  SortFile(fname, BUBBLESORT);
}

// Reads the file in, converts to int array, quicksorts, frees
// all of the resources.
static void QuickSortFile(char *fname) {
  SortFile(fname, QUICKSORT);
}

int main(int argc, char **argv) {
  if (argc != 2)
    return EXIT_FAILURE;

  printf("Running quicksort on '%s'\n", argv[1]);
  QuickSortFile(argv[1]);

  printf("Running bubblesort on '%s'; this may take a while.\n", argv[1]);
  BubbleSortFile(argv[1]);

  printf("Done!\n");
  return EXIT_SUCCESS;
}

static int IntComparator(void *el1, void *el2) {
  int *i1 = (int *) el1;
  int *i2 = (int *) el2;

  if (*i1 > *i2)
    return 1;
  if (*i1 == *i2)
    return 0;
  return -1;
}

#define READSIZE 1000
static unsigned char *ReadFile(char *fname, int *retlen) {
  unsigned char *buf = NULL;
  FILE *f;
  int readlen, count = 0;

  // Open up the file.
  f = fopen(fname, "rb");
  if (f == NULL)
    return NULL;

  // Slurp in the file, READSIZE bytes at a time.
  buf = (unsigned char *) realloc(buf, READSIZE + 1);
  assert(buf != NULL);
  while ((readlen = fread(buf+count, 1, READSIZE, f)) > 0) {
    count += readlen;
    buf = (unsigned char *) realloc(buf, count + READSIZE + 1);
    assert(buf != NULL);
  }

  // Did we break because of an error?
  if (ferror(f)) {
    // Yes, so clean up and arrange to return NULL.
    free(buf);
    buf = NULL;
    count = 0;
  }

  // Clean up, null terminate, return.
  fclose(f);
  buf[count] = '\0';
  *retlen = count;
  return buf;
}

static int *StringToIntArray(unsigned char *filecontent, int *arrlen) {
  int count = 0;
  int *retarray = NULL;
  char *nexttok = NULL;

  // Start by using strtok ("man strtok") to get the first newline-
  // separated token.
  nexttok = strtok((char *) filecontent, "\n");

  // Then, loop through, converting the previously found token to
  // an integer, growing the array, and adding it.  After this,
  // look for the next token.
  while(nexttok != NULL) {
    int nextint = 0;

    // Convert the line to an integer, growing the array to store it.
    retarray = (int *) realloc(retarray, sizeof(int) * (count + 1));
    assert(retarray != NULL);
    assert(sscanf(nexttok, "%d", &nextint) == 1);
    retarray[count] = nextint;
    count++;

    // Look for the next token.
    nexttok = strtok(NULL, "\n");
  }

  // Done! Return the array and count.
  *arrlen = count;
  return retarray;
}

static void SortFile(char *fname, int whichsort) {
  unsigned char *filecontent = NULL;
  int *intarray = NULL;
  int arrlen = 0, filelen = 0;

  // Read in the file.
  filecontent = ReadFile(fname, &filelen);
  if (filecontent == NULL) {
    fprintf(stderr, "Readfile returned empty content.\n");
    exit(EXIT_FAILURE);
  }

  // Convert to an int array.
  intarray = StringToIntArray(filecontent, &arrlen);
  free(filecontent);
  if (intarray == NULL) {
    fprintf(stderr, "StringToIntArray returned empty array.\n");
    exit(EXIT_FAILURE);
  }

  // Sort in place.
  if (whichsort == QUICKSORT) {
    QuickSort(intarray, arrlen, sizeof(int), &IntComparator);
  } else {
    BubbleSort(intarray, arrlen, sizeof(int), &IntComparator);
  }

  // Clean up.
  free(intarray);
}