anchor.diff:  handle_message(choke, State) ->
       #state{
           torrent_id=TorrentID,
  -        fast_extension=FastEnabled,
  -        remote_request_set=Requests,
  +        local_state=LocalState,
  +        local_config=LocalConf,
           download=Download} = State,
       ok = etorrent_peer_states:set_choke(TorrentID, self()),
  -    NewState = case FastEnabled of
  +    Fast = etorrent_peerconf:fast(LocalConf),
  +    NewState = case Fast of
           true ->
               %% If the Fast Extension is enabled a CHOKE message does
               %% not imply that all outstanding requests are dropped.
  -            State#state{remote_choked=true};
  +            NewLocalState = etorrent_peerstate:choked(true, LocalState),
  +            State#state{local_state=NewLocalState};
           false ->
               %% A CHOKE message implies that all outstanding requests has been dropped.
  +            Requests = etorrent_peerstate:requests(LocalState),
  +            Pieces = etorrent_rqueue:pieces(Requests),
               Chunks = etorrent_rqueue:to_list(Requests),
  +            Peers  = etorrent_peer_control:lookup_peers(TorrentID),
  +            ok = etorrent_piecestate:unassigned(Pieces, Peers),
               ok = etorrent_download:chunks_dropped(Chunks, Download),
  -            NewRequests = etorrent_rqueue:flush(Requests),
  -            etorrent_table:foreach_peer(TorrentID, fun try_queue_pieces/1),
  -            State#state{remote_choked=true, remote_request_set=NewRequests}
  +            NewReqs = etorrent_rqueue:flush(Requests),
  +            TmpLocalState = etorrent_peerstate:choked(true, LocalState),
  +            NewLocalState = etorrent_peerstate:requests(NewReqs, TmpLocalState),
  +            State#state{local_state=NewLocalState}
       end,
       {ok, NewState};
  -handle_message(unchoke, S) ->
  -    ok = etorrent_peer_states:set_unchoke(S#state.torrent_id, self()),
  -    try_to_queue_up_pieces(S#state{remote_choked = false});
  -handle_message(interested, S) ->
  -    ok = etorrent_peer_states:set_interested(S#state.torrent_id, self()),
  -    ok = etorrent_peer_send:check_choke(S#state.send_pid),
  -    {ok, S};
  -handle_message(not_interested, S) ->
  -    ok = etorrent_peer_states:set_not_interested(S#state.torrent_id, self()),
  -    ok = etorrent_peer_send:check_choke(S#state.send_pid),
  -    {ok, S};
  +
  +handle_message(unchoke, State) ->
  +    #state{
  +        torrent_id=TorrentID, send_pid=SendPid, download=Download,
  +        local_state=LocalState, remote_state=RemoteState} = State,
  +    ok = etorrent_peer_states:set_unchoke(TorrentID, self()),
  +    TmpLocalState = etorrent_peerstate:choked(false, LocalState),
  +    NewLocalState = poll_queue(Download, SendPid, RemoteState, TmpLocalState),
  +    NewState = State#state{local_state=NewLocalState},
  +    {ok, NewState};
  +
  +handle_message(interested, State) ->
  +    #state{torrent_id=TorrentID, send_pid=SendPid, remote_state=RemoteState} = State,
  +    ok = etorrent_peer_states:set_interested(TorrentID, self()),
  +    ok = etorrent_peer_send:check_choke(SendPid),
  +    NewRemoteState = etorrent_peerstate:interested(true, RemoteState),
  +    NewState = State#state{remote_state=NewRemoteState},
  +    {ok, NewState};
  +
  +handle_message(not_interested, State) ->
  +    #state{torrent_id=TorrentID, send_pid=SendPid, remote_state=RemoteState} = State,
  +    ok = etorrent_peer_states:set_not_interested(TorrentID, self()),
  +    ok = etorrent_peer_send:check_choke(SendPid),
  +    NewRemoteState = etorrent_peerstate:interested(false, RemoteState),
  +    NewState = State#state{remote_state=NewRemoteState},
  +    {ok, NewState};
  +
   handle_message({request, Index, Offset, Len}, S) ->
       etorrent_peer_send:remote_request(S#state.send_pid, Index, Offset, Len),
       {ok, S};
  +
   handle_message({cancel, Index, Offset, Len}, S) ->
       etorrent_peer_send:cancel(S#state.send_pid, Index, Offset, Len),
       {ok, S};
  -handle_message({have, PieceNum}, S) ->
  -    peer_have(PieceNum, S);
  -handle_message({suggest, Idx}, S) ->
  -    ?INFO([{peer_id, S#state.remote_peer_id}, {suggest, Idx}]),
  -    {ok, S};
  -handle_message(have_none, #state{remote_pieces=PS}=S) when PS =/= unknown ->
  -    {stop, normal, S};
  -handle_message(have_none, #state{fast_extension=true, torrent_id=TorrentID}=S) ->
  -    {value, NumPieces} = etorrent_torrent:num_pieces(TorrentID),
  -    Pieceset = etorrent_pieceset:new(NumPieces),
  +
  +handle_message({have, Piece}, State) ->
  +    #state{torrent_id=TorrentID, remote_state=RemoteState, local_state=LocalState} = State,
  +
  +    NewRemoteState = etorrent_peerconf:hasone(Piece, RemoteState),
  +    Pieceset = etorrent_peerstate:pieces(NewRemoteState),
  +    ok = etorrent_scarcity:add_piece(TorrentID, Piece, Pieceset),
  +
  +    ok = etorrent_peer_control:check_interest(Piece, LocalState),
  +    ok = etorrent_peer_control:check_seeder(NewRemoteState, LocalState),
  +
  +    NewState = State#state{remote_state=NewRemoteState},
  +    {ok, NewState};
  +
  +handle_message({suggest, Piece}, State) ->
  +    #state{remote_config=RemoteConf} = State,
  +    PeerID = etorrent_peerconf:peerid(RemoteConf),
  +    ?INFO([{peer_id, PeerID}, {suggest, Piece}]),
  +    {ok, State};
  +
  +handle_message(have_none, State) ->
  +    #state{torrent_id=TorrentID, remote_state=RemoteState, remote_config=RemoteConf} = State,
  +    etorrent_peerconf:fast(RemoteConf) orelse erlang:error(badarg),
  +    NewRemoteState = etorrent_peerstate:hasnone(RemoteState),
  +    Pieceset = etorrent_peerstate:pieces(NewRemoteState),
       ok = etorrent_scarcity:add_peer(TorrentID, Pieceset),
  -    NewState = S#state{
  -        remote_pieces=Pieceset,
  -        seeder=false},
  -    {ok, NewState};
  -
  -handle_message(have_all, #state{remote_pieces=PS}) when PS =/= unknown ->
  -    {error, remote_pieces_out_of_band};
  -
  -handle_message(have_all, #state{fast_extension=true, torrent_id=TorrentID}=S) ->
  -    {value, NumPieces} = etorrent_torrent:num_pieces(TorrentID),
  -    AllPieces = lists:seq(0, NumPieces - 1),
  -    FullSet = etorrent_pieceset:from_list(AllPieces, NumPieces),
  -    ok = etorrent_scarcity:add_peer(TorrentID, FullSet),
  -    NewState = S#state{
  -        remote_pieces=FullSet,
  -        seeder=true},
  -    {ok, NewState};
  -
  -handle_message({bitfield, _}, State) when State#state.remote_pieces /= unknown ->
  -    #state{socket=Socket, remote_peer_id=RemoteID} = State,
  -    {ok, {IP, Port}} = inet:peername(Socket),
  -    etorrent_peer_mgr:enter_bad_peer(IP, Port, RemoteID),
  -    {error, remote_pieces_out_of_band};
  -
  -handle_message({bitfield, Bin}, State) ->
  -    #state{
  -        torrent_id=TorrentID,
  -        remote_peer_id=RemoteID} = State,
  -    {value, Numpieces} = etorrent_torrent:num_pieces(TorrentID),
  -    Pieceset = etorrent_pieceset:from_binary(Bin, Numpieces),
  +    NewState = State#state{remote_state=NewRemoteState},
  +    {ok, NewState};
  +
  +handle_message(have_all, State) ->
  +    #state{torrent_id=TorrentID, remote_state=RemoteState, remote_config=RemoteConf} = State,
  +    etorrent_peerconf:fast(RemoteConf) orelse erlang:error(badarg),
  +    NewRemoteState = etorrent_peerstate:hasall(RemoteState),
  +    Pieceset = etorrent_peerstate:pieces(NewRemoteState),
       ok = etorrent_scarcity:add_peer(TorrentID, Pieceset),
  -    Left = Numpieces - etorrent_pieceset:size(Pieceset),
  -    IsSeeder = Left == 0,
  -    IsSeeder andalso etorrent_table:statechange_peer(self(), seeder),
  -    NewState = State#state{
  -        remote_pieces=Pieceset,
  -        seeder=IsSeeder},
  -    case etorrent_piece_mgr:check_interest(TorrentID, Pieceset) of
  -        {interested, _} ->
  -            statechange_interested(NewState, true),
  -            {ok, NewState#state{local_interested=true}};
  -        not_interested ->
  -            {ok, NewState};
  -        invalid_piece ->
  -            {stop, {invalid_piece_2, RemoteID}, State}
  -    end;
  +    NewState = State#state{remote_state=NewRemoteState},
  +    {ok, NewState};
  +
  +handle_message({bitfield, Bitfield}, State) ->
  +    #state{torrent_id=TorrentID, local_state=LocalState, remote_state=RemoteState} = State,
  +    NewRemoteState = etorrent_peerstate:hasset(Bitfield, RemoteState),
  +    Pieceset = etorrent_peerstate:pieces(NewRemoteState),
  +    ok = etorrent_scarcity:add_peer(TorrentID, Pieceset),
  +    %%IsSeeder andalso etorrent_table:statechange_peer(self(), seeder),
  +    NewState = State#state{remote_state=NewRemoteState},
  +    ok = etorrent_peer_control:check_interest(NewRemoteState, LocalState),
  +    {ok, NewState};
   
   handle_message({piece, Index, Offset, Data}, State) ->
  -    #state{
  -        torrent_id=TorrentID,
  -        download=Download,
  -        remote_request_set=Requests} = State,
  +    #state{torrent_id=TorrentID, download=Download, local_state=LocalState} = State,
       Length = byte_size(Data),
  -    NewRequests = case etorrent_rqueue:is_head(Index, Offset, Length, Requests) of
  +    Requests = etorrent_peerstate:requests(LocalState),
  +    NewLocal = case etorrent_rqueue:is_head(Index, Offset, Length, Requests) of
           true ->
               ok = etorrent_download:chunk_fetched(Index, Offset, Length, Download),
               ok = etorrent_io:write_chunk(TorrentID, Index, Offset, Data),
               ok = etorrent_download:chunk_stored(Index, Offset, Length, Download),
  -            etorrent_rqueue:pop(Requests);
  +            ok = etorrent_peerstate:check_queue(self()),
  +            NewRequests = etorrent_rqueue:pop(Requests),
  +            etorrent_peerstate:requests(NewRequests, LocalState);
           false ->
               %% Stray piece, we could try to get hold of it but for now we just
               %% throw it on the floor.
               Requests
       end,
  -    NewState = State#state{remote_request_set=NewRequests},
  -	try_to_queue_up_pieces(NewState);
  -
  -handle_message({extended, _, _}, S) when S#state.extended_messaging == false ->
  -    %% We do not accept extended messages unless they have been enabled.
  -    {stop, normal, S};
  -handle_message({extended, 0, _BCode}, S) ->
  +    NewState = State#state{local_state=NewLocal},
  +    {ok, NewState};
  +
  +handle_message({extended, 0, _Data}, State) ->
  +    #state{local_config=LocalConf} = State,
  +    etorrent_peerconf:extended(LocalConf) orelse erlang:error(badarg),
       %% Disable the extended messaging for now,
       %?INFO([{extended_message, etorrent_bcoding:decode(BCode)}]),
       %% We could consider storing the information here, if needed later on,
  -    %%   but for now we simply ignore that.
  -    {ok, S};
  -handle_message(Unknown, S) ->
  +    %% but for now we simply ignore that.
  +    {ok, State};
  +
  +handle_message(Unknown, State) ->
       ?WARN([unknown_message, Unknown]),
  -    {stop, normal, S}.
  -
  -
  -%% @doc Description: Try to queue up requests at the other end.
  -%%   Is called in many places with the state as input as the final thing
  -%%   it will check if we can queue up pieces and add some if needed.
  -%% @end
  -try_to_queue_up_pieces(#state { remote_choked = true } = S) ->
  -    {ok, S};
  -try_to_queue_up_pieces(State) ->
  +    {stop, normal, State}.
  +
  +
  +% @doc Initialize the connection, depending on the way the connection is
  +connection_initialize(incoming, State) ->
       #state{
  -        send_pid=SendPid,
  -        remote_pieces=Pieceset,
  -        remote_request_set=Requests,
  -        download=Download} = State,
  -    case etorrent_rqueue:is_low(Requests) of
  -        false ->
  -            {ok, State};
  -        true ->
  -            Numchunks = etorrent_rqueue:needs(Requests),
  -            case etorrent_download:request_chunks(Numchunks, Pieceset, Download) of
  -                {ok, not_interested} ->
  -                    statechange_interested(State, false),
  -                    {ok, State#state{local_interested=false}};
  -                {ok, assigned} ->
  -                    {ok, State};
  -                {ok, Chunks} ->
  -                    NewRequests = etorrent_rqueue:push(Chunks, Requests),
  -                    [etorrent_peer_send:local_request(SendPid, Chunk)
  -                    || Chunk <- Chunks],
  -                    NewState = State#state{remote_request_set=NewRequests},
  -                    {ok, NewState}
  -            end
  -    end.
  -
  -% @doc Initialize the connection, depending on the way the connection is
  -connection_initialize(incoming, S) ->
  -    case etorrent_proto_wire:complete_handshake(
  -                    S#state.socket,
  -                    S#state.info_hash,
  -                    S#state.local_peer_id) of
  -        ok -> SendPid = complete_connection_setup(S#state.socket,
  -                                            S#state.torrent_id,
  -                                            S#state.extended_messaging),
  -              NS = S#state { remote_peer_id = none_set,
  -                            fast_extension = false,
  -                            send_pid = SendPid},
  -              {ok, NS};
  -        {error, stop} -> {stop, normal}
  +        torrent_id=TorrentID,
  +        socket=Socket,
  +        info_hash=Infohash,
  +        local_config=LocalConf} = State,
  +    Extended = etorrent_peerconf:extended(LocalConf),
  +    LocalID = etorrent_peerstate:peerid(LocalConf),
  +    case etorrent_proto_wire:complete_handshake(Socket, Infohash, LocalID) of
  +        ok ->
  +            SendPid = complete_connection_setup(Socket, TorrentID, Extended),
  +            NewState = State#state{send_pid=SendPid},
  +            {ok, NewState};
  +        {error, stop} ->
  +            {stop, normal}
       end;
  -connection_initialize(outgoing, S) ->
  -    SendPid = complete_connection_setup(S#state.socket,
  -                                        S#state.torrent_id,
  -                                        S#state.extended_messaging),
  -    {ok, S#state{send_pid = SendPid}}.
  +
  +connection_initialize(outgoing, State) ->
  +    #state{
  +        torrent_id=TorrentID,
  +        socket=Socket,
  +        local_config=LocalConf} = State,
  +    Extended = etorrent_peerconf:extended(LocalConf),
  +    SendPid = complete_connection_setup(Socket, TorrentID, Extended),
  +    NewState = State#state{send_pid=SendPid},
  +    {ok, NewState}.
   
   %%--------------------------------------------------------------------
   %% Function: complete_connection_setup(Socket, TorrentId, ExtendedMSG)
  
positive.code:     NewState = State#state{download=NewDownload},
      {noreply, NewState};
  
  handle_info({tcp, _, _}, State) ->
      ?ERR([wrong_controller]),
      {noreply, State};
  
negative.code: %%    * Start the send pid
  %%    * Send off the bitfield
  %%--------------------------------------------------------------------
  complete_connection_setup(Socket, TorrentId, Extended) ->
      SendPid = gproc:lookup_local_name({peer, Socket, sender}),
      BF = etorrent_piece_mgr:bitfield(TorrentId),
      Extended andalso etorrent_peer_send:extended_msg(SendPid),
      etorrent_peer_send:bitfield(SendPid, BF),
      SendPid.
  