#ifndef RADIXSORT_H
 #define RADIXSORT_H

#include "stablesort.h"


//////////////////////////////////////////////////////////
// Radix Sort
//////////////////////////////////////////////////////////


_pair share_radix_sort_channel(_ a_, int channel)
{
  if (_party >  2) {
    _pair ans = {NULL, NULL};
    return ans;
  }
  _ a = _dup(a_);
//  _ pi = Perm_ID(a);
  int w = blog(a->n-1)+1;
  _ pi = Perm_ID2(a->n, 1<<w);
  share_t q = a->q;
//  share_t qb = order(a);
//  share_t qb = 1<<w;
  for (int k=1; k<q; k*=2) {
    // printf("k %d q %d\n", k, q);
//    printf("a "); _print(a);
//    _pair tmp = share_A2QB(a, q/k, qb);
//    printf("old bits "); _print(tmp2.y);
//    printf("old q    "); _print(tmp2.x);
//    _check(a);
    _pair tmp = share_A2QB_channel(a, q/k, 2, channel);
//    printf("new bits "); _print(tmp.y);
//    printf("new q    "); _print(tmp.x);
    //_ sigma = StableSort(tmp.y);
//    printf("bits "); _print(tmp.y);
//    _ sigma = StableSort(tmp.y);
      _ sigma = StableSort2_channel(tmp.y, channel);
//    printf("sigma "); _print(sigma);
    if (tmp.x->q > 1) {
      _move_(a, AppInvPerm_channel(tmp.x, sigma, channel));
    }
    _free(tmp.x);
    _free(tmp.y);
    _move_(pi, AppInvPerm_channel(pi, sigma, channel));
    _free(sigma);
  }
  _free(a);
  _ x = AppPerm_channel(a_, pi, channel);
  _pair ans = {x, pi};
  return ans;
}

//_pair share_radix_sort(_ a_)
//{
//  share_radix_sort_channel(a_, 0);
//}

/////////////////////////////////////////////////////////////////////
// 改良版 (2023-07-21)
/////////////////////////////////////////////////////////////////////
_pair share_radix_sort_channel2(_ a_, int channel)
{
  if (_party >  2) {
    _pair ans = {NULL, NULL};
    return ans;
  }
  _ a = _dup(a_);
//  _ pi = Perm_ID(a);
  int w = blog(a->n-1)+1;
  _ pi = Perm_ID2(a->n, 1<<w);
  share_t q = a->q;
//  share_t qb = order(a);
//  share_t qb = 1<<w;
  for (int k=1; k<q; k*=2) {
    // printf("k %d q %d\n", k, q);
    //printf("a "); _print(a);
//    _pair tmp = share_A2QB(a, q/k, qb);
//    printf("old bits "); _print(tmp2.y);
//    printf("old q    "); _print(tmp2.x);
//    _check(a);
  //  _pair tmp = share_A2QB_channel2(a, q/k, 2, channel);
    _pair tmp = share_A2QB_channel2(a, q/k, 1<<w, channel);
    //printf("new bits "); _print(tmp.y);
    //printf("new q    "); _print(tmp.x);
    //_ sigma = StableSort(tmp.y);
  //  printf("bits "); _print(tmp.y);
    //_ sigma = StableSort(tmp.y);
    _ sigma = StableSort_channel2(tmp.y, channel);
    //printf("sigma "); _print(sigma);
    if (tmp.x->q > 1) {
      _move_(a, AppInvPerm_channel(tmp.x, sigma, channel));
    }
    _free(tmp.x);
    _free(tmp.y);
    _move_(pi, AppInvPerm_channel(pi, sigma, channel));
    _free(sigma);
  }
  _free(a);
  _ x = AppPerm_channel(a_, pi, channel);
  _pair ans = {x, pi};
  return ans;
}

_pair share_radix_sort_channel4(_ a_, share_t q, int channel)
{
  if (_party >  2) {
    _pair ans = {NULL, NULL};
    return ans;
  }
  _ a = _dup(a_);
//  _ pi = Perm_ID(a);
  int w = blog(a->n-1)+1;
  _ pi = Perm_ID2(a->n, 1<<w);
//  share_t q = a->q;
  //printf("q %d %d\n", q, a->q);
  q = min(q, a->q);
//  share_t qb = order(a);
//  share_t qb = 1<<w;
  for (int k=1; k<q; k*=2) {
    // printf("k %d q %d\n", k, q);
    //printf("a "); _print(a);
//    _pair tmp = share_A2QB(a, q/k, qb);
//    printf("old bits "); _print(tmp2.y);
//    printf("old q    "); _print(tmp2.x);
//    _check(a);
  //  _pair tmp = share_A2QB_channel2(a, q/k, 2, channel);
    _pair tmp = share_A2QB_channel2(a, q/k, 1<<w, channel);
    //printf("new bits "); _print(tmp.y);
    //printf("new q    "); _print(tmp.x);
    //_ sigma = StableSort(tmp.y);
  //  printf("bits "); _print(tmp.y);
    //_ sigma = StableSort(tmp.y);
    _ sigma = StableSort_channel2(tmp.y, channel);
    //printf("sigma "); _print(sigma);
    if (tmp.x->q > 1) {
      _move_(a, AppInvPerm_channel(tmp.x, sigma, channel));
    }
    _free(tmp.x);
    _free(tmp.y);
    _move_(pi, AppInvPerm_channel(pi, sigma, channel));
    _free(sigma);
  }
  _free(a);
  _ x = AppPerm_channel(a_, pi, channel);
  _pair ans = {x, pi};
  return ans;
}


_pair share_radix_sort_xor_channel(_ a_, int channel)
{
  if (_party >  2) {
    _pair ans = {NULL, NULL};
    return ans;
  }
  _ a = _dup(a_);
//  _ pi = Perm_ID(a);
  int w = blog(a->n-1)+1;
  _ pi = Perm_ID2(a->n, 1<<w);
  share_t q = a->q;
//  share_t qb = order(a);
//  share_t qb = 1<<w;
  for (int k=1; k<q; k*=2) {
    _pair tmp = share_A2QB_xor(a);
    printf("tmp.x "); _print(tmp.x);
    printf("tmp.y "); _print(tmp.y);
    _ sigma = StableSort_channel2(tmp.y, channel);
    printf("sigma "); _print(sigma);
    if (tmp.x->q > 1) {
      //_move_(a, AppPerm_inverse_channel(tmp.x, sigma, channel));
      _move_(a, AppPerm_inverse_xor_channel(tmp.x, sigma, channel));
    }
    //_free(a);
    //a = tmp.x;
    _free(tmp.y);
    _move_(pi, AppInvPerm_channel(pi, sigma, channel));
    _free(sigma);
  }
  _free(a);
  //_ x = AppPerm_fwd_channel(a_, pi, channel);
  _ x = AppPerm_fwd_xor_channel(a_, pi, channel);
  _pair ans = {x, pi};
  return ans;
}
#define share_radix_sort_xor(a) share_radix_sort_xor_channel(a, 0)


#define share_radix_sort(a) share_radix_sort_channel2(a, 0)
//#define share_radix_sort(a) share_radix_sort_channel(a, 0)
#define _radix_sort share_radix_sort




_pair share_radix_sort_cont4(_ pi, _ a, share_t q)
{
  if (_party >  2) {
    _pair ans = {NULL, NULL};
    return ans;
  }
  _ key = AppPerm(a, pi);
  _pair tmp = share_radix_sort_channel4(key, q, 0);
  _free(key);
//  AppInvPerm_(pi, tmp.y);
  AppPerm_(pi, tmp.y);
  _move_(tmp.y, pi);
  return tmp;
}

_ share_radix_sort_bits(_bits a)
{
  if (_party >  2) return NULL;
  int d = a->d;
//  printf("b "); _print(a[0]);
//  _ pi = StableSort(a->a[0]);
  _ pi = StableSort2(a->a[0]);
//  printf("pi "); _print(pi);
  _ ap;
  _ sigma;
  for (int k=1; k<d; k++) {
  //  printf("k %d\n", k);
    ap = AppInvPerm(a->a[k], pi);
//    sigma = StableSort(ap);
    sigma = StableSort2(ap);
    _free(ap);
    _move_(pi, AppPerm(sigma, pi));
    _free(sigma);
  }
  return pi;
}
#define _radix_sort_bits share_radix_sort_bits

_ share_radix_sort_bits_channel(_bits a, int channel)
{
  if (_party >  2) return NULL;
  int d = a->d;
//  printf("b "); _print(a[0]);
//  _ pi = StableSort(a->a[0]);
  _ pi = StableSort2_channel(a->a[0], channel);
//  printf("pi "); _print(pi);
  _ ap;
  _ sigma;
  for (int k=1; k<d; k++) {
  //  printf("k %d\n", k);
    ap = AppInvPerm_channel(a->a[k], pi, channel);
    sigma = StableSort2_channel(ap, channel);
    _free(ap);
    _move_(pi, AppPerm_channel(sigma, pi, channel));
    _free(sigma);
  }
  return pi;
}
#define _radix_sort_bits2(a) share_radix_sort_bits_channel(a, 0)


#endif
