#ifndef _COMPARE_H
 #define _COMPARE_H

#define COMP_pPE 0
#define COMP_PIE 1
#define COMP_LT 2
#define COMP_LE 3
#define COMP_EQ 4
#define COMP_GE 5
#define COMP_GT 6
#define COMP_3 7



//////////////////////////////////////////////////////////////////
// comp_sub2
// input x, y
// output bi
// bi は長さ 2l+1 の配列
// bi[2l]   == 1 → x == y
// bi[2i]   == 1 → x < y  かつ i ビット目が異なる
// bi[2i+1] == 1 → x > y  かつ i ビット目が異なる
//////////////////////////////////////////////////////////////////
#if 0
int comp_sub2(Zp x, Zp y, int bi[MAXW*2+1])
{
// constant
  Zp Zp_1, Zp_3;
  int l;
  value_t p;
// shared
  value_t cyclic_shift;
// P1
  Zp xp[MAXW*2+1];
// P2
  Zp yp[MAXW*2+1];
// P3
//  int bi[MAXW*2+1];
  int bi_len;
// tmp
  int i;
//  Zp z;

// error check
  if (x.p != y.p) {
    printf("comp_sub2: x.p = %ld y.p = %ld\n", x.p, y.p);
    exit(1);
  }
   p = x.p;
   l = blog(p-1)+1;
   if (l > MAXW) {
    printf("comp_sub2: l = %d MAXW = %d\n", l, MAXW);
    exit(1);
   }

  printf("comp_sub2: x=%ld, y=%ld p=%ld\n", x.v, y.v, p);


// constant
  Zp_1 = Zp_new(1, p);
  Zp_3 = Zp_new(3, p);

// shared
  cyclic_shift = shared_random(l*2+1);
  cyclic_shift = 0;


// P1

  for (i=l-1; i>=0; i--) {
    Zp t, xb, xs;
    Zp x2;

    x2 = x;
    xs = Zp_new(x2.v >> i, p);        // x2 の i+1 ビット目から上の部分
    xb = Zp_new(Zp_getbit(x2, i), p); // x2 の下から i ビット目
    t = add_Zp(mul_Zp(xs, sub_Zp(Zp_1,xb)),xb);
    xp[(i*2 + cyclic_shift) % (l*2+1)] = t;

    x2 = x;
    x2.v = x2.v ^ ((1<<l)-1); // r==1 なら反転
    xs = Zp_new(x2.v >> i, p);
    xb = Zp_new(Zp_getbit(x2, i), p);
    t = add_Zp(mul_Zp(xs, sub_Zp(Zp_1,xb)),xb);
    xp[(i*2+1 + cyclic_shift) % (l*2+1)] = t;
  }

  xp[(l*2 + cyclic_shift) % (l*2+1)] = x;

// P2
  for (i=l-1; i>=0; i--) {
    Zp t, yb, ys;
    Zp y2;

    y2 = y;
    ys = Zp_new(y2.v >> i, p);
    yb = Zp_new(Zp_getbit(y2, i), p);
    t = add_Zp(mul_Zp(sub_Zp(ys, Zp_1), yb), mul_Zp(Zp_3, sub_Zp(Zp_1, yb)));
    yp[(i*2 + cyclic_shift) % (l*2+1)] = t;

    y2 = y;
    y2.v = y2.v ^ ((1<<l)-1);
    ys = Zp_new(y2.v >> i, p);
    yb = Zp_new(Zp_getbit(y2, i), p);
    t = add_Zp(mul_Zp(sub_Zp(ys, Zp_1), yb), mul_Zp(Zp_3, sub_Zp(Zp_1, yb)));
    yp[(i*2+1 + cyclic_shift) % (l*2+1)] = t;
  }

  yp[(l*2 + cyclic_shift) % (l*2+1)] = y;

// P3
  bi_len = l*2+1;
  for (i=bi_len-1; i>=0; i--) {
    bi[(i + (l*2+1) - cyclic_shift) % (l*2+1)] = pPE(xp[i], yp[i]);
    printf("comp_sub2: i=%d bi=%d\n", i, bi[i]);
  }

  return bi_len;
}

///////////////////////////////////
// b = (x < y)
// bi は長さ 2l+1 の配列
// bi[2l]   == 1 → x == y
// bi[2i]   == 1 → x < y  かつ i ビット目が異なる
// bi[2i+1] == 1 → x > y  かつ i ビット目が異なる
// p must be a prime
///////////////////////////////////
int Comp(Zp x, Zp y, int mode)
{
  int i, bi_len;
  int bi[MAXW*2+1];

  bi_len = comp_sub2(x, y, bi);

  switch (mode) {
    case COMP_EQ:
      return (bi[bi_len-1] == 1);
    case COMP_LE:
      if (bi[bi_len-1] == 1) return 1;
    case COMP_LT:
      for (i = 0; i < bi_len-1; i += 2) {
        if (bi[i] == 1) return 1;
      }
      return 0;
    case COMP_GE:
      if (bi[bi_len-1] == 1) return 1;
    case COMP_GT:
      for (i = 1; i < bi_len-1; i += 2) {
        if (bi[i] == 1) return 1;
      }
      return 0;
    case COMP_3:
      if (bi[bi_len-1] == 1) return 0;
      for (i = 0; i < bi_len-1; i += 2) {
        if (bi[i  ] == 1) return -1;
        if (bi[i+1] == 1) return  1;
      }
    default:
      printf("Comp: mode=%d\n", mode);
      exit(1);
  }


#if 0
// debug
  if ((x.v < y.v) != b) {
    printf("PIE2:error x = %ld y = %ld b = %d\n", x.v, y.v, b);
    exit(1);
  }
#endif

  return -2; // unreachable
}
#endif

//////////////////////////////////////////////////////////////
// x[i] == y[i] のとき b[i] := 1
// x, y は mod 2^k, b は mod 2
//////////////////////////////////////////////////////////////
_b Equality_bit(_ x, _ y)
{
  //if (_party >  2) return NULL; // 要検討
  //if (order(x) != 2 || order(y) != 2) {
  //  printf("Equality_bit: x->q = %d y->q = %d\n", (int)x->q, (int)y->q);
  //}
//  int q = order(x);
//  printf("Equality x "); _print(x);
//  printf("Equality y "); _print(y);
  int q = 2;
  int n = len(x);
//  _ ans = _dup(x);
  _b ans = _const(n, 0, q);
  if (_party <= 1) {
    for (int i=0; i<n; i++) {
      pa_set(ans->A, i, MOD(pa_get(x->A, i) + pa_get(y->A, i) + 1));
    }
  }
  if (_party == 2) {
    for (int i=0; i<n; i++) {
      pa_set(ans->A, i, MOD(pa_get(x->A, i) + pa_get(y->A, i)));
    }
  }
//  printf("Equality ans "); _print(ans);
  return ans;
}


_ Equality2(_ a, _ b)
{
  if (a == NULL || b == NULL) {
    printf("Equality2: a = %p b = %p\n", a, b);
    return NULL;
  }
  if (a->q != 2 || b->q != 2) {
    printf("Equality2: a->q = %d b->q = %d\n", a->q, b->q);
  }
  //if (_party >  2) return NULL;
  _ ans = XOR(a, b);
  vneg_(ans);
  return ans;
}


_b Equality_bits(_bits x, _bits y)
{
  if (_party >  2) return NULL;
  if (x->d != y->d) {
    printf("Equality_bits: x->d = %d y->d = %d\n", x->d, y->d);
  }
  int d = x->d;
  _b b = Equality_bit(x->a[0], y->a[0]);
  vneg_(b);
  for (int i=1; i<d; i++) {
    _b c = Equality_bit(x->a[i], y->a[i]);
    vneg_(c);
    _move_(b, OR(b, c));
    _free(c);
  }
  vneg_(b);
  return b;
}

#if 0
_b Equality(_ x, _ y)
{
  if (_party >  2) return NULL;
  _bits bx, by;
  bx = _A2B(x, 2);
  by = _A2B(y, 2);
  _b c = Equality_bits(bx, by);
  _free_bits(bx);
  _free_bits(by);
  return c;
}
#endif
_b Equality(_ a, _ b)
{
  if (a == NULL || b == NULL) {
    printf("Equality: a = %p b = %p\n", a, b);
    return NULL;
  }
  //if (_party >  2) return NULL;
  int n = len(a);
  _ ans;
  if (_party > max_partyid(a)) {
    NEWA(ans, struct share_array, 1);
    *ans = *a;
    ans->q = 2;
    ans->type = SHARE_T_22ADD; // 要検討 BINARY?
    ans->A = NULL;
    return ans;
  }
  //printf("Equality3:\n");
  //printf("a "); _print(a);
  //printf("b "); _print(b);
  if (_party >= 0) {
    share_t q = order(a);
    int k = blog(q-1)+1; // 桁数
    _ c = _const(n*k, 0, 2);
    _ v;
    if (_party == 1) {
      v = vsub(a, b);
    } else {
      v = vsub(b, a);
    }
    //printf("v "); _print(v);

    int d = (_party & 1) ^ 1;
    for (int i=0; i<n; i++) {
      share_t x = pa_get(v->A, i);
      for (int j=0; j<k; j++) {
        pa_set(c->A, j*n+i, (x & 1) ^ d);
        x >>= 1;
      }
    }
    //printf("c "); _print(c);
    ans = AND_rec(c, n);
    _free(c); _free(v);
    if (_party == 0) _free(ans);
  }
  if (_party <= 0) {
    ans = _const(n, 0, 2);
    for (int i=0; i<n; i++) {
      pa_set(ans->A, i, pa_get(a->A, i) == pa_get(b->A, i));
    }
  }
  return ans;
}




_b LessThan_bit_channel(_b x, _b y, int channel)
{
  if (_party >  2) return NULL;
  if (order(x) != 2 || order(y) != 2) {
//    printf("LessThan: x->q = %d y->q = %d\n", (int)x->q, (int)y->q);
  }
//  int q = order(x);
  int q = 2;
  int n = len(x);

  _b cx = _dup(x);
  if (_party <= 1) {
    for (int i=0; i<n; i++) {
      pa_set(cx->A, i, MOD(pa_get(x->A, i) + 1));
    }
  }
  if (_party == 2) {
    for (int i=0; i<n; i++) {
      pa_set(cx->A, i, MOD(pa_get(x->A, i)));
    }
  }

  _b cy = _dup(x);
  if (_party <= 1) {
    for (int i=0; i<n; i++) {
      pa_set(cy->A, i, MOD(pa_get(y->A, i)));
    }
  }
  if (_party == 2) {
    for (int i=0; i<n; i++) {
      pa_set(cy->A, i, MOD(pa_get(y->A, i)));
    }
  }
  _b ans = vmul_channel(cx, cy, channel);

  _free(cx);
  _free(cy);

  return ans;
}
#define LessThan_bit(x, y) LessThan_bit_channel(x, y, 0)


_b LessThan_bits_channel(_bits x, _bits y, int channel)
{
  if (_party >  2) return NULL;
  if (x->d != y->d) {
    printf("LessThan_bits: x->d = %d y->d = %d\n", x->d, y->d);
  }
  int d = x->d;
//  printf("x ");
//  _print(x->a[d-1]);
//  printf("y ");
//  _print(y->a[d-1]);
  _b lt = LessThan_bit_channel(x->a[d-1], y->a[d-1], channel);
//  printf("lt ");
//  _print(lt);
  _b eq = Equality_bit(x->a[d-1], y->a[d-1]);
//  printf("eq ");
//  _print(eq);
  for (int i=d-2; i>=0; i--) {
  //  printf("x ");
  //  _print(x->a[i]);
  //  printf("y ");
  //  _print(y->a[i]);
    _b c = LessThan_bit_channel(x->a[i], y->a[i], channel);
    _b e = Equality_bit(x->a[i], y->a[i]);
  //  printf("c ");
  //  _print(c);
  //  printf("e ");
  //  _print(e);
    _b l = AND_channel(eq, c, channel);
  //  printf("l ");
  //  _print(l);
    _move_(lt, OR_channel(lt, l, channel));
    _move_(eq, AND_channel(eq, e, channel));
  //  printf("lt ");
  //  _print(lt);
  //  printf("eq ");
  //  _print(eq);
    _free(l);
    _free(c);
    _free(e);
  }
  _free(eq);
  return lt;
}
#define LessThan_bits(x, y) LessThan_bits_channel(x, y, 0)


_b LessThan_channel(_ x, _ y, int channel)
{
  if (_party >  2) return NULL;
  _bits bx, by;
  bx = _A2B_channel(x, 2, channel);
  by = _A2B_channel(y, 2, channel);
  _b c = LessThan_bits_channel(bx, by, channel);
  _free_bits(bx);
  _free_bits(by);
#if 0
  printf("LessThan x = %d y = %d c = %d\n", debug_get(x, 0), debug_get(y, 0), debug_get(c, 0));
#endif
  return c;
}
#define LessThan(x, y) LessThan_channel(x, y, 0)



#endif
