#include "Dlist.h"
ListElm *avail;
extern MPI_Win winlock;

void InsertElm( const char *key, const char *value )
{
  ListElm       local_copy, *local_copy_ptr, 
                local_copy_last, *local_copy_last_ptr, *new_local_ptr;
  MPI_Aint      new_ptr_disp;
  RemotePointer last_ptr, ptr;
  int           compare;
  int           my_rank;
  MPI_Group     win_group;

  /* Create new element first.  The new element must be allocated from
     the local memory window.  Note that each process has its own list
     of available list elements */
  if (! (new_local_ptr = avail) ) MPI_Abort( MPI_COMM_WORLD, 1 );
  avail = (ListElm *)avail->next;
  strcpy( new_local_ptr->key, key );
  strcpy( new_local_ptr->value, value );

  /* my_rank could also be precomputed, of course */
  MPI_Win_get_group( win, &win_group ):
  MPI_Group_rank( win_group, &my_rank );
  MPI_Group_free( &win_group );

  /* Lock list, find insertion point, and insert element */
  MPE_Mutex_lock( 0, winlock );

  ptr = head;
  while (ptr.owner_rank >= 0) {
     MPI_Win_lock( MPI_LOCK_SHARED, ptr.owner_rank, 
                   MPI_MODE_NOCHECK, win );
     MPI_Get( &local_copy, 1, ListElm_type, 
	      ptr.owner_rank, ptr.disp, 1, 
              ListElm_type, win );
     MPI_Win_unlock( ptr.owner_rank, win );
  
     compare = strcmp( local_copy.key, key );
     if (compare == 0) {   /* duplicate entry.  Do nothing */
        MPE_Mutex_unlock( 0, winlock ); return; }
     if (compare > 0) {
        break;
     }
     /* Save entire list element that "last_ptr" points to */
     local_copy_last     = local_copy;
     last_ptr = ptr;
     ptr      = ptr->next;
  }
  new_local_ptr_disp  = new_local_ptr->disp;
  new_local_ptr->next = last_ptr.next;
  /* Set the remote pointer field of the previous entry to point to 
     the new entry */
  local_copy_last.next.owner_rank = my_rank;
  local_copy_last.next.disp       = new_ptr_disp;
  local_copy_last.next.local_ptr  = 
          (my_rank == last_ptr.owner_rank) ? new_local_ptr : 0;

  MPI_Win_lock( MPI_LOCK_SHARED, last_ptr.owner_rank, 
                MPI_MODE_NOCHECK, win );
  MPI_Put( &local_copy_last, 1, ListElm_type, 
           last_ptr.owner_rank, last_ptr.disp, 1, ListElm_type, win );
  MPI_Win_unlock( ptr.owner_rank, win );

  MPE_Mutex_unlock( 0, winlock );
}
