#include "data.table.h"

// from good ol' Numerical Recipes in C

static inline void iswap(int *a, int *b)           { int     tmp = *a; *a = *b; *b = tmp; }
static inline void dswap(double *a, double *b)     { double  tmp = *a; *a = *b; *b = tmp; }
static inline void i64swap(int64_t *a, int64_t *b) { int64_t tmp = *a; *a = *b; *b = tmp; }

#undef BODY
#define BODY(SWAP)                          \
  if (n == 0) return NA_REAL;               \
  int med = n / 2 - (n % 2 == 0);           \
  unsigned long ir = n - 1, l = 0;          \
  for(;;) {                                 \
    if (ir <= l + 1) {                      \
      if (ir == l + 1 && x[ir] < x[l]) {    \
        SWAP(x + l, x + ir);                \
      }                                     \
      break;                                \
    } else {                                \
      unsigned long mid = (l + ir) >> 1;    \
      SWAP(x + mid, x + l + 1);             \
      if (x[l] > x[ir]) {                   \
        SWAP(x + l, x + ir);                \
      }                                     \
      if (x[l + 1] > x[ir]) {               \
        SWAP(x + l + 1, x + ir);            \
      }                                     \
      if (x[l] > x[l + 1]) {                \
        SWAP(x + l, x + l + 1);             \
      }                                     \
      unsigned long i = l + 1, j = ir;      \
      a = x[l + 1];                         \
      for (;;) {                            \
        do i++; while (x[i] < a);           \
        do j--; while (x[j] > a);           \
        if (j < i) break;                   \
          SWAP(x + i, x + j);               \
      }                                     \
      x[l + 1] = x[j];                      \
      x[j] = a;                             \
      if (j >= med) ir = j - 1;             \
      if (j <= med) l = i;                  \
    }                                       \
  }                                         \
  a = x[med];                               \
  if (n % 2 == 1) {                         \
    return (double)a;                       \
  } else {                                  \
    b = x[med + 1];                         \
    for (int i = med + 2; i < n; i++) {     \
      if (x[i] < b) b = x[i];               \
    }                                       \
    return ((double)a + (double)b) / 2.0;   \
  }

double dquickselect(double *x, int n)
{
  double a, b;
  BODY(dswap);
}

double iquickselect(int *x, int n)
{
  int a, b;
  BODY(iswap);
}

double i64quickselect(int64_t *x, int n)
{
  int64_t a, b;
  BODY(i64swap);
}
