/**
  * Received when a peer request a piece. If the piece is available (which should always be the
  * case according to Bittorrent protocol) and we are able and willing to upload, the send the
  * piece to the peer
  *
  * @param peerID String
  * @param piece int
  * @param begin int
  * @param length int
  */
 public synchronized void peerRequest(String peerID, int piece, int begin, int length) {
   if (this.isPieceComplete(piece)) {
     DownloadTask dt = this.task.get(peerID);
     if (dt != null) {
       dt.ms.addMessageToQueue(
           new Message_PP(
               PeerProtocol.PIECE,
               Utils.concat(
                   Utils.intToByteArray(piece),
                   Utils.concat(
                       Utils.intToByteArray(begin), this.getPieceBlock(piece, begin, length)))));
       dt.peer.setULRate(length);
     }
     dt = null;
     this.pu.updateParameters(0, length, "");
   } else {
     try {
       this.task.get(peerID).end();
     } catch (Exception e) {
     }
     this.task.remove(peerID);
     this.peerList.remove(peerID);
     this.unchoken.remove(peerID);
   }
 }
  /**
   * Received when a piece has been fully downloaded by a task. The piece might have been corrupted,
   * in which case the manager will request it again later. If it has been successfully downloaded
   * and verified, the piece status is set to 'complete', a 'HAVE' message is sent to all connected
   * peers and the piece is saved into the corresponding file(s)
   *
   * @param peerID String
   * @param i int
   * @param complete boolean
   */
  public synchronized void pieceCompleted(String peerID, int i, boolean complete) {
    if (this.interrupted()) return;
    synchronized (this.isRequested) {
      this.isRequested.clear(i);
    }
    synchronized (this.isComplete) {
      if (complete && !this.isPieceComplete(i)) {
        pu.updateParameters(this.torrent.pieceLength, 0, "");
        this.isComplete.set(i, complete);
        //                float totaldl = (float) (((float) (100.0)) *
        //                                         ((float) (this.isComplete.cardinality())) /
        //                                         ((float) (this.nbPieces)));
        double totaldl = getPercentsCompleted();

        for (Iterator it = this.task.keySet().iterator(); it.hasNext(); )
          try {
            this.task
                .get(it.next())
                .ms
                .addMessageToQueue(new Message_PP(PeerProtocol.HAVE, Utils.intToByteArray(i), 1));
          } catch (NullPointerException npe) {
          }
        System.out.println(
            "Piece completed by " + peerID + " : " + i + " (Total dl = " + totaldl + "% )");
        this.savePiece(i);
        this.getPieceBlock(i, 0, 15000);

      } else {

        // this.pieceList[i].data = new byte[0];
      }

      if (this.isComplete.cardinality() == this.nbPieces) {
        // System.out.println("Download completed, saving file...");
        // this.save();
        // this.task.clear();
        // this.end();
        System.out.println("Task completed");
        this.downloadFinished = true;
        this.notify();
      }
    }
  }