/*
 * Demonstrates how to use a function pointer when calling qsort.
 * 
 * The comparison functions follow the signature requirements for
 * bsearch and qsort from stdlib.h.
 *
 * Author: Zach Tomaszewski
 */

#include <stdio.h>
#include <stdlib.h>

/*
 * Sorting two ints in increasing order.
 *
 * Given pointers to two ints, returns a negative value if left
 * is less than right, a positive value if left is greater than
 * right, or 0 if the two are equal.
 */
int increasing(const void* left, const void* right) {
  // there's a subtraction trick to do this in one line, but
  // it runs the risk of int overflow.
  
  //convert from void* so we can dereference
  const int* lhs = (int*) left;
  const int* rhs = (int*) right;
  
  if (*lhs < *rhs) {
    return -1;
  }else if (*lhs > *rhs) {
    return 1;
  }else {
    return 0;
  }    
}

/*
 * Sorts two ints in decreasing order.
 *
 * Given pointers to two ints, returns a negative value if left
 * is greather than right, a positive value if left is less than
 * right, or 0 if the two are equal.
 */
int decreasing(const void* left, const void* right) {
  // efficient coding; less efficient runtime
  return -increasing(left, right);
}

/*
 * Sorts two ints so that odds come before evens.
 *
 * Given pointers to two ints, returns a negative value if left
 * is odd and right is even, a positive value if left is even
 * and right is odd, or 0 if both are even or both are odd.
 */
int oddsBeforeEvens(const void* left, const void* right) {
  //convert from void* so we can dereference
  const int* lhs = (int*) left;
  const int* rhs = (int*) right;

  if (*lhs % 2 == *rhs % 2) {
    //both odd or both even, so secondary sort by value
    return increasing(left, right);
  }else if (*lhs % 2 == 1) {
    //left is odd, so come first
    return -1;
  }else {
    return 1;
  }  
}


/*
 * Prints an array of ints to the screen.
 * Ends the line when done.
 */
void print(int array[], int size) {
  int i;
  printf("[");
  for (i = 0; i < size; i++) {
    printf("%d", array[i]);
    if (i < size - 1) printf(" ");
  }
  puts("]");
}


/*
 * Creates an array of ints, prints it, and then sorts it a few
 * different ways, printing it each time.
 */
int main() {
  int nums[] = {3, 5, 7, 1, 9, 2, -6, 14, -10};
  int size = sizeof(nums) / sizeof(int);
  
  printf("Original:\n");
  print(nums, size);
  
  printf("Increasing:\n");
  qsort(nums, size, sizeof(int), increasing);
  print(nums, size);

  printf("Decreasing:\n");
  qsort(nums, size, sizeof(int), decreasing);
  print(nums, size);
  
  printf("Odds before evens:\n");
  qsort(nums, size, sizeof(int), &oddsBeforeEvens);
  print(nums, size);
}

