/* ***************************************************************************+
 * ITX package (cnrg.itx) for telephony application programming.              *
 * Copyright (c) 1999  Cornell University, Ithaca NY.                         *
 * A copy of the license is distributed with this package.  Look in the docs  *
 * directory, filename GPL.  Contact information: bergmark@cs.cornell.edu     *
 ******************************************************************************/

package cnrg.itx.signal;

import cnrg.itx.datax.*;
import cnrg.itx.ds.*;

/** This class contains vital signaling information to identify and hangup peer applications.
 *  It also contains the data exchange connection that allows for data transfer.
 */
public class SignalConnection {
	/** Possible states for a SignalConnection object **/
	
	/** SignalConnection object is idle **/
	protected static final int IDLE = 0;
	/** SignalConnection object is dialing **/
	protected static final int DIALING = 1;
	/** SignalConnection object is connected to an application **/
	protected static final int CONNECTED = 2;
	
	/** The InvitePacket corresponding to the connection **/
	private InvitePacket myInvite;
	/** true if this DesktopSignaling originated the InvitePacket; false otherwise **/
	private boolean isMyInvitePacket;
	/** Connection object for data exchange **/
	private Connection myC = null;
	/** Peer's IP Address **/
	private String myPeerIP = "";
	/** Peer's listening port **/
	private int myPeerPort = -1;
	/** Peer's User ID **/
	private UserID myPeerUID = null;
	
	/** Unique Sequence # for this call **/
	private Long myConnSeqNumber = null;
	/** Unique Sequence # being used by peer for this call **/
	private Long myPeerSeqNumber = null;
	/** Keepalive thread **/
	protected KeepAlive myKeepAlive = null;
	
	/** Members for complete Dialing Control **/
	protected static int myCurrentState = IDLE;
	/** DialThread handle **/
	private DialThread myDialer = null;
	
	/** Default Constructor
	 * 
	 * @param None.
	 * @return void.
	 */
	public SignalConnection(){
		this(null, "", -1);
	}
		
	/** Constructor
	 * 
	 * @param c is the connection for data exchange
	 * @param ip is the IP address of peer
	 * @param p is the listening port of peer
	 * @return void.
	 */
	public SignalConnection(Connection c, String ip, int p){
		this(c,ip,p,null, null);
	}
	
	/** Constructor
	 * 
	 * @param c is the connection for data exchange
	 * @param ip is the IP address of peer
	 * @param p is the listening port of peer
	 * @param puid is the userID of the peer
	 * @param d is the DialThread to make the call
	 * 
	 * @return void.
	 * @see cnrg.itx.signal.DialThread
	 */
	public SignalConnection(Connection c, String ip, int p, UserID puid, DialThread d){
		myC = c;
		myPeerIP = ip;
		myPeerPort = p;
		myPeerUID = puid;
		myDialer = d;
	}
	
	
	/** This method sets the current state of the call
	 * 
	 * @param s is the integer representation of the state
	 * @return void.
	 */
	protected void setCurrentState(int s){
		myCurrentState = s;
	}
	
	/**
	 * Returns the InvitePacket associated with the current connection.
	 * 
	 * @return the InvitePacket
	 */
	public InvitePacket getInvite()
	{
		return myInvite;
	}
	
	/**
	 * Returns whether or not the InvitePacket originated with the current DesktopSignaling.
	 * 
	 * @return true if the InvitePacket originated with the current DesktopSignaling; false otherwise
	 */
	public boolean checkIfMyInvite()
	{
		return isMyInvitePacket;
	}

	/** Returns the data exchange connection
	 * 
	 * @param None
	 * @return Connection object
	 */
	public Connection getConnection(){
		return myC;
	}
	
	/** Returns the IP address of the peer
	 * 
	 * @param None
	 * @return String representation of peer's IP address
	 */
	public String getIP(){
		return myPeerIP;
	}
	
	/** Returns the listening port of the peer
	 * 
	 * @param None
	 * @return integer representation of peer's listening port
	 */
	public int getPort(){
		return myPeerPort;
	}	
	
	/** Returns the uniques sequence number being used for this call
	 * 
	 * @param None
	 * @return Long object representing the sequence number
	 */
	public Long getSeqNumber(){
		return myConnSeqNumber;
	}

	/** Returns the uniques sequence number being used by the peer for this call
	 * 
	 * @param None
	 * @return Long object representing the sequence number being used by the peer
	 */
	public Long getPeerSeqNumber(){
		return myPeerSeqNumber;
	}

	/** Sets the peer's IP address
	 * 
	 * @param ip is the String representation of peer's IP address
	 * @return void.
	 */
	public void setIP(String ip){
		myPeerIP = ip;
	}
	
	/** Sets the peer's listening port
	 * 
	 * @param p is the integer representation of peer's port
	 * @return void.
	 */
	public void setPort(int p){
		myPeerPort = p;
	}
	
	/** Sets the sequence number for this connection
	 * 
	 * @param s is the Long representation of the sequence number
	 * @return void.
	 */
	public void setSeqNumber(Long s){
		myConnSeqNumber = s;
	}

	/** Sets the sequence number being used by the peer for this connection
	 * 
	 * @param s is the Long representation of the sequence number being used by the peer
	 * @return void.
	 */
	public void setPeerSeqNumber(Long s){
		myPeerSeqNumber = s;
	}
	
	/** Sets the KeepAlive object handle
	 * 
	 * @param ks is the KeepAlive object
	 * @return void.
	 */
	public void setKeepAlive(KeepAlive ka){
		myKeepAlive = ka;
	}
	
	/**
	 * @return the KeepAlive object
	 */
	public KeepAlive getKeepAlive(){
		return myKeepAlive;
	}
	
	/** Sets the KeepAlive object's wait period
	 * 
	 * @param timeout is the wait period in milli seconds
	 * @return void.
	 */
	public void setKeepAliveTime(int timeout){
		myKeepAlive.setKeepAliveTime(timeout);
	}
	
	/** Sets the peer's UserID
	 * 
	 * @param uid is the UserID object representing the peer's userID.
	 * @return void.
	 */
	public void setPeerUID(UserID uid){
		myPeerUID = uid;
	}
	
	/**
	 * @return the peer UserID object
	 */
	public UserID getPeerUID(){
		return myPeerUID;
	}
	
	/** Sets the DialThread to be used for the call.
	 * 
	 * @param d is the instantiated DialThread object
	 * @return void.
	 */
	public void setDialer(DialThread d){
		myDialer = d;
	}
	
	/** Dialing Related Information **/

	/**
	 * @return TRUE if the current state is idle, FALSE otherwise.
	 */
	public boolean isIdle(){
		return (myCurrentState == IDLE);
	}
	
	/**
	 * @return TRUE if the current state is Dialing, FALSE otherwise.
	 */
	public boolean isDialing(){
		return (myCurrentState == DIALING);
	}
	
	/**
	 * @return TRUE if the current state is Connected, FALSE otherwise.
	 */
	public boolean isConnected(){
		return (myCurrentState == CONNECTED);
	}
	
	/**
	 * @return the current state
	 */
	public int getCurrentState(){
		return myCurrentState;
	}
	
	/** Sets the conection object to use for data exchange
	 * 
	 * @param c is the Connection object to be used
	 * @return void.
	 */
	public void setConnection(Connection c){
		myC = c;
	}
	
	/**
	 * Sets the InvitePacket associated with the connection.
	 * 
	 * @param ip the InvitePacket
	 */
	public void setInvite(InvitePacket ip)
	{
		myInvite = ip;
	}
	
	/**
	 * Sets whether or not this DesktopSignaling created the InvitePacket.
	 * 
	 * @param ifSource true if this DesktopSignaling created the InvitePacket; false otherwise
	 */
	public void setSourceInvite(boolean ifSource)
	{
		isMyInvitePacket = ifSource;
	}
	
	/** Non-blocking dialing Functionality **/
	
	/** Starts dialing the peer.
	 * 
	 * @param None.
	 * @return void
	 */
	public void startCall(){
		System.out.println("Dialing user...");
		myDialer.start();		
		myCurrentState = DIALING;
	}
	
	/** Aborts the current dial sequence.
	 * 
	 * @param None.
	 * @return void.
	 */
	public void abortCall(){
		System.out.println("Aborting Call.");
		if (isDialing()){
			myDialer.cleanup();
			myCurrentState = IDLE;
		}
	}
	
	/** Creates and starts the KeepAlive thread for the connection
	 * 
	 * @param ds the handle to DesktopSignaling.
	 * @return void.
	 */
	public void startKeepAlive(DesktopSignaling ds){
		if (isConnected()){
			myKeepAlive = new KeepAlive(ds, this);
			myKeepAlive.start();
		}
	}
	
/****************** Method calls forwarded to Data Exchange's Connection method implementations ********************/
	/**
	 * @see cnrg.itx.datax.Connection.open()
	*/
	public void open() throws DataException {
		myC.open();
	}
	
	/**
	 * @see cnrg.itx.datax.Connection.close()
	*/
	public void close() throws DataException{
		myC.close();
	}

	/**
	 * @see cnrg.itx.datax.Connection.getInputChannel()
	*/
	public Channel getInputChannel()
	{
		return myC.getInputChannel();
	}
	
	/**
	 * @see cnrg.itx.datax.Connection.getOutputChannel()
	*/
	public Channel getOutputChannel()
	{
		return myC.getOutputChannel();
	}
	
	/**
	 * @see cnrg.itx.datax.Connection.setInputChannel(Channel c)
	*/
	public void setInputChannel(Channel c)
	{
		myC.setInputChannel(c);
	}
	
	/**
	 * @see cnrg.itx.datax.Connection.setOutputChannel(Channel c)
	*/
	public void setOutputChannel(Channel c)
	{
		myC.setOutputChannel(c);
	}
	
	/**
	 * @see cnrg.itx.datax.Connection.getStatistics()
	*/
	public Stats getStatistics()
	{
		return myC.getStatistics();
	}

	/**
	 * @see cnrg.itx.datax.Connection.getProperties()
	*/
	public PropertiesCollection getProperties()
	{
		return myC.getProperties();
	}

	/**
	 * @see cnrg.itx.datax.Connection.setProperties(PropertiesCollection pc)
	*/
	public void setProperties(PropertiesCollection pc)
	{
	   myC.setProperties(pc);
	}

	/**
	 * @see cnrg.itx.datax.Connection.setPeerProperties(PropertiesCollection pc)
	*/
	public void setPeerProperties(PropertiesCollection pc) throws DataException
	{
		myC.setPeerProperties(pc);
	}
}
