#include  <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdlib.h>
#include "strsubs.h"  
#include "sortit.h"  
#include "vsubs.h"  

/** 
 a simple sort routine
 */

static double *ttt;
static int *ittt;
static int **pttt;
static int plen = 0;
static int *porder = NULL;

void
setorder (int *pp, int rlen)
{
  int *tt;

  if (plen > 0)
    {
      if (porder != NULL)
        free (porder);
    }

  if (pp == NULL)
    {
      porder = NULL;
      plen = rlen;
      return;
    }
  ZALLOC(porder, rlen, int);
  ZALLOC(tt, rlen, int);
  copyiarr (pp, tt, rlen);
  isortit (tt, porder, rlen);
  free (tt);
  plen = rlen;
}
double
median (double *aa, int len)
// should be O(len) algorithm
{
  double *b, y;
  int t, x, a, n;

  ZALLOC(b, len, double);
  n = 0;
  for (a = 0; a < len; ++a)
    {
      y = aa[a];
      if (isfinite(y))
        {
          b[n] = y;
          ++n;
        }
    }
  if (n == 0)
    fatalx ("(median) no valids\n");
  if (n == 1)
    return b[0];
  if (n == 2)
    return 0.5 * (b[0] + b[1]);
  sortit (b, NULL, n);
  t = n % 2;
  x = n / 2;
  y = b[x];
  if (t == 0)
    y = 0.5 * (b[x] + b[x - 1]);

  free (b);
//  printf("zzmed: %d %d %d %9.3f\n", len, n, x, y) ;
  return y;

}
void
sortit (double *a, int *ind, int len)
{
  int i, k;
  int *inda;

  if (len == 0)
    fatalx ("(sortit) len = 0\n");
  ZALLOC(ttt, len, double);
  ZALLOC(inda, len, int);

  for (i = 0; i < len; i++)
    {
      inda[i] = i;
    }

  copyarr (a, ttt, len);
  qsort ((int *) inda, len, sizeof(int), (int
  (*) (const void *, const void *)) compit);

  for (i = 0; i < len; i++)
    {
      k = inda[i];
      a[i] = ttt[k];
    }
  free (ttt);
  if (ind != NULL)
    copyiarr (inda, ind, len);
  free (inda);
}

int
compit (int *a1, int *a2)
{
  if (ttt[*a1] < ttt[*a2])
    return -1;
  if (ttt[*a1] > ttt[*a2])
    return 1;
  return 0;
}

void
isortit (int *a, int *ind, int len)
{
  int i, k;
  int *inda;

  if (len == 0)
    fatalx ("(isortit) len = 0\n");
  ZALLOC(ittt, len, int);
  ZALLOC(inda, len, int);

  for (i = 0; i < len; i++)
    {
      inda[i] = i;
    }

  copyiarr (a, ittt, len);
  qsort ((int *) inda, len, sizeof(int), (int
  (*) (const void *, const void *)) icompit);

  for (i = 0; i < len; i++)
    {
      k = inda[i];
      a[i] = ittt[k];
    }
  free (ittt);
  if (ind != NULL)
    copyiarr (inda, ind, len);
  free (inda);
}

int
icompit (int *a1, int *a2)
{
  if (ittt[*a1] < ittt[*a2])
    return -1;
  if (ittt[*a1] > ittt[*a2])
    return 1;
  return 0;
}

void
invperm (int *a, int *b, int n)
{
  /** 
   a, b can be same 
   */
  int i, j;
  int *x;

  if (n == 0)
    return;
  ZALLOC(x, n, int);

  ivclear (x, -1, n);
  for (i = 0; i < n; i++)
    {
      j = b[i];
      x[j] = i;
    }
  copyiarr (x, a, n);
  free (x);
}

void
ipsortit (int **a, int *ind, int len, int rlen)
{
  ipsortitp (a, ind, len, rlen, NULL);

}
void
ipsortitp (int **a, int *ind, int len, int rlen, int *order)
/** 
 sort integer array pointers 
 rows of array are sorted in lexicographical order 

 compiarr can be called outside the sort
 */
{
  int i, k;
  int *inda;

  if (len == 0)
    fatalx ("(ipsortit) len = 0\n");
  ZALLOC(pttt, len, int *);
  ZALLOC(inda, len, int);

  setorder (order, rlen); // order defines order as sorted in ascending order.  

  for (i = 0; i < len; i++)
    {
      if (a[i] == NULL)
        fatalx ("(ipsortit) array pointer %d NULL\n", i);
      inda[i] = i;
    }

  copyiparr (a, pttt, len);
  qsort ((int *) inda, len, sizeof(int), (int
  (*) (const void *, const void *)) ipcompit);

  for (i = 0; i < len; i++)
    {
      k = inda[i];
      a[i] = pttt[k];
    }
  if (ind != NULL)
    copyiarr (inda, ind, len);
  free (inda);
  free (pttt);
}

int
ipcompit (int *a1, int *a2)
{
  int l;
  l = compiarr (pttt[*a1], pttt[*a2], plen);
  return l;
}

int
compiarr (int *a, int *b, int len)
{
  int i, k;
  for (i = 0; i < len; i++)
    {
      k = i;
      if (porder != NULL)
        k = porder[i];
      if (a[k] < b[k])
        return -1;
      if (a[k] > b[k])
        return 1;
    }
  return 0;
}

