EnableExplicit


Procedure Peer_EndgameMode_Detect(*Local_TorrentList.Core_Torrent) ; Детектирование необходимости включения режима "Endgame Mode".
  Protected Size.q, TSize.q,TempQ.q
  
  ; Режим "Endgame Mode" не включен.
  If *Local_TorrentList\TorrentList()\Endgame_Mode <> #True
    ; Может нужно включить этот режим?
    Size = *Local_TorrentList\TorrentList()\Torrent\Torrent_FileSize - *Local_TorrentList\TorrentList()\Torrent\CurrentFileSize
    If Size>0 ; Сколько еще нужно скачать.
      If Size < #Peer_PieceLength * #Peer_CountBlock_Enable_EndgameMode
        TSize = *Local_TorrentList\TorrentList()\Torrent\Torrent_FileSize
        Size = *Local_TorrentList\TorrentList()\Torrent\CurrentFileSize
        If Size>0
          TempQ = *Local_TorrentList\TorrentList()\Torrent\Torrent_FileSize / *Local_TorrentList\TorrentList()\Torrent\CurrentFileSize
          If TempQ>0
            If 100/TempQ >= 90
              *Local_TorrentList\TorrentList()\Endgame_Mode = #True
            EndIf
          EndIf
        EndIf
      EndIf
    EndIf
  EndIf
  
EndProcedure


 ; Вызывается Peer_InCommand_Piece() и если активен режим "EndgameMode" то проверяет есть ли приславший пир в списке и отсылает "Cancel" остальным пирам.
Procedure.a Peer_EndgameMode_GetPiece(*Local_TorrentList.Core_Torrent, Pos)
  Protected Result.a, ListPos, x, Peer_NoSendCancel
  Protected ConnectID, Piece, Begin, Length
  
  Result = #False
  If *Local_TorrentList\TorrentList()\Endgame_Mode = #True
    Peer_NoSendCancel = *Local_TorrentList\TorrentList()\GetPieces_List()\PiecesInfo(Pos)\ConnectID
    If Peer_NoSendCancel
      ListPos = ListIndex(*Local_TorrentList\TorrentList()\Network\PeerList())
      
      x=#False
      If ListPos>=0 And *Local_TorrentList\TorrentList()\Network\PeerList()\ConnectID = Peer_NoSendCancel
        x=#True
      Else
        ForEach *Local_TorrentList\TorrentList()\Network\PeerList()
          If *Local_TorrentList\TorrentList()\Network\PeerList()\ConnectID = Peer_NoSendCancel
            x=#True
            Break
          EndIf
        Next
      EndIf
      
      If x=#True
        Piece = *Local_TorrentList\TorrentList()\GetPieces_List()\Piece
        Begin = *Local_TorrentList\TorrentList()\GetPieces_List()\PiecesInfo(Pos)\begin
        Length = *Local_TorrentList\TorrentList()\GetPieces_List()\PiecesInfo(Pos)\length
        
        ForEach *Local_TorrentList\TorrentList()\Network\PeerList()
          ConnectID = *Local_TorrentList\TorrentList()\Network\PeerList()\ConnectID
          If ConnectID <> Peer_NoSendCancel And ConnectID<>0
            If *Local_TorrentList\TorrentList()\Network\PeerList()\Peer_Status\Choke=#False ; ОК, пир нас не сблокирует.
              Peer_Send_Cancel(*Local_TorrentList, Piece, Begin, Length)
            EndIf
          EndIf
        Next
        
        Result = #True
        
      EndIf
      
      If ListPos>=0
        SelectElement(*Local_TorrentList\TorrentList()\Network\PeerList(), ListPos)
      EndIf
      
    EndIf
  EndIf
  
  ProcedureReturn Result
EndProcedure


; Запрос блока у пиров, у коороых не превышен лимит запросов, криме пира, идентификатор которого указан в SendConnect.
Procedure Peer_EndgameMode_SetPiece(*Local_TorrentList.Core_Torrent, SendConnect, Piece, Begin, Length)
  Protected ListPos, *Point, x
  Protected NewList PeerList.Int_2()
  
  ListPos = ListIndex(*Local_TorrentList\TorrentList()\Network\PeerList())
  x=0
  ForEach *Local_TorrentList\TorrentList()\Network\PeerList()
    If *Local_TorrentList\TorrentList()\Network\PeerList()\ConnectID <> SendConnect And *Local_TorrentList\TorrentList()\Network\PeerList()\ConnectID<>0
      If *Local_TorrentList\TorrentList()\Network\PeerList()\Peer_Status\Choke=#False ; ОК, пир нас не блокирует
        If *Local_TorrentList\TorrentList()\Network\PeerList()\CurrentRequest < *Local_TorrentList\TorrentList()\Network\PeerList()\MaxRequest+8 ;10
          If AddElement(PeerList())
            PeerList()\Int_1 = x
            PeerList()\Int_2 = *Local_TorrentList\TorrentList()\Network\PeerList()\Average_InSpeed
          EndIf
        EndIf
      EndIf
    EndIf
    x+1
  Next
  
  If ListSize(PeerList())>0
    
    CompilerIf #PB_Compiler_Version<520
      SortStructuredList(PeerList(), #PB_Sort_Descending, OffsetOf(Int_2\Int_2), #PB_Sort_Integer)
    CompilerElse
      SortStructuredList(PeerList(), #PB_Sort_Descending, OffsetOf(Int_2\Int_2), #PB_Integer)
    CompilerEndIf
    
    x=0
    ForEach PeerList()
      SelectElement(*Local_TorrentList\TorrentList()\Network\PeerList(), PeerList()\Int_1)
      *Point = Peer_Create_Request(Piece, Begin, Length) ; Создаем Request-запрос пиру.
      If *Point ; Запрос успешно сформирован.
        If Peer_AddList_OutData(*Local_TorrentList, *Point, 17)=#True ; Отправляем пиру запрос блока.
          *Local_TorrentList\TorrentList()\Network\PeerList()\CountOut_Request + 1 ; Исходящий запрос пиру.
          *Local_TorrentList\TorrentList()\Network\PeerList()\CurrentRequest + 1 ; Текущее число запросов блоков для пира.
          *Local_TorrentList\TorrentList()\Network\PeerList()\Active = #True   ; Переводим пира в раздел активных.
          *Local_TorrentList\TorrentList()\Network\PeerList()\PeerUp=#True     ; Мы качаем от пира.
          x+1
          If x>=4 : Break : EndIf ;128
        EndIf
      EndIf
    Next
    
    
  EndIf
  
  If ListPos>=0
    SelectElement(*Local_TorrentList\TorrentList()\Network\PeerList(), ListPos)
  EndIf
EndProcedure


Procedure Peer_EndgameMode_Start(*Local_TorrentList.Core_Torrent) ; Вызов прецедуры приведет к переходу в режим "Endgame Mode".
  Protected ListPos, Piece, i, SizeArray
  Protected ConnectID
  
  If *Local_TorrentList\TorrentList()\Endgame_Mode <> #True
    *Local_TorrentList\TorrentList()\Endgame_Mode = #True
    
    ListPos = ListIndex(*Local_TorrentList\TorrentList()\GetPieces_List())
    
    ForEach *Local_TorrentList\TorrentList()\GetPieces_List()
      Piece = *Local_TorrentList\TorrentList()\GetPieces_List()\Piece
      SizeArray = ArraySize(*Local_TorrentList\TorrentList()\GetPieces_List()\PiecesInfo())
      For i=0 To SizeArray
        ConnectID = *Local_TorrentList\TorrentList()\GetPieces_List()\PiecesInfo(i)\ConnectID
        If ConnectID And *Local_TorrentList\TorrentList()\GetPieces_List()\PiecesInfo(i)\Point=0 ; Этот блок еще не прислали.
          Peer_EndgameMode_SetPiece(*Local_TorrentList, ConnectID, Piece, *Local_TorrentList\TorrentList()\GetPieces_List()\PiecesInfo(i)\begin, *Local_TorrentList\TorrentList()\GetPieces_List()\PiecesInfo(i)\length)
        EndIf
      Next i
    Next
    
    If ListPos>=0
      SelectElement(*Local_TorrentList\TorrentList()\GetPieces_List(), ListPos)
    EndIf
    
  Else
    Peer_EndgameMode_Detect(*Local_TorrentList)
  EndIf
  
EndProcedure


DisableExplicit
; IDE Options = PureBasic 5.11 (Windows - x86)
; Folding = -
; EnableXP