package org.gudy.azureus2.core3.peer.impl;
///*
// * File : PEPieceImpl.java
// * Created : 15-Oct-2003
// * By : Olivier
// *
// * Azureus - a Java Bittorrent client
// *
// * This program is free software; you can redistribute it and/or modify
// * it under the terms of the GNU General Public License as published by
// * the Free Software Foundation; either version 2 of the License.
// *
// * This program is distributed in the hope that it will be useful,
// * but WITHOUT ANY WARRANTY; without even the implied warranty of
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// * GNU General Public License for more details ( see the LICENSE file ).
// *
// * You should have received a copy of the GNU General Public License
// * along with this program; if not, write to the Free Software
// * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// */
//
//package org.gudy.azureus2.core3.peer.impl;
//
///**
// * @author parg
// * @author MjrTom
// * 2005/Oct/08: numerous changes for new piece-picking
// * 2006/Jan/02: refactoring piece picking to elsewhere, and consolidations
// */
//
//import java.util.*;
//
////import org.gudy.azureus2.core3.disk.*;
////import org.gudy.azureus2.core3.logging.*;
//import org.gudy.azureus2.core3.peer.*;
//import org.gudy.azureus2.core3.util.*;
//
//import com.aelitis.azureus.core.peermanager.piecepicker.PiecePicker;
//
//
//public class PEPieceImpl
// implements PEPiece
//{
//// private static final LogIDs LOGID = LogIDs.PIECES;
//
//// private final DiskManagerPiece dmPiece;
// private final PEPeerManager manager;
//
// private final int nbBlocks; // number of blocks in this piece
// private long creationTime;
//
//
// private final String[] requested;
// private boolean fully_requested;
//
// private final boolean[] downloaded;
// private boolean fully_downloaded;
// private long time_last_download;
//
// private final String[] writers;
// private List writes;
//
// private String reservedBy; // using address for when they send bad/disconnect/reconnect
//
// //In end game mode, this limitation isn't used
// private int speed; //slower peers dont slow down fast pieces too much
//
// private int resumePriority;
//
// private Object real_time_data;
//
// // experimental class level lock
// protected static final AEMonitor class_mon = new AEMonitor( "PEPiece:class");
//
// /** piece for tracking partially downloaded pieces
// * @param _manager the PEPeerManager
// * @param _dm_piece the backing dmPiece
// * @param _pieceSpeed the speed threshold for potential new requesters
// */
//// public PEPieceImpl(
//// PEPeerManager _manager,
//// DiskManagerPiece _dm_piece,
//// int _pieceSpeed)
//// {
//// creationTime =SystemTime.getCurrentTime();
//// manager =_manager;
//// dmPiece =_dm_piece;
//// speed =_pieceSpeed;
////
//// nbBlocks =dmPiece.getNbBlocks();
////
//// requested =new String[nbBlocks];
////
//// final boolean[] written =dmPiece.getWritten();
//// if (written ==null)
//// downloaded =new boolean[nbBlocks];
//// else
//// downloaded =(boolean[])written.clone();
////
//// writers =new String[nbBlocks];
//// writes =new ArrayList(0);
//// }
////
//// public DiskManagerPiece getDMPiece()
//// {
//// return dmPiece;
//// }
//
// public long getCreationTime()
// {
// final long now =SystemTime.getCurrentTime();
// if (now >=creationTime &&creationTime >0)
// return creationTime;
// creationTime =now;
// return now;
// }
//
// public long getTimeSinceLastActivity()
// {
// final long now =SystemTime.getCurrentTime();
// final long lastWriteTime =getLastDownloadTime(now);
// if (time_last_download >0 &&now >=time_last_download)
// return now -time_last_download;
// if (creationTime >0 &&now >=creationTime)
// return now -creationTime;
// creationTime =now;
// return 0;
// }
//
// public long getLastDownloadTime(final long now)
// {
// if (time_last_download <=now)
// return time_last_download;
// return time_last_download =now;
// }
//
// /** Tells if a block has been requested
// * @param blockNumber the block in question
// * @return true if the block is Requested already
// */
// public boolean isRequested(int blockNumber)
// {
// return requested[blockNumber] !=null;
// }
//
// /** Tells if a block has been downloaded
// * @param blockNumber the block in question
// * @return true if the block is downloaded already
// */
// public boolean isDownloaded(int blockNumber)
// {
// return downloaded[blockNumber];
// }
//
// /** This flags the block at the given offset as having been downloaded
// * If all blocks are now downloaed, sets the dmPiece as downloaded
// * @param blockNumber
// */
// public void setDownloaded(int offset)
// {
// time_last_download =SystemTime.getCurrentTime();
// downloaded[offset /DiskManager.BLOCK_SIZE] =true;
// for (int i =0; i <nbBlocks; i++)
// {
// if (!downloaded[i])
// return;
// }
//
// fully_downloaded = true;
// fully_requested = false;
// }
//
// /** This flags the block at the given offset as NOT having been downloaded
// * and the whole piece as not having been fully downloaded
// * @param blockNumber
// */
// public void clearDownloaded(int offset)
// {
// downloaded[offset /DiskManager.BLOCK_SIZE] =false;
//
// fully_downloaded = false;
// }
//
// public boolean
// isDownloaded()
// {
// return( fully_downloaded );
// }
//
// public boolean[]
// getDownloaded()
// {
// return( downloaded );
// }
//
// public boolean
// hasUndownloadedBlock()
// {
// for (int i =0; i <nbBlocks; i++ ){
//
// if (!downloaded[i]){
//
// return( true );
// }
// }
//
// return( false );
// }
//
// /** This marks a given block as having been written by the given peer
// * @param peer the PEPeer that sent the data
// * @param blockNumber the block we're operating on
// */
// public void setWritten(PEPeer peer, int blockNumber)
// {
// writers[blockNumber] =peer.getIp();
// dmPiece.setWritten(blockNumber);
// }
//
// /** This method clears the requested information for the given block
// * unless the block has already been downloaded, in which case the writer's
// * IP is recorded as a request for the block.
// */
// public void clearRequested(int blockNumber)
// {
// requested[blockNumber] =downloaded[blockNumber] ?writers[blockNumber] :null;
//
// fully_requested = false;
// }
//
// public boolean
// isRequested()
// {
// return( fully_requested );
// }
//
// public void
// setRequested()
// {
// fully_requested = true;
// }
//
// /** This will scan each block looking for requested blocks. For each one, it'll verify
// * if the PEPeer for it still exists and is still willing and able to upload data.
// * If not, it'll unmark the block as requested.
// * @return int of how many were cleared (0 to nbBlocks)
// */
// /*
// public int checkRequests()
// {
// if (getTimeSinceLastActivity() <30 *1000)
// return 0;
// int cleared =0;
// boolean nullPeer =false;
// for (int i =0; i <nbBlocks; i++)
// {
// if (!downloaded[i] &&!dmPiece.isWritten(i))
// {
// final String requester =requested[i];
// final PEPeerTransport pt;
// if (requester !=null)
// {
// pt =manager.getTransportFromAddress(requester);
// if (pt !=null)
// {
// pt.setSnubbed(true);
// if (!pt.isDownloadPossible())
// {
// clearRequested(i);
// cleared++;
// }
// } else
// {
// nullPeer =true;
// clearRequested(i);
// cleared++;
// }
// }
// }
// }
// if (cleared >0)
// {
// dmPiece.clearRequested();
// if (Logger.isEnabled())
// Logger.log(new LogEvent(dmPiece.getManager().getTorrent(), LOGID, LogEvent.LT_WARNING,
// "checkRequests(): piece #" +getPieceNumber()+" cleared " +cleared +" requests."
// + (nullPeer ?" Null peer was detected." :"")));
// }
// return cleared;
// }
// */
//
// /*
// * Parg: replaced above commented out checking with one that verifies that the
// * requests still exist. As piece-picker activity and peer disconnect logic is multi-threaded
// * and full of holes, this is a stop-gap measure to prevent a piece from being left with
// * requests that no longer exist
// */
//
// public void
// checkRequests()
// {
// if ( getTimeSinceLastActivity() < 30*1000 ){
//
// return;
// }
//
// int cleared = 0;
//
// for (int i=0; i<nbBlocks; i++){
//
// if (!downloaded[i] &&!dmPiece.isWritten(i)){
//
// final String requester = requested[i];
//
// if ( requester != null ){
//
// if ( !manager.requestExists(
// requester,
// getPieceNumber(),
// i *DiskManager.BLOCK_SIZE,
// getBlockSize( i ))){
//
// clearRequested(i);
//
// cleared++;
// }
// }
// }
// }
//
// if ( cleared > 0 ){
//
//// if (Logger.isEnabled())
//// Logger.log(new LogEvent(dmPiece.getManager().getTorrent(), LOGID, LogEvent.LT_WARNING,
//// "checkRequests(): piece #" +getPieceNumber()+" cleared " +cleared +" requests" ));
// }else{
//
// if ( fully_requested && getNbUnrequested() > 0 ){
//
//// if (Logger.isEnabled())
//// Logger.log(new LogEvent(dmPiece.getManager().getTorrent(), LOGID, LogEvent.LT_WARNING,
//// "checkRequests(): piece #" +getPieceNumber()+" reset fully requested" ));
//
// fully_requested = false;
// }
// }
// }
//
//
// /** @return true if the piece has any blocks that are not;
// * Downloaded, Requested, or Written
// */
// public boolean hasUnrequestedBlock()
// {
// final boolean[] written =dmPiece.getWritten();
// for (int i =0; i <nbBlocks; i++ )
// {
// if (!downloaded[i] &&requested[i] ==null &&(written ==null ||!written[i]))
// return true;
// }
// return false;
// }
//
// /**
// * This method scans a piece for the first unrequested block. Upon finding it,
// * it counts how many are unrequested up to nbWanted.
// * The blocks are marked as requested by the PEPeer
// * Assumption - single threaded access to this
// * TODO: this should return the largest span equal or smaller than nbWanted
// * OR, probably a different method should do that, so this one can support 'more sequential' picking
// */
// public int[] getAndMarkBlocks(PEPeer peer, int nbWanted, boolean enable_request_hints )
// {
// final String ip =peer.getIp();
// final boolean[] written =dmPiece.getWritten();
// int blocksFound =0;
//
// if ( enable_request_hints ){
//
// int[] request_hint = peer.getRequestHint();
//
// if ( request_hint != null && request_hint[0] == dmPiece.getPieceNumber()){
//
// // try to honour the hint first
//
// int hint_block_start = request_hint[1] / DiskManager.BLOCK_SIZE;
// int hint_block_count = ( request_hint[2] + DiskManager.BLOCK_SIZE-1 ) / DiskManager.BLOCK_SIZE;
//
// for (int i =hint_block_start; i < nbBlocks && i <hint_block_start + hint_block_count; i++)
// {
// while (blocksFound <nbWanted &&(i +blocksFound) <nbBlocks &&!downloaded[i +blocksFound]
// &&requested[i +blocksFound] ==null &&(written ==null ||!written[i]))
// {
// requested[i +blocksFound] =ip;
// blocksFound++;
// }
// if (blocksFound >0){
//
// return new int[] {i, blocksFound};
// }
// }
// }
// }
//
// // scan piece to find first free block
// for (int i =0; i <nbBlocks; i++)
// {
// while (blocksFound <nbWanted &&(i +blocksFound) <nbBlocks &&!downloaded[i +blocksFound]
// &&requested[i +blocksFound] ==null &&(written ==null ||!written[i]))
// {
// requested[i +blocksFound] =ip;
// blocksFound++;
// }
// if (blocksFound >0)
// return new int[] {i, blocksFound};
// }
// return new int[] {-1, 0};
// }
//
// public void getAndMarkBlock(PEPeer peer, int index )
// {
// requested[index] = peer.getIp();
//
// if ( getNbUnrequested() <= 0 ){
//
// setRequested();
// }
// }
//
// public int getNbRequests()
// {
// int result =0;
// for (int i =0; i <nbBlocks; i++)
// {
// if (!downloaded[i] &&requested[i] !=null)
// result++;
// }
// return result;
// }
//
// public int getNbUnrequested()
// {
// int result =0;
// final boolean[] written =dmPiece.getWritten();
// for (int i =0; i <nbBlocks; i++ )
// {
// if (!downloaded[i] &&requested[i] ==null &&(written ==null ||!written[i]))
// result++;
// }
// return result;
// }
//
// /**
// * Assumption - single threaded with getAndMarkBlock
// */
// public boolean setRequested(PEPeer peer, int blockNumber)
// {
// if (!downloaded[blockNumber])
// {
// requested[blockNumber] =peer.getIp();
// return true;
// }
// return false;
// }
//
// public boolean
// isRequestable()
// {
// return( dmPiece.isDownloadable() && !( fully_downloaded || fully_requested ));
// }
//
// public int
// getBlockSize(
// int blockNumber)
// {
// if ( blockNumber == (nbBlocks - 1)){
//
// int length = dmPiece.getLength();
//
// if ((length % DiskManager.BLOCK_SIZE) != 0){
//
// return( length % DiskManager.BLOCK_SIZE );
// }
// }
//
// return DiskManager.BLOCK_SIZE;
// }
//
// public int getBlockNumber(int offset)
// {
// return offset /DiskManager.BLOCK_SIZE;
// }
//
// public int getNbBlocks()
// {
// return nbBlocks;
// }
//
// public List getPieceWrites()
// {
// List result;
// try{
// class_mon.enter();
//
// result = new ArrayList(writes);
// }finally{
//
// class_mon.exit();
// }
// return result;
// }
//
//
// public List getPieceWrites(int blockNumber) {
// final List result;
// try{
// class_mon.enter();
//
// result = new ArrayList(writes);
//
// }finally{
//
// class_mon.exit();
// }
// final Iterator iter = result.iterator();
// while(iter.hasNext()) {
// final PEPieceWriteImpl write = (PEPieceWriteImpl) iter.next();
// if(write.getBlockNumber() != blockNumber)
// iter.remove();
// }
// return result;
// }
//
//
// public List getPieceWrites(PEPeer peer) {
// final List result;
// try{
// class_mon.enter();
//
// result = new ArrayList(writes);
// }finally{
// class_mon.exit();
// }
// final Iterator iter = result.iterator();
// while(iter.hasNext()) {
// PEPieceWriteImpl write = (PEPieceWriteImpl) iter.next();
// if(peer == null || ! peer.getIp().equals(write.getSender()))
// iter.remove();
// }
// return result;
// }
//
// public List
// getPieceWrites(
// String ip )
// {
// final List result;
//
// try{
// class_mon.enter();
//
// result = new ArrayList(writes);
//
// }finally{
//
// class_mon.exit();
// }
//
// final Iterator iter = result.iterator();
//
// while(iter.hasNext()) {
//
// final PEPieceWriteImpl write = (PEPieceWriteImpl) iter.next();
//
// if ( !write.getSender().equals( ip )){
//
// iter.remove();
// }
// }
//
// return result;
// }
//
// public void reset()
// {
// dmPiece.reset();
// for (int i =0; i <nbBlocks; i++)
// {
// requested[i] =null;
// downloaded[i] =false;
// writers[i] =null;
// }
// fully_downloaded = false;
// time_last_download = 0;
// reservedBy =null;
// real_time_data=null;
// }
//
// public Object
// getRealTimeData()
// {
// return( real_time_data );
// }
//
// public void
// setRealTimeData(
// Object o )
// {
// real_time_data = o;
// }
//
// protected void addWrite(PEPieceWriteImpl write) {
// try{
// class_mon.enter();
//
// writes.add(write);
//
// }finally{
//
// class_mon.exit();
// }
// }
//
// public void
// addWrite(
// int blockNumber,
// String sender,
// byte[] hash,
// boolean correct )
// {
// addWrite( new PEPieceWriteImpl( blockNumber, sender, hash, correct ));
// }
//
// public String[] getWriters()
// {
// return writers;
// }
//
// public int getSpeed()
// {
// return speed;
// }
//
// public void setSpeed(int newSpeed)
// {
// speed =newSpeed;
// }
//
// public void
// setLastRequestedPeerSpeed(
// int peerSpeed )
// {
// // Up the speed on this piece?
// if (peerSpeed > speed ){
// speed++;
// }
// }
//
// /**
// * @return Returns the manager.
// */
// public PEPeerManager getManager()
// {
// return manager;
// }
//
// public void setReservedBy(String peer)
// {
// reservedBy =peer;
// }
//
// public String getReservedBy()
// {
// return reservedBy;
// }
//
// /** for a block that's already downloadedt, mark up the piece
// * so that the block will get downloaded again. This is used
// * when the piece fails hash-checking.
// */
// public void reDownloadBlock(int blockNumber)
// {
// downloaded[blockNumber] =false;
// requested[blockNumber] =null;
// fully_downloaded = false;
// writers[blockNumber] = null;
// dmPiece.reDownloadBlock(blockNumber);
// }
//
// /** finds all blocks downloaded by the given address
// * and marks them up for re-downloading
// * @param address String
// */
// public void reDownloadBlocks(String address)
// {
// for (int i =0; i <writers.length; i++ )
// {
// final String writer =writers[i];
//
// if (writer !=null &&writer.equals(address))
// reDownloadBlock(i);
// }
// }
//
// public void setResumePriority(int p)
// {
// resumePriority =p;
// }
//
// public int getResumePriority()
// {
// return resumePriority;
// }
//
// /**
// * @return int of availability in the swarm for this piece
// * @see org.gudy.azureus2.core3.peer.PEPeerManager.getAvailability(int pieceNumber)
// */
// public int getAvailability()
// {
// return manager.getAvailability(dmPiece.getPieceNumber());
// }
//
// /** This support method returns how many blocks have already been
// * written from the dmPiece
// * @return int from dmPiece.getNbWritten()
// * @see org.gudy.azureus2.core3.disk.DiskManagerPiece.getNbWritten()
// */
// public int getNbWritten()
// {
// return dmPiece.getNbWritten();
// }
//
// /** This support method returns the dmPiece's written array
// * @return boolean[] from the dmPiece
// * @see org.gudy.azureus2.core3.disk.DiskManagerPiece.getWritten()
// */
// public boolean[] getWritten()
// {
// return dmPiece.getWritten();
// }
// public boolean isWritten()
// {
// return dmPiece.isWritten();
// }
//
// public boolean isWritten( int block)
// {
// return dmPiece.isWritten( block );
// }
// public int getPieceNumber()
// {
// return dmPiece.getPieceNumber();
// }
//
// public int getLength()
// {
// return dmPiece.getLength();
// }
//
// public void setRequestable()
// {
// fully_downloaded = false;
// fully_requested = false;
//
// dmPiece.setDownloadable();
// }
//
// public String
// getString()
// {
// String text = "";
//
//// PiecePicker pp = manager.getPiecePicker();
//
// text += ( isRequestable()?"reqable,":"" );
// text += "req=" + getNbRequests() + ",";
// text += ( isRequested()?"reqstd,":"" );
// text += ( isDownloaded()?"downed,":"" );
// text += ( getReservedBy()!=null?"resrv,":"" );
// text += "speed=" + getSpeed() + ",";
//// text += ( pp==null?("pri=" + getResumePriority()):pp.getPieceString(dmPiece.getPieceNumber()));
//
// if ( text.endsWith(",")){
// text = text.substring(0,text.length()-1);
// }
//
// return( text );
// }
//}