/***********************************************************
Copyright (C) 2018 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.codec.validate.v02;

import com.verisign.epp.codec.gen.EPPCodecException;
import com.verisign.epp.codec.gen.EPPCodecTst;
import com.verisign.epp.codec.gen.EPPEncodeDecodeStats;
import com.verisign.epp.codec.gen.EPPFactory;
import com.verisign.epp.codec.gen.EPPResult;
import com.verisign.epp.codec.gen.EPPTransId;
import com.verisign.epp.util.TestThread;

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

/**
 * Is a unit test of the com.verisign.epp.codec.validate package. The unit test
 * will execute, gather statistics, and output the results of a test of each
 * com.verisign.epp.codec.namestoreext package concrete extension
 * {@code EPPCodecComponent}'s.
 */
public class EPPValidateTst extends TestCase {
	/**
	 * Number of unit test iterations to run. This is set in
	 * {@code EPPCodecTst.main}
	 */
	static private long numIterations = 1;

	/**
	 * Creates a new EPPValidateTst object.
	 *
	 * @param name
	 *           Name of test
	 */
	public EPPValidateTst(String name) {
		super(name);
	}

	/**
	 * Unit test of a Validate check command.
	 */
	public void testCheckCommand() {
		EPPCodecTst.printStart("testCheckCommand");

		EPPEncodeDecodeStats theStats;

		EPPValidateCheckCmd theCommand = new EPPValidateCheckCmd("ABC-12345");

		// Contact #1 - sh8013 for registrant
		EPPValidateContact theContact = new EPPValidateContact("sh8013", "registrant", "COM");

		EPPValidateAddress theAddress = new EPPValidateAddress();
		theAddress.setStreets("123 Example Dr.", "Suite 100");
		theAddress.setCity("Dulles");
		theAddress.setStateProvince("VA");
		theAddress.setPostalCode("20166-6503");
		theAddress.setCountry("US");
		EPPValidatePostalDefinition thePostalDef = new EPPValidatePostalDefinition(EPPValidatePostalDefinition.Type.INT,
		      "John Doe", theAddress);
		thePostalDef.setOrg("Example Inc.");
		theContact.addPostalInfo(thePostalDef);

		theContact.setVoice("+1.7035555555");
		theContact.setFax("+1.7035555556");
		theContact.setEmail("jdoe@example.com");
		theContact.setAuthInfo(new EPPValidateAuthInfo("2fooBAR"));

		theContact.addKeyValue(new EPPValidateKeyValue("VAT", "1234567890"));

		theCommand.addContact(theContact);

		// Contact #2 - existing sh8012 for tech contact
		theCommand.addContact(new EPPValidateContact("sh8012", "tech", "COM"));

		// Contact #3 - sh8014 for admin contact
		theContact = new EPPValidateContact("sh8014", "admin", "COM");

		theAddress = new EPPValidateAddress();
		theAddress.setStreets("123 Example Dr.", "Suite 100");
		theAddress.setCity("Dulles");
		theAddress.setStateProvince("VA");
		theAddress.setPostalCode("20166-6503");
		theAddress.setCountry("US");
		thePostalDef = new EPPValidatePostalDefinition(EPPValidatePostalDefinition.Type.INT, "John Doe", theAddress);
		thePostalDef.setOrg("Example Inc.");
		theContact.addPostalInfo(thePostalDef);

		theContact.setVoice("+1.7035555555");
		theContact.setFax("+1.7035555556");
		theContact.setEmail("jdoe@example.com");
		theContact.setAuthInfo(new EPPValidateAuthInfo("2fooBAR"));

		theCommand.addContact(theContact);

		// Contact #4 - sh8014 for billing contact
		try {
			theContact = (EPPValidateContact) theContact.clone();
			theContact.setContactType("billing");
			theCommand.addContact(theContact);
		}
		catch (CloneNotSupportedException e) {
			Assert.fail("CloneNotSupportedException cloning sh8014 for billing contact: " + e);
		}

		theStats = EPPCodecTst.testEncodeDecode(theCommand);
		System.out.println(theStats);

		EPPCodecTst.printEnd("testCheckCommand");
	}

	/**
	 * Unit test of a Validate check response.
	 */
	public void testCheckResponse() {
		EPPCodecTst.printStart("testCheckResponse");

		EPPTransId theTransId = new EPPTransId("ABC-12345", "54321-XYZ");
		EPPEncodeDecodeStats theStats;

		EPPValidateCheckResp theResponse = new EPPValidateCheckResp(theTransId);

		// sh8013 validate check data
		theResponse.addResult(new EPPValidateCheckResult("sh8013", EPPResult.SUCCESS));

		// sh8014 validate check data
		EPPValidateCheckResult theResult = new EPPValidateCheckResult("sh8014", EPPResult.PARAM_VALUE_POLICY_ERROR);
		theResult.addKeyValue(new EPPValidateKeyValue("contact:city", "City not valid for state."));
		theResult
		      .addKeyValue(new EPPValidateKeyValue("contact:cc", "Invalid country code for admin, must be mx.", "Admin"));
		theResult.addKeyValue(new EPPValidateKeyValue("VAT", "VAT required for Billing contact.", "Billing"));
		theResponse.addResult(theResult);

		theStats = EPPCodecTst.testEncodeDecode(theResponse);
		System.out.println(theStats);

		EPPCodecTst.printEnd("testCheckResponse");
	}

	/**
	 * JUNIT {@code setUp} method.
	 */
	@Override
	protected void setUp() {
	}

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

	/**
	 * JUNIT {@code suite} static method, which returns the tests associated with
	 * {@code EPPValidateTst}.
	 *
	 * @return Configured Test Suite
	 */
	public static Test suite() {
		EPPCodecTst.initEnvironment();

		TestSuite suite = new TestSuite(EPPValidateTst.class);

		// iterations Property
		String numIterProp = System.getProperty("iterations");

		if (numIterProp != null) {
			numIterations = Integer.parseInt(numIterProp);
		}

		// Add the EPPNSProductExtFactory to the EPPCodec.
		try {
			EPPFactory.getInstance().addMapFactory("com.verisign.epp.codec.validate.v02.EPPValidateMapFactory");
		}
		catch (EPPCodecException e) {
			Assert.fail("EPPCodecException adding factories to EPPCodec: " + e);
		}

		return suite;
	}

	/**
	 * 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}) or off ( {@code false}
	 * ). If validate is not specified, validation will be off.</li>
	 * </ul>
	 *
	 * @param args
	 *           Command line arguments
	 */
	public static void main(String[] args) {
		// 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("EPPValidateTst Thread " + i, EPPValidateTst.suite());
				thread.start();
			}
		}
		else { // Single threaded mode.
			junit.textui.TestRunner.run(EPPValidateTst.suite());
		}
	}

	/**
	 * Sets the number of iterations to run per test.
	 *
	 * @param aNumIterations
	 *           number of iterations to run per test
	 */
	public static void setNumIterations(long aNumIterations) {
		numIterations = aNumIterations;
	}

}
