anchor.diff:      end.
   
   %% @doc Tries to do a lookup for all join IDs in JoinState by contacting the
  -%%      first node among the ContactNodes, then go to phase 3. If there is no
  +%%      first node among the Connections, then go to phase 3. If there is no
   %%      node to contact, try to get new contact nodes and continue in phase 2.
   %%      A node that has been contacted will be put at the end of the
  -%%      ContactNodes list.
  +%%      Connections list.
   %%      Note: the returned join state will stay in phase 4 if already in phase 4
   -spec lookup(phase2() | phase2b() | phase3()) -> NewState::phase_2_4().
   lookup(JoinState) ->
  
positive.code: -spec set_join_ids(JoinIds::[?RT:key()], phase_2_4()) -> phase_2_4().
  set_join_ids(JoinIds, JoinState) -> setelement(6, JoinState, JoinIds).
  -spec remove_join_id(JoinId::?RT:key(), phase_2_4()) -> phase_2_4().
  remove_join_id(JoinIdToRemove, {Phase, JoinUUId, Options, CurIdVersion, ContactNodes, JoinIds, Candidates}) ->
      {Phase, JoinUUId, Options, CurIdVersion, ContactNodes,
       [Id || Id <- JoinIds, Id =/= JoinIdToRemove], Candidates}.
  -spec add_candidate_front(Candidate::lb_op:lb_op(), phase_2_4()) -> phase_2_4().
  add_candidate_front(Candidate, {Phase, JoinUUId, Options, CurIdVersion, ContactNodes, JoinIds, Candidates}) ->
      {Phase, JoinUUId, Options, CurIdVersion, ContactNodes, JoinIds, [Candidate | Candidates]}.
  -spec add_candidate_back(Candidate::lb_op:lb_op(), phase_2_4()) -> phase_2_4().
  add_candidate_back(Candidate, {Phase, JoinUUId, Options, CurIdVersion, ContactNodes, JoinIds, Candidates}) ->
      {Phase, JoinUUId, Options, CurIdVersion, ContactNodes, JoinIds, lists:append(Candidates, [Candidate])}.
  -spec sort_candidates(phase_2_4()) -> phase_2_4().
  sort_candidates({Phase, JoinUUId, Options, CurIdVersion, ContactNodes, JoinIds, Candidates} = JoinState) ->
      LbPsv = get_lb_psv(JoinState),
      {Phase, JoinUUId, Options, CurIdVersion, ContactNodes, JoinIds, LbPsv:sort_candidates(Candidates)}.
  -spec remove_candidate(CandId::lb_op:id(), phase_2_4()) -> phase_2_4().
  remove_candidate(CandId, {Phase, JoinUUId, Options, CurIdVersion, Connections, JoinIds, Candidates}) ->
      NewCandidates = [C || C <- Candidates, lb_op:get(C, id) =/= CandId],
      {Phase, JoinUUId, Options, CurIdVersion, Connections, JoinIds, NewCandidates}.
  -spec remove_candidate_front(phase_2_4()) -> phase_2_4().
  remove_candidate_front({Phase, JoinUUId, Options, CurIdVersion, ContactNodes, JoinIds, []}) ->
      {Phase, JoinUUId, Options, CurIdVersion, ContactNodes, JoinIds, []};
  remove_candidate_front({Phase, JoinUUId, Options, CurIdVersion, ContactNodes, JoinIds, [_ | Candidates]}) ->
      {Phase, JoinUUId, Options, CurIdVersion, ContactNodes, JoinIds, Candidates}.
  -spec remove_candidate_front_keep_id(phase_2_4()) -> phase_2_4().
  remove_candidate_front_keep_id({Phase, JoinUUId, Options, CurIdVersion, ContactNodes, JoinIds, []}) ->
      {Phase, JoinUUId, Options, CurIdVersion, ContactNodes, JoinIds, []};
  remove_candidate_front_keep_id({Phase, JoinUUId, Options, CurIdVersion, ContactNodes, JoinIds, [Front | Candidates]}) ->
      IdFront = node_details:get(lb_op:get(Front, n1_new), new_key),
      {Phase, JoinUUId, Options, CurIdVersion, ContactNodes, [IdFront | JoinIds], Candidates}.
  -spec skip_psv_lb(phase_2_4()) -> boolean().
  skip_psv_lb({_Phase, _JoinUUId, Options, _CurIdVersion, _ContactNodes, _JoinIds, _Candidates}) ->
      lists:member({skip_psv_lb}, Options).
  
  -spec new_connection(OldConn::{null | pos_integer(), comm:mypid()})
  
negative.code: 
  -type phase2() ::
      {phase2,  JoinUUId::pos_integer(), Options::[tuple()], MyKeyVersion::non_neg_integer(),
       Connections::[{null | pos_integer(), comm:mypid()}],
       JoinIds::[?RT:key()], Candidates::[lb_op:lb_op()]}.
  -type phase2b() ::
      {phase2b, JoinUUId::pos_integer(), Options::[tuple()], MyKeyVersion::non_neg_integer(),
       Connections::[{null | pos_integer(), comm:mypid()},...],
       JoinIds::[?RT:key()], Candidates::[lb_op:lb_op()]}.
  -type phase3() ::
      {phase3,  JoinUUId::pos_integer(), Options::[tuple()], MyKeyVersion::non_neg_integer(),
       Connections::[{null | pos_integer(), comm:mypid()}],
       JoinIds::[?RT:key()], Candidates::[lb_op:lb_op()]}.
  -type phase4() ::
      {phase4,  JoinUUId::pos_integer(), Options::[tuple()], MyKeyVersion::non_neg_integer(),
       Connections::[{null | pos_integer(), comm:mypid()}],
       JoinIds::[?RT:key()], Candidates::[lb_op:lb_op()]}.
  -type phase_2_4() :: phase2() | phase2b() | phase3() | phase4().
  
  -type join_state() ::
      {join, {phase1,  JoinUUId::pos_integer(), Options::[tuple()], MyKeyVersion::non_neg_integer(),
              Connections::[], JoinIds::[?RT:key()], Candidates::[]},
       QueuedMessages::msg_queue:msg_queue()} |
      {join, phase_2_4(), QueuedMessages::msg_queue:msg_queue()}.
  
  