/***********************************************************
 Copyright (C) 2004 VeriSign, Inc.

 This library is free software; you can redistribute it and/or
 modify it under the terms of the GNU Lesser General Public
 License as published by the Free Software Foundation; either
 version 2.1 of the License, or (at your option) any later version.

 This library 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
 Lesser General Public License for more details.

 You should have received a copy of the GNU Lesser General Public
 License along with this library; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

 http://www.verisign.com/nds/naming/namestore/techdocs.html
 ***********************************************************/
package com.verisign.epp.namestore.interfaces;

//----------------------------------------------
//
// imports...
//
//----------------------------------------------
// Java Core Imports

import java.util.Random;

import junit.extensions.TestSetup;
import junit.framework.Assert;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;

import org.apache.log4j.Logger;

import com.verisign.epp.codec.contact.EPPContactTransferResp;
import com.verisign.epp.codec.domain.EPPDomainTransferResp;
import com.verisign.epp.codec.gen.EPPResponse;
import com.verisign.epp.codec.gen.EPPResult;
import com.verisign.epp.codec.lowbalancepoll.EPPLowBalancePollResponse;
import com.verisign.epp.codec.rgppoll.EPPRgpPollResponse;
import com.verisign.epp.interfaces.EPPApplicationSingle;
import com.verisign.epp.interfaces.EPPCommandException;
import com.verisign.epp.interfaces.EPPSession;
import com.verisign.epp.pool.EPPSessionPool;
import com.verisign.epp.util.EPPCatFactory;
import com.verisign.epp.util.InvalidateSessionException;
import com.verisign.epp.util.TestThread;
import com.verisign.epp.util.TestUtil;

/**
 * Tests the handling of NameStore poll messages.  This test 
 * also functions as a sample for handling all of the possible
 * poll messages generated by NameStore.    
 * 
 * @see com.verisign.epp.namestore.interfaces.NSDomain
 * @see com.verisign.epp.interfaces.EPPDomain
 */
public class NSPollTst extends TestCase {

	/**
	 * Handle to the Singleton EPP Application instance
	 * (<code>EPPApplicationSingle</code>)
	 */
	private static EPPApplicationSingle app = EPPApplicationSingle
			.getInstance();

	/** Name of configuration file to use for test (default = epp.config). */
	private static String configFileName = "epp.config";

	/** Logging category */
	private static final Logger cat = Logger.getLogger(NSPollTst.class
			.getName(), EPPCatFactory.getInstance().getFactory());

	/** EPP Session pool associated with test */
	private static EPPSessionPool sessionPool = null;

	/**
	 * Random instance for the generation of unique objects (hosts, IP
	 * addresses, etc.).
	 */
	private Random rd = new Random(System.currentTimeMillis());

	/**
	 * Allocates an <code>NSPollTst</code> with a logical name.  The
	 * constructor will initialize the base class <code>TestCase</code> with
	 * the logical name.
	 *
	 * @param name Logical name of the test
	 */
	public NSPollTst(String name) {
		super(name);
	}

	// End NSPollTst(String)

	/**
	 * Unit test of <code>EPPSession.sendPoll</code> command.
	 */
	public void testPoll() {
		printStart("testPoll");

		EPPSession theSession = null;
		try {
			theSession = this.borrowSession();

			EPPResponse theResponse = null;
			Long numMsgs = null;

			try {
				NSDomain theDomain = new NSDomain(theSession);
				theDomain.addDomainName("NSPollTst.com");
				theDomain.setAuthString("MyAuth");
				theDomain.sendCreate();
				
				theSession.setTransId("ABC-12345-XYZ");
				theSession.setPollOp(EPPSession.OP_REQ);
				theResponse = theSession.sendPoll();
				
				while (theResponse.getResult().getCode() == EPPResult.SUCCESS_POLL_MSG) {
					
					// poll response
					System.out.println("testPoll: Poll Response = [" + theResponse
							+ "]\n\n");

					// Domain Transfer notification
					if (theResponse instanceof EPPDomainTransferResp) {
						System.out.println("testPoll: Got domain transfer notification");
						
						EPPDomainTransferResp theMsg = (EPPDomainTransferResp) theResponse;
						
						String theStatus = theMsg.getTransferStatus();
						
						// Transfer request?
						if (theStatus.equals(EPPDomainTransferResp.TRANSFER_PENDING)) {
							System.out.println("testPoll: Got domain transfer request notification");
						} // Transfer approved?
						else if (theStatus.equals(EPPDomainTransferResp.TRANSFER_CLIENT_APPROVED)) {
							System.out.println("testPoll: Got domain transfer approve notification");							
						} // Transfer cancelled?
						else if (theStatus.equals(EPPDomainTransferResp.TRANSFER_CLIENT_CANCELLED)) {
							System.out.println("testPoll: Got domain transfer cancelled notification");														
						} // Transfer rejected?
						else if (theStatus.equals(EPPDomainTransferResp.TRANSFER_CLIENT_REJECTED)) {
							System.out.println("testPoll: Got domain transfer rejected notification");																					
						} // Tranfer auto approved?
						else if (theStatus.equals(EPPDomainTransferResp.TRANSFER_SERVER_APPROVED)) {
							System.out.println("testPoll: Got domain transfer auto approve notification");																										
						} // Tranfer auto cancelled?
						else if (theStatus.equals(EPPDomainTransferResp.TRANSFER_SERVER_CANCELLED)) {
							System.out.println("testPoll: Got domain transfer auto cancelled notification");																										
						}
						else {
							System.out.println("testPoll: Unknown domain transfer status [" + theStatus + "]");																																	
						}
					} // Contact transfer notification
					else if (theResponse instanceof EPPContactTransferResp) {
							System.out.println("testPoll: Got contact transfer notification");
							
							EPPContactTransferResp theMsg = (EPPContactTransferResp) theResponse;
							
							String theStatus = theMsg.getTransferStatus();
							
							// Transfer request?
							if (theStatus.equals(EPPContactTransferResp.TRANSFER_PENDING)) {
								System.out.println("testPoll: Got contact transfer request notification");
							} // Transfer approved?
							else if (theStatus.equals(EPPContactTransferResp.TRANSFER_CLIENT_APPROVED)) {
								System.out.println("testPoll: Got contact transfer approve notification");							
							} // Transfer cancelled?
							else if (theStatus.equals(EPPContactTransferResp.TRANSFER_CLIENT_CANCELLED)) {
								System.out.println("testPoll: Got contact transfer cancelled notification");														
							} // Transfer rejected?
							else if (theStatus.equals(EPPContactTransferResp.TRANSFER_CLIENT_REJECTED)) {
								System.out.println("testPoll: Got contact transfer rejected notification");																					
							} // Transfer auto approved?
							else if (theStatus.equals(EPPContactTransferResp.TRANSFER_SERVER_APPROVED)) {
								System.out.println("testPoll: Got contact transfer auto approve notification");																										
							} // Transfer auto cancelled?
							else if (theStatus.equals(EPPContactTransferResp.TRANSFER_SERVER_CANCELLED)) {
								System.out.println("testPoll: Got contact transfer auto cancelled notification");																										
							}
							else {
								System.out.println("testPoll: Unknown contact transfer status [" + theStatus + "]");																																	
							}
			
					} // low balance notification
					else if (theResponse instanceof EPPLowBalancePollResponse) {
						System.out.println("testPoll: Got low balance notification");						
					} // RGP notification
					else if (theResponse instanceof EPPRgpPollResponse) {
						System.out.println("testPoll: Got RGP notification");						
					} // Domain pending action notification
					else if (theResponse instanceof com.verisign.epp.codec.domain.EPPDomainPendActionMsg) {
						System.out.println("testPoll: Got domain pending action notification");												
					} // Unknown general message
					else {
						System.out.println("testPoll: Got general notification");
					}
					
					// Acknowledge the current message
					theSession.setPollOp(EPPSession.OP_ACK);
					theSession.setMsgID(theResponse.getMsgQueue().getId());
					theResponse = theSession.sendPoll();
					
					// Ack response
					System.out.println("doPoll: Poll ACK Response = [" + theResponse
							+ "]\n\n");

					theSession.setPollOp(EPPSession.OP_REQ);
					theResponse = theSession.sendPoll();
				}

			}
			catch (EPPCommandException ex) {
				TestUtil.handleException(theSession, ex);
			}


		}
		catch (InvalidateSessionException ex) {
			this.invalidateSession(theSession);
			theSession = null;
		}
		finally {
			if (theSession != null) this.returnSession(theSession);
		}

		printEnd("testPoll");
	}


	
	/**
	 * Unit test of <code>EPPSession.endSession</code>. One session in the
	 * session pool wil be ended.
	 */
	public void testEndSession() {
		printStart("testEndSession");

		EPPSession theSession = null;
		try {
			theSession = this.borrowSession();
			sessionPool.invalidateObject(theSession);
			theSession = null;
		}
		catch (Exception ex) {
			ex.printStackTrace();
			Assert.fail("testEndSession(): Exception invalidating session: "
					+ ex);
		}
		finally {
			if (theSession != null) this.returnSession(theSession);
		}

		printEnd("testEndSession");
	}

	// End NSPollTst.endSession()

	/**
	 * JUNIT <code>setUp</code> method
	 */
	protected void setUp() {

	}

	// End NSPollTst.setUp();

	/**
	 * JUNIT <code>tearDown</code>, which currently does nothing.
	 */
	protected void tearDown() {
	}

	// End NSPollTst.tearDown();

	/**
	 * JUNIT <code>suite</code> static method, which returns the tests
	 * associated with <code>NSPollTst</code>.
	 *
	 * @return DOCUMENT ME!
	 */
	public static Test suite() {
		return new NSPollTstSetup(new TestSuite(NSPollTst.class));
	}

	// End NSPollTst.suite()
	
	/**
	 * Setup framework from running NSPollTst tests.
	 */
	private static class NSPollTstSetup extends TestSetup {
		
		/**
		 * Creates setup instance for passed in tests.
		 * 
		 * @param aTest Tests to execute
		 */
		public NSPollTstSetup(Test aTest) {
			super(aTest);
		}

		/**
		 * Setup framework for running NSPollTst tests.
		 */
		protected void setUp() throws Exception {
			super.setUp();
			
			String theConfigFileName = System.getProperty("EPP.ConfigFile");
			if (theConfigFileName != null) configFileName = theConfigFileName;

			try {
				app.initialize(configFileName);
			}
			catch (EPPCommandException e) {
				e.printStackTrace();
				Assert.fail("Error initializing the EPP Application: " + e);
			}

			// Initialize the session pool
			try {
				sessionPool = EPPSessionPool.getInstance();
				sessionPool.init();
			}
			catch (Exception ex) {
				ex.printStackTrace();
				Assert.fail("Error initializing the session pool: " + ex);
			}

		}

		/**
		 * Tear down framework from running NSPollTst tests.
		 */
		protected void tearDown() throws Exception {
			super.tearDown();
			EPPSessionPool.getInstance().close();
		}
	}

	/**
	 * Unit test main, which accepts the following system property options: <br>
	 * 
	 * <ul>
	 * <li>iterations Number of unit test iterations to run</li>
	 * <li>validate Turn XML validation on (<code>true</code>) or off (
	 * <code>false</code>). If validate is not specified, validation will be
	 * off.</li>
	 * </ul>
	 * 
	 * 
	 * @param args
	 *            DOCUMENT ME!
	 */
	public static void main(String[] args) {
		// Override the default configuration file name?
		if (args.length > 0) {
			configFileName = args[0];
		}

		// Number of Threads
		int numThreads = 1;
		String threadsStr = System.getProperty("threads");

		if (threadsStr != null) {
			numThreads = Integer.parseInt(threadsStr);
		}

		// Run test suite in multiple threads?
		if (numThreads > 1) {
			// Spawn each thread passing in the Test Suite
			for (int i = 0; i < numThreads; i++) {
				TestThread thread = new TestThread("NSPollTst Thread " + i,
						NSPollTst.suite());
				thread.start();
			}
		}
		else { // Single threaded mode.
			junit.textui.TestRunner.run(NSPollTst.suite());
		}

		try {
			app.endApplication();
		}
		catch (EPPCommandException e) {
			e.printStackTrace();
			Assert.fail("Error ending the EPP Application: " + e);
		}
	}

	// End NSPollTst.main(String [])


	/**
	 * Print the start of a test with the <code>Thread</code> name if the
	 * current thread is a <code>TestThread</code>.
	 *
	 * @param aTest name for the test
	 */
	public static void printStart(String aTest) {
		if (Thread.currentThread() instanceof TestThread) {
			System.out.print(Thread.currentThread().getName() + ": ");
			cat
					.info(Thread.currentThread().getName() + ": " + aTest
							+ " Start");
		}

		System.out.println("Start of " + aTest);
		System.out
				.println("****************************************************************\n");
	}

	// End NSPollTst.testStart(String)

	/**
	 * Print the end of a test with the <code>Thread</code> name if the current
	 * thread is a <code>TestThread</code>.
	 *
	 * @param aTest name for the test
	 */
	public static void printEnd(String aTest) {
		System.out
				.println("****************************************************************");

		if (Thread.currentThread() instanceof TestThread) {
			System.out.print(Thread.currentThread().getName() + ": ");
			cat.info(Thread.currentThread().getName() + ": " + aTest + " End");
		}

		System.out.println("End of " + aTest);
		System.out.println("\n");
	}

	// End NSPollTst.testEnd(String)

	/**
	 * Utility method to borrow a session from the session pool.
	 * All exceptions will result in the test failing.  This method
	 * should only be used for positive session pool tests.
	 * 
	 * @return Session from the session pool
	 */
	private EPPSession borrowSession() {
		EPPSession theSession = null;
		try {
			theSession = sessionPool.borrowObject();
		}
		catch (Exception ex) {
			ex.printStackTrace();
			Assert.fail("borrowSession(): Exception borrowing session: " + ex);
		}

		return theSession;
	}

	/**
	 * Utility method to return a session to the session pool.  
	 * This should be placed in a finally block.  All exceptions will
	 * result in the test failing.
	 * 
	 * @param aSession Session to return to the pool
	 */
	private void returnSession(EPPSession aSession) {
		try {
			if (aSession != null) sessionPool.returnObject(aSession);
		}
		catch (Exception ex) {
			ex.printStackTrace();
			Assert.fail("returnSession(): Exception returning session: " + ex);
		}
	}

	/**
	 * Utility method to invalidate a session in the session pool.  
	 * This should be placed in an exception block.  
	 * 
	 * @param aSession Session to invalidate in the pool
	 */
	private void invalidateSession(EPPSession aSession) {
		try {
			if (aSession != null) sessionPool.invalidateObject(aSession);
		}
		catch (Exception ex) {
			ex.printStackTrace();
			Assert.fail("invalidateSession(): Exception invalidating session: " + ex);
		}
	}
	

	/**
	 * Handle a response by printing out the result details.
	 * 
	 * @param aResponse the response to handle
	 */
	private void handleResponse(EPPResponse aResponse) {

		for (int i = 0; i < aResponse.getResults().size(); i++) {
			EPPResult theResult = (EPPResult) aResponse.getResults().elementAt(
					i);

			System.out.println("Result Code    : " + theResult.getCode());
			System.out.println("Result Message : " + theResult.getMessage());
			System.out.println("Result Lang    : " + theResult.getLang());

			if (theResult.isSuccess()) {
				System.out.println("Command Passed ");
			}
			else {
				System.out.println("Command Failed ");
			}

			if (theResult.getAllValues() != null) {
				for (int k = 0; k < theResult.getAllValues().size(); k++) {
					System.out.println("Result Values  : "
							+ theResult.getAllValues().elementAt(k));
				}
			}
		}
	} // End handleResponse(EPPResponse)


} // End class NSPollTst
