/*******************************************************************************
 * Copyright © 2004 VHA. All rights reserved
 ******************************************************************************/

// package
package gov.va.med.fw.util;

// Library classes
import org.apache.commons.logging.Log;
import org.springframework.test.AbstractTransactionalDataSourceSpringContextTests;
import org.springframework.transaction.PlatformTransactionManager;

// Framework classes
import gov.va.med.fw.service.config.SingletonApplicationContext;
import org.springframework.transaction.support.TransactionSynchronizationManager;

/**
 * A base class for all JUnit test cases that utilizes a Request Broker to
 * obtain spring managed components. This base class also provides utility
 * methods to obtain a reference to a logging component and to execute methods
 * in a transaction scope.
 * 
 * @author Vu Le, Yi He
 */
public abstract class AbstractTestCase extends AbstractTransactionalDataSourceSpringContextTests { 
	
	// path in test_resource.jar
	protected static final String DEFAULT_TEST_CONTEXT = "fw/test_components.xml"; 

	/**
	 * An instance of configLocations
	 */
	protected String[] configLocations = new String[] { DEFAULT_TEST_CONTEXT };

	// #####################################
	// ### below are used for test drivers in Framework
	// #####################################
	// allows subclasses to not have to name testcases
	public AbstractTestCase() {
	}

	// preserved for old code
	public AbstractTestCase(String name) {
		// since Spring does not have a String constructor, we must call this so
		// JUnit does not fail
		setName(name);
	}

	// #####################################
	// ### below are used for test drivers in clients of Framework (1 level deep)
	// #####################################
	// allows subclasses to not have to name testcases
	public AbstractTestCase(String[] configFiles) {
		initConfigLocations(configFiles, null);
	}

	// preserved for old code
	public AbstractTestCase(String name, String[] configFiles) {
		this(name);
		initConfigLocations(configFiles, null);
	}

	// #####################################
	// ### below are used for test drivers in clients of Framework (2 levels
	// deep)
	// #####################################
	// allows subclasses to not have to name testcases
	public AbstractTestCase(String[] configFiles, String[] parentConfigFiles) {
		initConfigLocations(configFiles, parentConfigFiles);
	}

	// preserved for old code
	public AbstractTestCase(String name, String[] configFiles,
			String[] parentConfigFiles) {
		this(name);
		initConfigLocations(configFiles, parentConfigFiles);
	}

	// overridden from Spring
	public void onSetUpInTransaction() throws Exception {
      
      SingletonApplicationContext.getInstance().setSingletonContext( this.applicationContext );
		// makes this be the default for any test cases that are referencing it
		// that way
      
      // Set a transaction name
      String name = TransactionSynchronizationManager.getCurrentTransactionName();
      if( TransactionSynchronizationManager.isActualTransactionActive() && name == null ) {
         TransactionSynchronizationManager.setCurrentTransactionName( this.getName() );
      }
		customSetUp();
	}

	// for convenience
	protected Log getLogger() {
		return logger;
	}

	protected void customSetUp() throws Exception {
	}

	// overridden from Spring
	public void onTearDownInTransaction() {
		try {
			customTearDown();
		}
		catch (Exception e) {
			fail("Unable to tear down data", e);
		}
	}

	/** Subclasses can override (helpful in testing services that start their own TX) */
	protected boolean shouldTestCaseStartTransaction() {
		return true;
	}
	
	public void setTransactionManager(PlatformTransactionManager ptm) {
		if(shouldTestCaseStartTransaction())
			super.setTransactionManager(ptm);
	// else do nothing (this disables TX in AbstractTransactionalSpringContextTests)
	}
	
	protected void customTearDown() throws Exception {
	}

	/**
	 * Initializes a test case with the specific name, using a parent's
	 * configuration files
	 * 
	 * @param testName
	 * @param configFiles
	 */
	private void initConfigLocations(String[] configFiles,
			String parentConfigFiles[]) {

		/*
		 * RATIONALE: merging the two into one ApplicationContext was performed so
		 * that Common can depend on Messaging's overriding of dataSource and
		 * transactionManager. Splitting them into two ApplicationContext's (as is
		 * done for the runtime application) would have consequences that the
		 * Common test_components.xml would be needed in the test.classpath of
		 * running Messaging's tests.
		 */
		
		/**
         * set the caip properties here
         */
        System.setProperty("DSKey.store",       "config/shared/caip/caipService.jks");
        System.setProperty("myCaipConfig.xml",  "config/shared/caip/local/caipConfig.xml");
        System.setProperty("weblogic.Name",  "JUnit");

        
		int parentConfigFilesLength = 0;
		int configFilesLength = 0;
		
		if (parentConfigFiles != null)
			parentConfigFilesLength = parentConfigFiles.length;
		
		if (configFiles != null)
			configFilesLength = configFiles.length;
		
		String[] completeSetOfConfigFiles = new String[parentConfigFilesLength + configFilesLength];

		int index = 0, i = 0;
		while (i < parentConfigFilesLength) {
			completeSetOfConfigFiles[index++] = parentConfigFiles[i++];
		}
		i = 0;
		while (i < configFilesLength) {
			completeSetOfConfigFiles[index++] = configFiles[i++];
		}

		configLocations = completeSetOfConfigFiles;
	}

	/**
	 * Useful for html reporting to see the entire stack trace
	 * 
	 * @param message
	 * @param e
	 */
	protected void fail(String message, Exception e) {
		e.fillInStackTrace(); // just to get the most information possible
		Throwable cause = e;
		StringBuffer trace = new StringBuffer();
		while (cause != null) {
			trace.append("******").append(cause.getMessage()).append(" ").append(
					cause);
			cause = cause.getCause();
		}
		fail(message + trace.toString());
	}

	protected String[] getConfigLocations() {
		return configLocations;
	}
}