public synchronized Request getNextBlockRequest(Peer peer, int[] piecesFrequencies){

        RequestExtended recoveredRequest = recoverRequest(peer);
        if (recoveredRequest != null){
            associateRequest(peer,recoveredRequest);
            return recoveredRequest;
        }
        
        Integer pieceIndex = peerPiece.get(peer);
        // null if not downloading, completing if piece is completing
        if (pieceIndex==null || torrent.getTorrentDisk().isCompleted(pieceIndex) || completingPieces.contains(pieceIndex)){

            peerPiece.remove(peer);
            // get next piece
            pieceIndex = choosePiece(peer,piecesFrequencies);
            
            if (Torrent.verbose)
                torrent.addEvent(new Event(this,"chosen piece " + pieceIndex,Level.FINER));
            
            // no more pieces to download
            if (pieceIndex == null)
                return endGameBlockRequest(peer);
            
            // requested piece pieceIndex to peer
            peerPiece.put(peer,pieceIndex);
        }
        
        int firstMissingByte = getFirstMissingByte(pieceIndex);
        if (firstMissingByte >= torrent.getTorrentDisk().getLength(pieceIndex))
            throw new AssertionError("this piece is already completely requested, we should not be here.");
        int pieceMissingBytes = torrent.getTorrentDisk().getLength(pieceIndex) - firstMissingByte;
        int requestBlockLength = blockLength;
        
        // we have all but the last block
        if (pieceMissingBytes <= blockLength){
            completingPieces.add(pieceIndex);
            peerPiece.remove(peer);

            requestBlockLength = pieceMissingBytes;
            
            if (Torrent.verbose)
                torrent.addEvent(new Event(this,"request piece completed " + pieceIndex + " " + firstMissingByte + " " + requestBlockLength,Level.FINER));
        }
        
        RequestExtended re = new RequestExtended(pieceIndex,firstMissingByte,requestBlockLength);
        
        associateRequest(peer,re);
        return re;
    }