BlockInfo?GetFromList(IPeer peer, BitField bitfield, IList <int> pieces)
        {
            if (!peer.SupportsFastPeer || !ClientEngine.SupportsFastPeer)
            {
                return(null);
            }

            for (int i = 0; i < pieces.Count; i++)
            {
                int index = pieces[i];
                // A peer should only suggest a piece he has, but just in case.
                if (index >= bitfield.Length || !bitfield[index] || AlreadyRequested(index))
                {
                    continue;
                }

                pieces.RemoveAt(i);
                var p = new Piece(index, TorrentData.BytesPerPiece(index));
                requests.Add(p);
                return(p.Blocks[0].CreateRequest(peer));
            }


            return(null);
        }
        IList <BlockInfo> GetStandardRequest(IPeer peer, BitField current, int startIndex, int endIndex, int count)
        {
            int piecesNeeded = (count * Piece.BlockSize) / TorrentData.PieceLength;

            if ((count * Piece.BlockSize) % TorrentData.PieceLength != 0)
            {
                piecesNeeded++;
            }
            int checkIndex = CanRequest(current, startIndex, endIndex, ref piecesNeeded);

            // Nothing to request.
            if (checkIndex == -1)
            {
                return(null);
            }

            var bundle = new List <BlockInfo> (count);

            for (int i = 0; bundle.Count < count && i < piecesNeeded; i++)
            {
                // Request the piece
                var p = new Piece(checkIndex + i, TorrentData.BytesPerPiece(checkIndex + i));
                requests.Add(p);
                for (int j = 0; j < p.Blocks.Length && bundle.Count < count; j++)
                {
                    bundle.Add(p.Blocks[j].CreateRequest(peer));
                }
            }
            return(bundle);
        }
        BlockInfo?ContinueExistingRequest(IPeer peer, int startIndex, int endIndex, int maxDuplicateRequests, bool allowAbandoned, bool allowAny)
        {
            for (int req = 0; req < requests.Count; req++)
            {
                Piece p     = requests[req];
                int   index = p.Index;
                if (p.AllBlocksRequested || index < startIndex || index > endIndex || !peer.BitField[index])
                {
                    continue;
                }

                // For each piece that was assigned to this peer, try to request a block from it
                // A piece is 'assigned' to a peer if he is the first person to request a block from that piece
                if (allowAny || (allowAbandoned && p.Abandoned) || peer == p.Blocks[0].RequestedOff)
                {
                    for (int i = 0; i < p.BlockCount; i++)
                    {
                        if (!p.Blocks[i].Received && !p.Blocks[i].Requested)
                        {
                            return(p.Blocks[i].CreateRequest(peer));
                        }
                    }
                }
            }

            // If all blocks have been requested at least once and we're allowed more than 1 request then
            // let's try and issue a duplicate!
            for (int duplicate = 1; duplicate < maxDuplicateRequests; duplicate++)
            {
                for (int req = 0; req < requests.Count; req++)
                {
                    Piece primaryPiece = requests[req];
                    if (primaryPiece.Index < startIndex || primaryPiece.Index > endIndex || !peer.BitField[primaryPiece.Index])
                    {
                        continue;
                    }

                    if (!duplicates.TryGetValue(primaryPiece.Index, out List <Piece> extraPieces))
                    {
                        duplicates[primaryPiece.Index] = extraPieces = new List <Piece> ();
                    }

                    if (extraPieces.Count < duplicate)
                    {
                        var newPiece = new Piece(primaryPiece.Index, TorrentData.BytesPerPiece(primaryPiece.Index));
                        for (int i = 0; i < primaryPiece.BlockCount; i++)
                        {
                            if (primaryPiece.Blocks[i].Received)
                            {
                                newPiece.Blocks[i].TrySetReceived(primaryPiece.Blocks[i].RequestedOff);
                            }
                        }
                        extraPieces.Add(newPiece);
                    }

                    for (int extraPieceIndex = 0; extraPieceIndex < extraPieces.Count; extraPieceIndex++)
                    {
                        var extraPiece = extraPieces[extraPieceIndex];
                        for (int i = 0; i < extraPiece.BlockCount; i++)
                        {
                            if (!extraPiece.Blocks[i].Requested && !HasAlreadyRequestedBlock(primaryPiece, extraPieces, peer, i))
                            {
                                return(extraPiece.Blocks[i].CreateRequest(peer));
                            }
                        }
                    }
                }
            }

            // If we get here it means all the blocks in the pieces being downloaded by the peer are already requested
            return(null);
        }