#ifndef _SYMMETRY_C_
#define _SYMMETRY_C_

#ifdef SYMMETRY

#ifndef SYMMOD
#include "hsfpan-sym.c"
#include "symmetric-fsm.c"
#include "symmetric-orbit.c"
#include "symmetric-orbit2.c"
#endif //

void construct_error_orbit(State * state){
  State *tmp_state,*aux_state;

  ErrorOrbit=new HashTable(state->ps->_nr_pr);
  orbit_states=0;

#ifndef SYMMOD
  tmp_state=new State;
  tmp_state->ps=new PackedState;
  memcpy(tmp_state->ps,state->ps,state->ps->_vsz);
  ErrorOrbit->insert(tmp_state); orbit_states++;
  orbit_zeta(state->ps);
  int f=1; for(int i=state->ps->_nr_pr-1; i>0; i--) f=f*i;
  printf("Fact(%d): %d\n",state->ps->_nr_pr-1,f);
  printf("States in orbit: %d\n",orbit_states);
#else
  tmp_state=new State;
  tmp_state->ps=new PackedState;
  memcpy(tmp_state->ps,state->ps,state->ps->_vsz);
  ErrorOrbit->insert(tmp_state); orbit_states++;
  for(int i=0; i<(state->ps->_nr_pr-1); i++){ /* linear search: _nr_pr-1 rotations  */
    aux_state=tmp_state;
    tmp_state=new State;
    tmp_state->ps=new PackedState;
    memcpy(tmp_state->ps,aux_state->ps,state->ps->_vsz);
    rotate(tmp_state);
    if(!ErrorOrbit->search(tmp_state)){
      ErrorOrbit->insert(tmp_state);
      orbit_states++;
    }
  }
  printf("N: %d\n",state->ps->_nr_pr);
  printf("States in orbit: %d\n",orbit_states);
#endif //
}

void canonicalize_successors(StateItem *successors){
  StateItem* state;
  PackedState *rep;

  for(state=successors; state; state=state->next){ 

/*     printf("Original state:        "); */
/*     printf("[ "); */
/*     for(int i=0; i<state->the_state->ps->_nr_pr; i++){ */
/*       printf("%2d ",((P0*)hsf_pptr(state->the_state->ps,i))->_p);  */
/*     } */
/*     printf("]\n"); */
    
/*     for(int i=0; i<state->the_state->ps->_nr_pr; i++){ */
/*       printf("\t Q%d: len(%d), [ ",i,((Q1*)hsf_qptr(state->the_state->ps,0))->Qlen); */
/*       for(int j=0; j<(2*state->the_state->ps->_nr_pr); j++){ */
/* 	printf(" (%d,%d) ",((Q1*)hsf_qptr(state->the_state->ps,i))->contents[j].fld0,((Q1*)hsf_qptr(state->the_state->ps,i))->contents[j].fld1); */
/*       } */
/*       printf("]\n"); */
/*     } */

    //#ifdef SYMMOD
    canonicalize_state(state->the_state);
    //#else
    //vsize=state->the_state->ps->_vsz;
    //rep=zeta(state->the_state->ps);
    //memcpy(state->the_state->ps,rep,vsize);
    //#endif //

/*     printf("Canonicalized state:   "); */
/*     printf("[ "); */
/*     for(int i=0; i<state->the_state->ps->_nr_pr; i++){ */
/*       printf("%2d ",((P0*)hsf_pptr(state->the_state->ps,i))->_p);  */
/*     } */
/*     printf("]\n"); */

/*     for(int i=0; i<state->the_state->ps->_nr_pr; i++){ */
/*       printf("\t Q%d: len(%d), [ ",i,((Q1*)hsf_qptr(state->the_state->ps,0))->Qlen); */
/*       for(int j=0; j<(2*state->the_state->ps->_nr_pr); j++){ */
/* 	printf(" (%d,%d) ",((Q1*)hsf_qptr(state->the_state->ps,i))->contents[j].fld0,((Q1*)hsf_qptr(state->the_state->ps,i))->contents[j].fld1); */
/*       } */
/*       printf("]\n"); */
    /*     } */
  }
}

void canonicalize_state(State *min_state){
  State tmp_state;

#ifndef SYMMOD
  vsize=min_state->ps->_vsz;
  tmp_state.ps=zeta(min_state->ps);
  memcpy(min_state->ps,tmp_state.ps,vsize);
  return;
#endif //


  tmp_state.ps=(PackedState*)new unsigned char[min_state->ps->_vsz];
  memcpy((void *)tmp_state.ps,(void *)min_state->ps,min_state->ps->_vsz);
#ifdef SYMMOD
  for(int i=0; i<(min_state->ps->_nr_pr-1); i++){ /* linear search: _nr_pr-1 rotations  */
    rotate(&tmp_state);

    /*printf("\trotated state: forks[ ");
    for(int i=0; i<tmp_state.ps->_nr_pr; i++){
      printf("%d ",tmp_state.ps->forks[i]); 
    }
     printf("] state[ ");
     for(int i=0; i<tmp_state.ps->_nr_pr; i++){
       printf("%d ",((P0*)hsf_pptr(tmp_state.ps,i))->_p);
     }
     printf("]\n");
     for(int j=0; j<tmp_state.ps->_vsz; j++) printf("%d ",((unsigned char *)tmp_state.ps)[j]); printf("\n");
     for(int j=0; j<tmp_state.ps->_vsz; j++) printf("%d ",((unsigned char *)min_state->ps)[j]); printf("\n");*/

    /*if(Selected_Heuristic==SYMMETRY_FSM1){ /* For preserving admissibility. */
    /*tmp_state.h=proto->Heuristic(&tmp_state);
      if(tmp_state.h<min_state->h) min_state->h=tmp_state.h;
    }*/
    if(memcmp(tmp_state.ps,min_state->ps,tmp_state.ps->_vsz)<0){
      /* Lexicographically smaller. */
      memcpy((void *)min_state->ps,(void *)tmp_state.ps,tmp_state.ps->_vsz);
    }
  } 
#endif // SYMMOD
  delete tmp_state.ps;
}

#ifdef SYMMOD
int rotate(State* state){
  P0 p;
  int i;
  unsigned pid,_p;

#if SYMMOD==4
  for(i=0; i<(state->ps->_nr_pr-1); i++)
    apply_swap(state->ps,i,i+1);
  return 0;
#endif //


  /* rotate forks */
#if SYMMOD==1
  unsigned char fork;
  fork=state->ps->forks[0];

  for(i=0; i<(state->ps->_nr_pr-1); i++)
    state->ps->forks[i]=state->ps->forks[i+1];
  state->ps->forks[i]=fork;
#elif SYMMOD==2
  Q1 q;

  q.Qlen=((Q1*)hsf_qptr(state->ps,0))->Qlen;
  //q._t=((Q1*)hsf_qptr(state->ps,0))->_t;
  for(int j=0; j<(2*state->ps->_nr_pr); j++){
    q.contents[j].fld0=((Q1*)hsf_qptr(state->ps,0))->contents[j].fld0;
    q.contents[j].fld1=((Q1*)hsf_qptr(state->ps,0))->contents[j].fld1;
  }

  for(i=0; i<(state->ps->_nr_pr-1); i++){
    ((Q1*)hsf_qptr(state->ps,i))->Qlen=((Q1*)hsf_qptr(state->ps,i+1))->Qlen;
    //((Q1*)hsf_qptr(state->ps,i))->_t=((Q1*)hsf_qptr(state->ps,i+1))->_t;
    for(int j=0; j<(2*state->ps->_nr_pr); j++){
      ((Q1*)hsf_qptr(state->ps,i))->contents[j].fld0=((Q1*)hsf_qptr(state->ps,i+1))->contents[j].fld0;
      ((Q1*)hsf_qptr(state->ps,i))->contents[j].fld1=((Q1*)hsf_qptr(state->ps,i+1))->contents[j].fld1;
    }
  }
  ((Q1*)hsf_qptr(state->ps,i))->Qlen=q.Qlen;
  //((Q1*)hsf_qptr(state->ps,i))->_t=q._t;
  for(int j=0; j<(2*state->ps->_nr_pr); j++){
    ((Q1*)hsf_qptr(state->ps,i))->contents[j].fld0=q.contents[j].fld0;
    ((Q1*)hsf_qptr(state->ps,i))->contents[j].fld1=q.contents[j].fld1;
  }
#endif //
  /* rotate processes */
  memcpy(&p,hsf_pptr(state->ps,0),sizeof(P0));
  //_p=((P0*)hsf_pptr(state->ps,0))->_p;
  for(i=0; i<(state->ps->_nr_pr-1); i++){
    pid=((P0*)hsf_pptr(state->ps,i))->_pid;
    memcpy(hsf_pptr(state->ps,i),hsf_pptr(state->ps,i+1),sizeof(P0));
    ((P0*)hsf_pptr(state->ps,i))->_pid=pid;
    //((P0*)hsf_pptr(state->ps,i))->_p=((P0*)hsf_pptr(state->ps,i+1))->_p;
  }
  pid=((P0*)hsf_pptr(state->ps,i))->_pid;
  memcpy(hsf_pptr(state->ps,i),&p,sizeof(P0));
  ((P0*)hsf_pptr(state->ps,i))->_pid=pid;
  //((P0*)hsf_pptr(state->ps,i))->_p=_p;
}

#endif // SYMMOD

#if SYMMOD==3 || SYMMOD==4
void apply_swap(PackedState *state, int i, int j)
{
  uchar up,ack;
  P0 p;
  unsigned pid;

  if(state->holder==i) state->holder=j;
  else if(state->holder==j) state->holder=i;

  up=state->up[i];
  ack=state->ack[i];
  memcpy(&p,hsf_pptr(state,i),sizeof(P0));

  state->up[i]=state->up[j];
  state->ack[i]=state->ack[j];
  pid=((P0*)hsf_pptr(state,i))->_pid;
  memcpy(hsf_pptr(state,i),hsf_pptr(state,j),sizeof(P0));
  ((P0*)hsf_pptr(state,i))->_pid=pid;

  state->up[j]=up;
  state->ack[j]=ack;
  pid=((P0*)hsf_pptr(state,j))->_pid;
  memcpy(hsf_pptr(state,j),&p,sizeof(P0));
  ((P0*)hsf_pptr(state,j))->_pid=pid;
}
#endif // /* 3,4 */

#endif // SYMMETRY

#endif // SYMMETRY_H
