/*
 * Copyright (C) 2005 Luca Veltri - University of Parma - Italy
 * 
 * This file is part of MjSip (http://www.mjsip.org)
 * 
 * MjSip 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.
 * 
 * MjSip 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.
 * 
 * You should have received a copy of the GNU General Public License
 * along with MjSip; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 * 
 * Author(s):
 * Luca Veltri (luca.veltri@unipr.it)
 */

package org.zoolu.sip.transaction;

import org.zoolu.sip.provider.*;
import org.zoolu.sip.message.*;
import org.zoolu.tools.Timer;
import org.zoolu.tools.TimerListener;
import org.zoolu.tools.Log;
import org.zoolu.tools.LogLevel;

/**
 * Abstract class Transaction is hinerited by classes ClientTransaction,
 * ServerTransaction, InviteClientTransaction and InviteServerTransaction. An
 * Object Transaction is responsable to handle a new SIP transaction.<BR>
 * The changes of the internal status and the received messages are fired to the
 * TransactionListener passed to the Transaction Objects.<BR>
 */
public abstract class Transaction implements SipProviderListener, TimerListener {
	/** Transactions counter */
	protected static int transaction_counter = 0;

	// all transaction states:
	/** State Waiting, used only by server transactions */
	static final int STATE_IDLE = 0;
	/** State Waiting, used only by server transactions */
	static final int STATE_WAITING = 1;
	/** State Trying */
	static final int STATE_TRYING = 2;
	/** State Proceeding */
	static final int STATE_PROCEEDING = 3;
	/** State Completed */
	static final int STATE_COMPLETED = 4;
	/** State Confirmed, used only by invite server transactions */
	static final int STATE_CONFIRMED = 5;
	/** State Waiting. */
	static final int STATE_TERMINATED = 7;

	/** Gets the transaction state. */
	static String getStatus(int st) {
		switch (st) {
		case STATE_IDLE:
			return "T_Idle";
		case STATE_WAITING:
			return "T_Waiting";
		case STATE_TRYING:
			return "T_Trying";
		case STATE_PROCEEDING:
			return "T_Proceeding";
		case STATE_COMPLETED:
			return "T_Completed";
		case STATE_CONFIRMED:
			return "T_Confirmed";
		case STATE_TERMINATED:
			return "T_Terminated";
		default:
			return null;
		}
	}

	/** Transaction sequence number */
	int transaction_sqn;

	/** Event logger. */
	Log log;

	/**
	 * Lower layer dispatcher that sends and receive messages. The messages
	 * received by the SipProvider are fired to the Transaction by means of the
	 * onReceivedMessage() method.
	 */
	SipProvider sip_provider;

	/** Internal state-machine status */
	int status;

	/** transaction request message/method */
	Message request;

	/** the Transaction ID */
	TransactionIdentifier transaction_id;

	/** Transaction connection id */
	ConnectionIdentifier connection_id;

	/** Costructs a new Transaction */
	protected Transaction(SipProvider sip_provider) {
		this.sip_provider = sip_provider;
		log = sip_provider.getLog();
		this.transaction_id = null;
		this.request = null;
		this.connection_id = null;
		this.transaction_sqn = transaction_counter++;
		this.status = STATE_IDLE;
	}

	/** Changes the internal status */
	void changeStatus(int newstatus) {
		status = newstatus;
		// transaction_listener.onChangedTransactionStatus(status);
		printLog("changed transaction state: " + getStatus(), LogLevel.MEDIUM);
	}

	/** Whether the internal status is equal to <i>st</i> */
	boolean statusIs(int st) {
		return status == st;
	}

	/** Gets the current transaction state. */
	String getStatus() {
		return getStatus(status);
	}

	/** Gets the SipProvider of this Transaction. */
	public SipProvider getSipProvider() {
		return sip_provider;
	}

	/** Gets the Transaction request message */
	public Message getRequestMessage() {
		return request;
	}

	/** Gets the Transaction method */
	public String getTransactionMethod() {
		return request.getTransactionMethod();
	}

	/** Gets the transaction-ID */
	public TransactionIdentifier getTransactionId() {
		return transaction_id;
	}

	/** Gets the transaction connection id */
	public ConnectionIdentifier getConnectionId() {
		return connection_id;
	}

	/**
	 * Method derived from interface SipListener. It's fired from the
	 * SipProvider when a new message is catch for to the present
	 * ServerTransaction.
	 */
	public void onReceivedMessage(SipProvider provider, Message msg) { // do
		// nothing
	}

	/**
	 * Method derived from interface TimerListener. It's fired from an active
	 * Timer.
	 */
	public void onTimeout(Timer to) { // do nothing
	}

	/** Terminates the transaction. */
	public abstract void terminate();

	// **************************** Logs ****************************/

	/** Adds a new string to the default Log */
	protected void printLog(String str, int level) {
		if (log != null)
			log.println("Transaction#" + transaction_sqn + ": " + str, level
					+ SipStack.LOG_LEVEL_TRANSACTION);
	}

	/** Adds a WARNING to the default Log */
	protected void printWarning(String str, int level) {
		printLog("WARNING: " + str, level);
	}

	/** Adds the Exception to the log file */
	protected void printException(Exception e, int level) {
		if (log != null)
			log.printException(e, level + SipStack.LOG_LEVEL_TRANSACTION);
	}

}
