/*
 * File    : PEPeerSocket.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, or
 * (at your option) any later version.
 *
 * 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
 */

/*
 * Created on 4 juil. 2003
 *
 */
package org.gudy.azureus2.core3.peer;


import java.net.InetAddress;
import java.util.List;
import java.util.Map;

import org.gudy.azureus2.core3.disk.DiskManagerReadRequest;
import org.gudy.azureus2.plugins.network.Connection;

import com.aelitis.azureus.core.networkmanager.LimitedRateGroup;
import com.aelitis.azureus.core.peermanager.messaging.Message;
import com.aelitis.azureus.core.peermanager.piecepicker.util.BitFlags;
import com.aelitis.azureus.core.tag.Taggable;


/**
 * @author Olivier
 * @author MjrTom
 *			2005/Oct/08: lastPiece handling
 *
 */

public interface 
PEPeer 
	extends Taggable
{
	public final static int CONNECTING 		= 10;
	public final static int HANDSHAKING 	= 20;
	public final static int TRANSFERING 	= 30;
	public final static int CLOSING      	= 40;
	public final static int DISCONNECTED 	= 50;
	
	
	// these should be maintained to match above list ordinals /10
	// if they don't than some debug info won't work right (not too big of a deal)
	public final static String[] StateNames = { "Twinkle",
		"Connecting", "Handshaking", "Transfering", "Closing", "Disconnected"
	};
	
	public static final int MESSAGING_BT_ONLY = 1;
	public static final int MESSAGING_AZMP = 2;
	public static final int MESSAGING_LTEP = 3;
	//used for plugins, such as webseeds
	public static final int MESSAGING_EXTERN = 4;
	
	
  /**
   * Add peer listener.
   * @param listener
   */
  public void addListener( PEPeerListener listener );
  
  
  /**
   * Remove peer listener.
   * @param listener
   */
  public void removeListener( PEPeerListener listener );
  
  
	public int getPeerState();	// from above set
  
	public PEPeerManager
	getManager();

	public String
	getPeerSource();
	
	public byte[] getId();

	public String getIp();
	
	/**
	 * @return an ipv6 address under which the peer should be connectable if it announced one, null otherwise
	 */
	public InetAddress getAlternativeIPv6();
  
  /**
   * Get the peer's local TCP connection port.
   * @return local port
   */
  public int getPort();
 
	/**
	 * Gets the host name for the IP, if possible, IP as string otherwise
   * @return hostname or IP
   */
	public String getIPHostName();

  
  /**
   * Get the TCP port this peer is listening for incoming connections on.
   * @return TCP port, or 0 if port is unknown
   */
  public int getTCPListenPort();
  
  /**
   * Get the UDP port this peer is listening for incoming connections on.
   * @return UDP port, or 0 if port is unknown
   */
  public int getUDPListenPort();

  /**
   * Get the UDP port this peer is listening on for non-data connections
   * @return
   */
  
  public int getUDPNonDataListenPort();
  
	public BitFlags getAvailable();
	/**
	 * @param pieceNumber int
	 * @return true if this peers makes this piece available
	 */
	public boolean isPieceAvailable(int pieceNumber);

	public boolean
	transferAvailable();
	
	public void setSnubbed(boolean b);	// explicit un-snub
  
  /**
   * Is the peer choking me.
   * @return true if I am choked by the peer, false if not
   */
	public boolean isChokingMe();
	
	public boolean isUnchokeOverride();

  /**
   * Am I choking the peer.
   * @return true if the peer is choked, false if not
   */
	public boolean isChokedByMe();

	public void
	sendChoke();
	
	public void
	sendUnChoke();
	
  /**
   * Am I Interested in the peer.
   * @return true if peer is interesting, false if not
   */
	public boolean isInteresting();

  /**
   * Is the peer Interested in me.
   * @return true if the peer is interested in me, false if not
   */
	public boolean isInterested();

	/**
	 * checks several factors within the object so the caller wouldn't need to
	 * for convienience and speed.
	 * @return true if none of several criteria indicate a request can't be made of the peer  
	 */
	public boolean isDownloadPossible();
	
	public boolean isSeed();
	
	/**
	 * @return true if the peer is only uploading and can't use the data we have
	 *         to offer (we're seeding) or we can't use the data he has to offer
	 *         (we're downloading)
	 */
	public boolean isRelativeSeed();
 
	public boolean isSnubbed();
	
	public long getSnubbedTime();
 
	public PEPeerStats getStats();
 	
	public boolean isIncoming();

	public boolean hasReceivedBitField();
	
  /**
   * Get the peer's torrent completion percentage in thousand-notation,
   * i.e. 53.7% is returned as the value 0537.
   * @return the percentage the peer has complete
   */
	public int getPercentDoneInThousandNotation();

  
	public String getClient();

	public boolean isOptimisticUnchoke();
  public void setOptimisticUnchoke( boolean is_optimistic );
	
	//Used in super-seed mode
	//The lower the better
	public void setUploadHint(int timeToSpread);
	
	public int getUploadHint();
	
	public void setUniqueAnnounce(int uniquePieceNumber);
	
	public int getUniqueAnnounce();
   
	public int getConsecutiveNoRequestCount();
	public void setConsecutiveNoRequestCount( int num );

	public void setUploadRateLimitBytesPerSecond( int bytes );
	public void setDownloadRateLimitBytesPerSecond( int bytes );
	public int getUploadRateLimitBytesPerSecond();
	public int getDownloadRateLimitBytesPerSecond();
	
	public void
	addRateLimiter(
		LimitedRateGroup	limiter,
		boolean				upload );
	
	public LimitedRateGroup[]
	getRateLimiters(
		boolean				upload );
	
	public void
	removeRateLimiter(
		LimitedRateGroup	limiter,
		boolean				upload );
	
	public void
	setUploadDisabled(
		Object				key,
		boolean				disabled );
	
	public void
	setDownloadDisabled(
		Object				key,
		boolean				disabled );

	public boolean
	isUploadDisabled();
	
	public boolean
	isDownloadDisabled();
	
	public void
	updateAutoUploadPriority(
		Object	key,
		boolean	inc );
	
  /** To retreive arbitrary objects against a peer. */
  public Object getData (String key);
  /** To store arbitrary objects against a peer. */
  public void setData (String key, Object value);
  
  public Object getUserData (Object key);
  /** To store arbitrary objects against a peer. */
  public void setUserData (Object key, Object value);

  /**
   * Get the connection that backs this peer.
   * @return connection
   */
  
  public Connection getPluginConnection();
  
  
  /**
   * Whether or not this peer supports the advanced messaging API.
   * @return true if extended messaging is supported, false if not
   */
  public boolean supportsMessaging();
  
  /**
   * @Return the handshaked messaging type, {@link PEPeer} constants
   */ 
  public int getMessagingMode();

  
  
  /**
   * Returns name of encryption used by the peer
   * @return
   */
  public String
  getEncryption();
  
  public String
  getProtocol();
  
  /**
   * Get the list of messages that this peer and us both understand.
   * @return messages available for use, or null of supported is yet unknown or unavailable
   */
  public Message[] getSupportedMessages();
  
  /**
   * adds the reserved piece for piece picking by this peer
   */
  public void addReservedPieceNumber(int pieceNumber);
  
  public void removeReservedPieceNumber(int pieceNumber);
  
  /**
   * Get the reserved pieces for piece picking by this peer
   */
  public int[] getReservedPieceNumbers();
  
  public int getIncomingRequestCount();
  public int getOutgoingRequestCount();
  
  /**
   * amount of data queued for delivery to peer
   * @return
   */
  
  public int getOutboundDataQueueSize();
  
  /**
   * get a list of piece numbers the peer has requested
   * @return list of Long() representing the piece number requested, in order
   */
  public int[] getIncomingRequestedPieceNumbers();
  
  /**
   * get a list of piece numbers the we have requested from peer
   * @return list of Long() representing the piece number requested, oldest
   *          to newest
   */
  public int[] getOutgoingRequestedPieceNumbers();
  
  public int
  getPercentDoneOfCurrentIncomingRequest();
  
  public int
  getPercentDoneOfCurrentOutgoingRequest();
  
  public long
  getBytesRemaining();
  
  	/**
  	 * Enable suspended lazy bitfield for this peer - we will appear incomplete until this is disabled, at
  	 * which point (well, fairly soon after) the bitfield will be completed  
  	 * @param enable
  	 */
  
  public void
  setSuspendedLazyBitFieldEnabled(
		boolean	enable );
  
  /**
   * Get the time since this connection was first established.
   * NOTE: This method will always return 0 at any time before
   * the underlying transport is fully connected, i.e. before
   * handshaking begins.
   * @return time count in ms
   */
  public long getTimeSinceConnectionEstablished();

	public void setLastPiece(int i);
	public int getLastPiece();
	
	public boolean
	isLANLocal();
	
		/**
		 * Send a request hint to the peer. 
		 * @param piece_number
		 * @param offset
		 * @param length
		 * @param life
		 * @return true if sent, false otherwise
		 */
	
	public boolean
	sendRequestHint(
		int		piece_number,
		int		offset,
		int		length,
		int		life );
	
		/**
		 * Get current request hint for a given piece for this peer. 
		 * @return null if no hint int[]{ piece_number, offset, length } if hint found
		 */
	
	public int[]
	getRequestHint();
	        		 
	public void
	clearRequestHint();

	public void
	sendStatsRequest(
		Map		request );
	
	public void
	sendRejectRequest(
		DiskManagerReadRequest	request );
	
	public void
	setHaveAggregationEnabled(
		boolean		enabled );
	
	public byte[] getHandshakeReservedBytes();
	
	public String getClientNameFromPeerID();
	public String getClientNameFromExtensionHandshake();
	
	public boolean isPriorityConnection();
	
	public void setPriorityConnection( boolean is_priority ); 
}