/***********************************************************
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.interfaces.launchpolicy.v01;

import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.verisign.epp.codec.gen.EPPResponse;
import com.verisign.epp.codec.launchpolicy.v01.EPPLaunchPolicyCreate;
import com.verisign.epp.codec.launchpolicy.v01.EPPLaunchPolicyInfData;
import com.verisign.epp.codec.launchpolicy.v01.EPPLaunchPolicyInfoPhase;
import com.verisign.epp.codec.launchpolicy.v01.EPPLaunchPolicyPhase;
import com.verisign.epp.codec.launchpolicy.v01.EPPLaunchPolicyPhaseStatus;
import com.verisign.epp.codec.launchpolicy.v01.EPPLaunchPolicyPollPolicy;
import com.verisign.epp.codec.launchpolicy.v01.EPPLaunchPolicyUpdate;
import com.verisign.epp.codec.launchpolicy.v01.EPPLaunchPolicyZone;
import com.verisign.epp.codec.registry.v02.EPPRegistryBatchJob;
import com.verisign.epp.codec.registry.v02.EPPRegistryCheckResp;
import com.verisign.epp.codec.registry.v02.EPPRegistryCheckResult;
import com.verisign.epp.codec.registry.v02.EPPRegistryContact;
import com.verisign.epp.codec.registry.v02.EPPRegistryContactAddress;
import com.verisign.epp.codec.registry.v02.EPPRegistryContactCity;
import com.verisign.epp.codec.registry.v02.EPPRegistryContactName;
import com.verisign.epp.codec.registry.v02.EPPRegistryContactOrg;
import com.verisign.epp.codec.registry.v02.EPPRegistryContactPostalCode;
import com.verisign.epp.codec.registry.v02.EPPRegistryContactStateProvince;
import com.verisign.epp.codec.registry.v02.EPPRegistryContactStreet;
import com.verisign.epp.codec.registry.v02.EPPRegistryCreateResp;
import com.verisign.epp.codec.registry.v02.EPPRegistryDNSSEC;
import com.verisign.epp.codec.registry.v02.EPPRegistryDS;
import com.verisign.epp.codec.registry.v02.EPPRegistryDomain;
import com.verisign.epp.codec.registry.v02.EPPRegistryDomain.HostModelSupported;
import com.verisign.epp.codec.registry.v02.EPPRegistryDomainContact;
import com.verisign.epp.codec.registry.v02.EPPRegistryDomainHostLimit;
import com.verisign.epp.codec.registry.v02.EPPRegistryDomainNSLimit;
import com.verisign.epp.codec.registry.v02.EPPRegistryDomainName;
import com.verisign.epp.codec.registry.v02.EPPRegistryDomainPeriod;
import com.verisign.epp.codec.registry.v02.EPPRegistryExceedMaxExDate;
import com.verisign.epp.codec.registry.v02.EPPRegistryExternalHost;
import com.verisign.epp.codec.registry.v02.EPPRegistryGracePeriod;
import com.verisign.epp.codec.registry.v02.EPPRegistryHost;
import com.verisign.epp.codec.registry.v02.EPPRegistryIDN;
import com.verisign.epp.codec.registry.v02.EPPRegistryInfoCmd;
import com.verisign.epp.codec.registry.v02.EPPRegistryInfoResp;
import com.verisign.epp.codec.registry.v02.EPPRegistryInternalHost;
import com.verisign.epp.codec.registry.v02.EPPRegistryKey;
import com.verisign.epp.codec.registry.v02.EPPRegistryLanguage;
import com.verisign.epp.codec.registry.v02.EPPRegistryMaxSig;
import com.verisign.epp.codec.registry.v02.EPPRegistryMinMaxLength;
import com.verisign.epp.codec.registry.v02.EPPRegistryPendingDeletePeriodType;
import com.verisign.epp.codec.registry.v02.EPPRegistryPendingRestorePeriodType;
import com.verisign.epp.codec.registry.v02.EPPRegistryPeriodType;
import com.verisign.epp.codec.registry.v02.EPPRegistryPostal;
import com.verisign.epp.codec.registry.v02.EPPRegistryRGP;
import com.verisign.epp.codec.registry.v02.EPPRegistryRedemptionPeriodType;
import com.verisign.epp.codec.registry.v02.EPPRegistryRegex;
import com.verisign.epp.codec.registry.v02.EPPRegistryReservedNames;
import com.verisign.epp.codec.registry.v02.EPPRegistryServices;
import com.verisign.epp.codec.registry.v02.EPPRegistryServices.EPPRegistryObjURI;
import com.verisign.epp.codec.registry.v02.EPPRegistryServicesExt;
import com.verisign.epp.codec.registry.v02.EPPRegistryServicesExt.EPPRegistryExtURI;
import com.verisign.epp.codec.registry.v02.EPPRegistrySupportedStatus;
import com.verisign.epp.codec.registry.v02.EPPRegistrySupportedStatus.Status;
import com.verisign.epp.codec.registry.v02.EPPRegistryTransferHoldPeriodType;
import com.verisign.epp.codec.registry.v02.EPPRegistryZone;
import com.verisign.epp.codec.registry.v02.EPPRegistryZoneName;
import com.verisign.epp.codec.registry.v02.EPPRegistryZoneSummary;
import com.verisign.epp.interfaces.EPPApplicationSingle;
import com.verisign.epp.interfaces.EPPCommandException;
import com.verisign.epp.interfaces.EPPSession;
import com.verisign.epp.interfaces.registry.v02.EPPRegistry;
import com.verisign.epp.interfaces.registry.v02.EPPRegistryTst;
import com.verisign.epp.util.Environment;
import com.verisign.epp.util.TestThread;

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

public class EPPLaunchPolicyRegistryTst extends TestCase {
	/**
	 * Handle to the Singleton EPP Application instance (
	 * {@code EPPApplicationSingle})
	 */
	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 Logger cat = LoggerFactory.getLogger(EPPLaunchPolicyRegistryTst.class);

	/**
	 * EPP Registry associated with test
	 */
	private EPPRegistry registry = null;

	/**
	 * EPP Session associated with test
	 */
	private EPPSession session = null;

	/**
	 * Current test iteration
	 */
	private int iteration = 0;

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

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

	/**
	 * Test the Registry Mapping by doing the following:
	 * <ol>
	 * <li>Create a set of zones.</li>
	 * <li>Update a zone.</li>
	 * <li>Check the availability (existence) of the zones.</li>
	 * <li>Get all summary information for the zones.</li>
	 * <li>Get detailed zone information for some zones.</li>
	 * <li>Get registry system information.</li>
	 * <li>Delete a set of zones.</li>
	 * <li>
	 *
	 * </ol>
	 */
	public void testRegistry() {
		int numIterations = 1;

		String iterationsStr = System.getProperty("iterations");

		if (iterationsStr != null) {
			try {
				numIterations = Integer.parseInt(iterationsStr);
				numIterations = (numIterations < 1) ? 1 : numIterations;
			}
			catch (Exception e) {
				numIterations = 1;
			}
		}

		printStart("Test Suite");

		registryCreate("launchpolicytst", true);

		registryUpdate("launchpolicytst", true);

		registryInfo(EPPRegistryInfoCmd.Mode.name, "launchpolicytst", null);

		registryDelete("launchpolicytst", true);

		printEnd("Test Suite");
	}

	/**
	 * Unit test of {@code EPPRegistry.sendCheck}.
	 * 
	 * @param aZoneNames
	 *           Names of the zones to check
	 */
	public void registryCheck(Map aZoneNames) {
		printStart("registryCheck");

		EPPRegistryCheckResp response;
		try {
			System.out.println("\n----------------------------------------------------------------");
			System.out.print("registryCheck:");
			this.registry.setTransId("ABC-12345-XYZ");

			for (Iterator it = aZoneNames.entrySet().iterator(); it.hasNext();) {
				String name = (String) ((Entry) it.next()).getKey();
				System.out.print(" " + name + " ");
				this.registry.addZone(name);
			}
			System.out.println("");

			response = this.registry.sendCheck();

			System.out.println("registryCheck: Response = [" + response + "]\n\n");

			for (Iterator it = aZoneNames.entrySet().iterator(); it.hasNext();) {
				Entry entry = (Entry) it.next();
				String name = (String) entry.getKey();
				Boolean available = (Boolean) entry.getValue();
				inner: for (Object element : response.getCheckResults()) {
					EPPRegistryCheckResult result = (EPPRegistryCheckResult) element;
					if (result.getName().equals(name)) {
						if (result.isAvailable().booleanValue() == available.booleanValue()) {
							break inner;
						}
						else {
							fail("Expected availability for tld \"" + name + "\": " + available.booleanValue() + ", but got: "
							      + result.isAvailable());
						}
					}
				}
			}

			assertTrue(response != null && response.isSuccess());
		}
		catch (EPPCommandException e) {
			handleException(e);
		}

		printEnd("registryCheck");
	}

	/**
	 * Unit test of {@code EPPRegistry.sendCreate}.
	 * 
	 * @param aZoneName
	 *           Zone to create
	 * @param aShouldSucceed
	 *           {@code true} if the zone create should succeed; {@code false}
	 *           otherwise.
	 */
	public void registryCreate(String aZoneName, boolean aShouldSucceed) {
		printStart("registryCreate");

		EPPRegistryCreateResp response = null;
		try {
			System.out.println("\n----------------------------------------------------------------");
			System.out.println("registryCreate: " + aZoneName);
			this.registry.setTransId("ABC-12345-XYZ");
			this.registry.setZone(this.buildZoneInfo(new EPPRegistryZoneName(aZoneName)));

			// Add the Launch Phase Policy Extension
			EPPLaunchPolicyCreate launchPolicyExt = new EPPLaunchPolicyCreate(buildLaunchPolicyZone());
			this.registry.addExtension(launchPolicyExt);

			response = this.registry.sendCreate();
			System.out.println("registryCreate: Response = [" + response + "]\n\n");

			if (aShouldSucceed) {
				assertTrue(response != null && response.isSuccess());
			}
			else {
				fail("Expecting error in response");
			}
		}
		catch (EPPCommandException e) {
			if (aShouldSucceed) {
				handleException(e);
			}
		}

		printEnd("registryCreate");
	}

	/**
	 * Unit test of {@code EPPRegistry.sendDelete}.
	 * 
	 * @param aZoneName
	 *           Zone to delete
	 * @param aShouldSucceed
	 *           {@code true} if the zone delete should succeed; {@code false}
	 *           otherwise.
	 */
	public void registryDelete(String aZoneName, boolean aShouldSucceed) {
		printStart("registryDelete");

		EPPResponse response = null;
		try {
			System.out.println("\n----------------------------------------------------------------");
			System.out.println("registryDelete: " + aZoneName);
			this.registry.setTransId("ABC-12345-XYZ");
			this.registry.addZone(aZoneName);

			response = this.registry.sendDelete();
			System.out.println("registryDelete: Response = [" + response + "]\n\n");

			if (aShouldSucceed) {
				assertTrue(response != null && response.isSuccess());
			}
			else {
				fail("Expecting error in response");
			}
		}
		catch (EPPCommandException e) {
			if (aShouldSucceed) {
				handleException(e);
			}
		}

		printEnd("registryDelete");
	}

	/**
	 * Unit test of {@code EPPRegistry.sendUpdate}.
	 * 
	 * @param aZoneName
	 *           Zone to update
	 * @param aShouldSucceed
	 *           {@code true} if the zone update should succeed; {@code false}
	 *           otherwise.
	 */
	public void registryUpdate(String aZoneName, boolean aShouldSucceed) {
		printStart("registryUpdate");

		EPPResponse response = null;
		try {
			System.out.println("\n----------------------------------------------------------------");
			System.out.println("registryUpdate: " + aZoneName);
			this.registry.setTransId("ABC-12345-XYZ");
			this.registry.setZone(this.buildZoneInfo(new EPPRegistryZoneName(aZoneName)));

			// Add the Launch Phase Policy Extension
			EPPLaunchPolicyUpdate launchPolicyExt = new EPPLaunchPolicyUpdate(buildLaunchPolicyZone());
			this.registry.addExtension(launchPolicyExt);

			response = this.registry.sendUpdate();
			System.out.println("registryUpdate: Response = [" + response + "]\n\n");

			if (aShouldSucceed) {
				assertTrue(response != null && response.isSuccess());
			}
			else {
				fail("Expecting error in response");
			}
		}
		catch (EPPCommandException e) {
			if (aShouldSucceed) {
				handleException(e);
			}
		}

		printEnd("registryUpdate");
	}

	/**
	 * Test for the registry info command that supports the three forms of
	 * getting detailed information for an individual zone by setting the
	 * {@code aZoneName} parameter to a non-{@code null} value, getting a summary
	 * of all zones by setting the {@code aScope} parameter to a non-{@code null}
	 * value, and getting the system information by setting the {@code aSystem}
	 * parameter to true. There can be only one form used as a time.
	 *
	 * @param aMode
	 *           One of the support info modes (
	 *           {@code EPPRegistryInfoCmd.Mode.name},
	 *           {@code EPPRegistryInfoCmd.Mode.all}, or
	 *           {@code EPPRegistryInfoCmd.Mode.system})
	 * @param aZoneName
	 *           Used with the "name" info mode that represents the zone name to
	 *           query. Set to {@code null} with the
	 *           {@code EPPRegistryInfoCmd.Mode.all} or
	 *           {@code EPPRegistryInfoCmd.Mode.system} modes.
	 * @param aScope
	 *           Used with the "all" info mode that represents the scope of the
	 *           zones to query. Set to {@code null} with the
	 *           {@code EPPRegistryInfoCmd.Mode.name} or
	 *           {@code EPPRegistryInfoCmd.Mode.system} modes.
	 */
	public void registryInfo(EPPRegistryInfoCmd.Mode aMode, String aZoneName, EPPRegistryInfoCmd.Scope aScope) {
		printStart("registryInfo");

		EPPRegistryInfoResp response = null;

		try {

			switch (aMode) {
				case name:
					if (aZoneName == null) {
						Assert.fail("aZoneName must not be null with the name info mode");
					}
					this.registry.setTransId("ABC-12345-XYZ");
					this.registry.addZone(aZoneName);
					response = this.registry.sendInfo();

					assertTrue(response != null && response.isSuccess());

					assertTrue(response.getZoneList() == null && response.getZoneInfo() != null);
					System.out.println("Zone accessible = " + response.getZoneInfo().isAccessible());
					EPPRegistryZone info = response.getZoneInfo().getZone();
					System.out.println("Zone name: " + info.getName());
					if (info.getServices() != null) {
						System.out.println("Services:");
						for (Object element : info.getServices().getObjURIs()) {
							EPPRegistryObjURI objUri = (EPPRegistryObjURI) element;
							System.out.println("\tobjURI: " + objUri.getUri() + ", required: " + objUri.getRequired());
						}
					}
					if (info.getServices() != null && info.getServices().getExtension() != null) {
						System.out.println("Services extension:");
						for (Iterator it = info.getServices().getExtension().getExtURIs().iterator(); it.hasNext();) {
							EPPRegistryExtURI extUri = (EPPRegistryExtURI) it.next();
							System.out.println("\textURI: " + extUri.getUri() + ", required: " + extUri.getRequired());
						}
					}
					System.out.println("crId: " + info.getCreatedBy());
					System.out.println("crDate: " + info.getCreatedDate());
					System.out.println("upId: " + info.getLastUpdatedBy());
					System.out.println("upDate: " + info.getLastUpdatedDate());

					if (info.hasBatchJobs()) {
						List<EPPRegistryBatchJob> jobs = info.getBatchJobs();
						for (EPPRegistryBatchJob currJob : jobs) {
							System.out.println("batchJob: " + currJob);
						}
					}
					info.getBatchJobs();

					EPPRegistryDomain domain = info.getDomain();
					assertTrue(domain != null);
					System.out.println("Domain: " + domain);
					EPPRegistryHost host = info.getHost();
					assertTrue(host != null);
					EPPRegistryContact contact = info.getContact();
					assertTrue(contact != null);
					EPPLaunchPolicyInfData launchPolicyExt = (EPPLaunchPolicyInfData) response
					      .getExtension(EPPLaunchPolicyInfData.class);
					assertTrue(launchPolicyExt != null);
					if (launchPolicyExt != null) {
						System.out.println("Launch Policy Zone: " + launchPolicyExt.getZone());
					}

					break;
				case all:
					if (aScope == null) {
						Assert.fail("aScope must not be null with the all info mode");
					}

					this.registry.setTransId("ABC-12345-XYZ");
					this.registry.setAllScope(EPPRegistryInfoCmd.Scope.both);
					response = this.registry.sendInfo();

					assertTrue(response != null && response.isSuccess());

					assertTrue(response.getZoneList() != null && response.getZoneList().getZoneList() != null
					      && response.getZoneInfo() == null && response.getZoneList().getZoneList().size() > 0);
					System.out.println("All TLDs: ");
					for (Iterator it = response.getZoneList().getZoneList().iterator(); it.hasNext();) {
						EPPRegistryZoneSummary tld = (EPPRegistryZoneSummary) it.next();
						assertTrue(tld.getName().getName() != null && tld.getName().getName().length() > 0);
						assertTrue(tld.getCreateDate() != null);
						System.out.print(tld.getName() + "\tcreated on " + tld.getCreateDate());
						if (tld.getUpdateDate() != null) {
							System.out.println("\tupdated on " + tld.getUpdateDate());
						}
						else {
							System.out.println();
						}
					}

					break;
				case system:
					this.registry.setTransId("ABC-12345-XYZ");
					this.registry.setInfoMode(aMode);
					response = this.registry.sendInfo();

					assertTrue(response != null && response.isSuccess());

					System.out.println("System Info Response = " + response);

			}

			printEnd("registryInfo");
		}
		catch (EPPCommandException e) {
			handleException(e);
		}

	}

	/**
	 * Make a pseudo random zone name.
	 *
	 * @return pseudo random zone name
	 */
	public String makeZoneName() {
		int len = this.rd.nextInt(15);
		StringBuffer sb = new StringBuffer();
		for (int i = 0; i < len; i++) {
			sb.append('a' + this.rd.nextInt(26));
		}
		return sb.toString();
	}

	/**
	 * Handle an {@code EPPCommandException}, which can be either a server
	 * generated error or a general exception. If the exception was caused by a
	 * server error, "Server Error :&lt;Response XML&gt;" will be specified. If
	 * the exception was caused by a general algorithm error, "General Error
	 * :&lt;Exception Description&gt;" will be specified.
	 *
	 * @param aException
	 *           Exception thrown during test
	 */
	public void handleException(Exception aException) {
		EPPResponse theResponse = null;
		if (aException instanceof EPPCommandException) {
			theResponse = ((EPPCommandException) aException).getResponse();
		}

		aException.printStackTrace();

		// Is a server specified error?
		if ((theResponse != null) && (!theResponse.isSuccess())) {
			Assert.fail("Server Error : " + theResponse);
		}

		else {
			Assert.fail("General Error : " + aException);
		}
	}

	public static Test suite() {
		TestSuite suite = new TestSuite(EPPLaunchPolicyRegistryTst.class);

		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);
		}

		return suite;
	}

	@Override
	protected void setUp() {
		try {
			String theSessionClassName = System.getProperty("EPP.SessionClass");

			if (theSessionClassName != null) {
				try {
					Class theSessionClass = Class.forName(theSessionClassName);

					if (!EPPSession.class.isAssignableFrom((theSessionClass))) {
						Assert.fail(theSessionClassName + " is not a subclass of EPPSession");
					}

					this.session = (EPPSession) theSessionClass.getDeclaredConstructor().newInstance();
				}
				catch (Exception ex) {
					Assert.fail("Exception instantiating EPP.SessionClass value " + theSessionClassName + ": " + ex);
				}
			}
			else {
				this.session = new EPPSession();
			}

			this.session.setClientID(Environment.getProperty("EPP.Test.clientId", "ClientX"));
			this.session.setPassword(Environment.getProperty("EPP.Test.password", "foo-BAR2"));
		}

		catch (Exception e) {
			e.printStackTrace();

			Assert.fail("Error initializing the session: " + e);
		}

		initSession();

		// System.out.println("out init");
		this.registry = new EPPRegistry(this.session);
	}

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

	/**
	 * Unit test of {@code EPPSession.initSession}. The session attribute is
	 * initialized with the attributes defined in the EPP sample files.
	 */
	private void initSession() {
		printStart("initSession");

		// Set attributes for initSession
		this.session.setTransId("ABC-12345-XYZ");

		this.session.setVersion("1.0");

		this.session.setLang("en");

		// Initialize the session
		try {
			this.session.initSession();
		}

		catch (EPPCommandException e) {
			EPPResponse response = this.session.getResponse();

			// Is a server specified error?
			if ((response != null) && (!response.isSuccess())) {
				Assert.fail("Server Error : " + response);
			}
			else {
				e.printStackTrace();

				Assert.fail("initSession Error : " + e);
			}
		}

		printEnd("initSession");
	}

	/**
	 * Unit test of {@code EPPSession.endSession}. The session with the EPP
	 * Server will be terminated.
	 */
	private void endSession() {
		printStart("endSession");

		this.session.setTransId("ABC-12345-XYZ");

		// End the session
		try {
			this.session.endSession();
		}

		catch (EPPCommandException e) {
			EPPResponse response = this.session.getResponse();

			// Is a server specified error?
			if ((response != null) && (!response.isSuccess())) {
				Assert.fail("Server Error : " + response);
			}

			else // Other error
			{
				e.printStackTrace();

				Assert.fail("initSession Error : " + e);
			}
		}

		printEnd("endSession");
	}

	/**
	 * Print the start of a test with the {@code Thread} name if the current
	 * thread is a {@code TestThread}.
	 *
	 * @param aTest
	 *           name for the test
	 */
	private void printStart(String aTest) {
		if (Thread.currentThread() instanceof TestThread) {
			System.out.print(Thread.currentThread().getName() + ", iteration " + this.iteration + ": ");

			cat.info(Thread.currentThread().getName() + ", iteration " + this.iteration + ": " + aTest + " Start");
		}

		System.out.println("Start of " + aTest);

		System.out.println("****************************************************************\n");
	}

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

		if (Thread.currentThread() instanceof TestThread) {
			System.out.print(Thread.currentThread().getName() + ", iteration " + this.iteration + ": ");

			cat.info(Thread.currentThread().getName() + ", iteration " + this.iteration + ": " + aTest + " End");
		}

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

		System.out.println("\n");
	}

	/**
	 * Creates a populated {@link EPPRegistryZone} instance given a zone name.
	 *
	 * @param aZone
	 *           Zone name to create a populated {@link EPPRegistryZone} instance
	 *           for.
	 *
	 * @return Populated {@link EPPRegistryZone} instance
	 */
	private EPPRegistryZone buildZoneInfo(EPPRegistryZoneName aZone) {

		EPPRegistryZone theZoneInfo = new EPPRegistryZone(aZone);

		theZoneInfo.setDomain(EPPRegistryTst.buildDomain(false, false));
		theZoneInfo.setHost(EPPRegistryTst.buildHost(true));
		theZoneInfo.setContact(EPPRegistryTst.buildContact());

		EPPRegistryServices services = new EPPRegistryServices();
		services.addObjURI(new EPPRegistryObjURI("urn:ietf:params:xml:ns:registry-1.2", Boolean.TRUE));
		services.addObjURI(new EPPRegistryObjURI("urn:ietf:params:xml:ns:registry-1.1", Boolean.FALSE));
		EPPRegistryServicesExt svcExt = new EPPRegistryServicesExt();
		services.setExtension(svcExt);
		svcExt.addExtURI(new EPPRegistryExtURI("urn:ietf:params:xml:ns:registry-1.2", Boolean.TRUE));
		svcExt.addExtURI(new EPPRegistryExtURI("urn:ietf:params:xml:ns:registry-1.1", Boolean.FALSE));
		theZoneInfo.setServices(services);

		theZoneInfo.setCreatedBy("crId");
		theZoneInfo.setCreatedDate(new Date());

		return theZoneInfo;
	}



	/**
	 * Build a populated {@link EPPLaunchPolicyZone} instance that can be
	 * included in one of the Launch Policy Extensions. The populated attributes
	 * are based on the sample included in draft-gould-regext-launch-policy. The
	 * following phases are added to the populated {@link EPPLaunchPolicyZone}
	 * instance:<br>
	 * <ol>
	 * <li>Sunrise</li>
	 * <li>Claims for Limited Registration Period #1 (LRP1)</li>
	 * <li>Claims for Landrush</li>
	 * <li>Claims (Open)</li>
	 * <li>Custom for Limited Registration Period #2 (LRP2)</li>
	 * <li>Open</li>
	 * </ol>
	 * 
	 * @return Populated {@link EPPLaunchPolicyZone} based on the sample included
	 *         in draft-gould-regext-launch-policy.
	 */
	public static EPPLaunchPolicyZone buildLaunchPolicyZone() {
		EPPLaunchPolicyZone zone = new EPPLaunchPolicyZone();

		// Sunrise
		EPPLaunchPolicyPhase sunrise = new EPPLaunchPolicyPhase(EPPLaunchPolicyPhase.Phase.sunrise,
		      new GregorianCalendar(2017, 11, 01, 0, 0).getTime());
		sunrise.setMode(EPPLaunchPolicyPhase.Mode.pendingApplication);
		sunrise.setEndDate(new GregorianCalendar(2017, 12, 01, 0, 0).getTime());
		sunrise.setValidatePhase(true);
		sunrise.addValidatorId("tmch");
		sunrise.addStatus(new EPPLaunchPolicyPhaseStatus(EPPLaunchPolicyPhaseStatus.Status.pendingAllocation));
		sunrise.addStatus(new EPPLaunchPolicyPhaseStatus(EPPLaunchPolicyPhaseStatus.Status.allocated));
		sunrise.addStatus(new EPPLaunchPolicyPhaseStatus(EPPLaunchPolicyPhaseStatus.Status.rejected));
		sunrise.addStatus(
		      new EPPLaunchPolicyPhaseStatus(EPPLaunchPolicyPhaseStatus.Status.custom, "test", null, "test status"));
		sunrise.addMarkValidation(EPPLaunchPolicyPhase.MarkValidation.signedMark);
		sunrise.setMaxMarks(1);
		sunrise.addSignedMarkSupported("urn:ietf:params:xml:ns:signedMark-1.0");
		sunrise.addEncodedSignedMarkSupported("urn:ietf:params:xml:ns:signedMark-1.0");
		sunrise.addInfoPhase(new EPPLaunchPolicyInfoPhase(EPPLaunchPolicyPhase.Phase.sunrise));
		sunrise.addCreateForm(EPPLaunchPolicyPhase.CreateForm.sunrise);
		sunrise.setCreateValidateType(true);

		zone.addPhase(sunrise);

		// Claims LRP1
		EPPLaunchPolicyPhase lrp1 = new EPPLaunchPolicyPhase(EPPLaunchPolicyPhase.Phase.claims,
		      new GregorianCalendar(2017, 12, 01, 0, 0).getTime());
		lrp1.setName("lrp1");
		lrp1.setMode(EPPLaunchPolicyPhase.Mode.pendingRegistration);
		lrp1.setEndDate(new GregorianCalendar(2017, 12, 8, 0, 0).getTime());
		lrp1.setValidatePhase(true);
		lrp1.addValidatorId("tmch");
		lrp1.addStatus(new EPPLaunchPolicyPhaseStatus(EPPLaunchPolicyPhaseStatus.Status.pendingValidation));
		lrp1.addStatus(new EPPLaunchPolicyPhaseStatus(EPPLaunchPolicyPhaseStatus.Status.allocated));
		lrp1.addStatus(new EPPLaunchPolicyPhaseStatus(EPPLaunchPolicyPhaseStatus.Status.rejected));
		lrp1.setPendingCreate(true);
		lrp1.addCheckForm(EPPLaunchPolicyPhase.CheckForm.claims);
		lrp1.addCheckForm(EPPLaunchPolicyPhase.CheckForm.availability);
		lrp1.addCheckForm(EPPLaunchPolicyPhase.CheckForm.trademark);
		lrp1.addMarkValidation(EPPLaunchPolicyPhase.MarkValidation.signedMark);
		lrp1.addInfoPhase(new EPPLaunchPolicyInfoPhase(EPPLaunchPolicyPhase.Phase.sunrise));
		lrp1.addInfoPhase(new EPPLaunchPolicyInfoPhase(EPPLaunchPolicyPhase.Phase.claims, "lrp1"));
		lrp1.addCreateForm(EPPLaunchPolicyPhase.CreateForm.claims);
		lrp1.setCreateValidateType(true);

		zone.addPhase(lrp1);

		// Claims Landrush
		EPPLaunchPolicyPhase landrush = new EPPLaunchPolicyPhase(EPPLaunchPolicyPhase.Phase.claims,
		      new GregorianCalendar(2017, 12, 8, 0, 0).getTime());
		landrush.setName("landrush");
		landrush.setMode(EPPLaunchPolicyPhase.Mode.pendingApplication);
		landrush.setEndDate(new GregorianCalendar(2017, 12, 15, 0, 0).getTime());
		landrush.setValidatePhase(true);
		landrush.addValidatorId("tmch");
		landrush.addStatus(new EPPLaunchPolicyPhaseStatus(EPPLaunchPolicyPhaseStatus.Status.pendingAllocation));
		landrush.addStatus(new EPPLaunchPolicyPhaseStatus(EPPLaunchPolicyPhaseStatus.Status.allocated));
		landrush.addStatus(new EPPLaunchPolicyPhaseStatus(EPPLaunchPolicyPhaseStatus.Status.rejected));
		landrush.setPendingCreate(true);
		landrush.setPollPolicy(new EPPLaunchPolicyPollPolicy(false, false, false));
		landrush.addCheckForm(EPPLaunchPolicyPhase.CheckForm.claims);
		landrush.addCheckForm(EPPLaunchPolicyPhase.CheckForm.availability);
		landrush.addCheckForm(EPPLaunchPolicyPhase.CheckForm.trademark);
		landrush.addMarkValidation(EPPLaunchPolicyPhase.MarkValidation.signedMark);
		landrush.addInfoPhase(new EPPLaunchPolicyInfoPhase(EPPLaunchPolicyPhase.Phase.sunrise));
		landrush.addInfoPhase(new EPPLaunchPolicyInfoPhase(EPPLaunchPolicyPhase.Phase.claims, "lrp1"));
		landrush.addInfoPhase(new EPPLaunchPolicyInfoPhase(EPPLaunchPolicyPhase.Phase.claims, "landrush"));
		landrush.addCreateForm(EPPLaunchPolicyPhase.CreateForm.claims);
		landrush.setCreateValidateType(true);

		zone.addPhase(landrush);

		// Claims Open
		EPPLaunchPolicyPhase claims = new EPPLaunchPolicyPhase(EPPLaunchPolicyPhase.Phase.claims,
		      new GregorianCalendar(2017, 12, 15, 0, 0).getTime());
		claims.setName("open");
		claims.setMode(EPPLaunchPolicyPhase.Mode.fcfs);
		claims.setEndDate(new GregorianCalendar(2018, 2, 15, 0, 0).getTime());
		claims.setValidatePhase(true);
		claims.addValidatorId("tmch");
		claims.addCheckForm(EPPLaunchPolicyPhase.CheckForm.claims);
		claims.addCheckForm(EPPLaunchPolicyPhase.CheckForm.availability);
		claims.addCheckForm(EPPLaunchPolicyPhase.CheckForm.trademark);
		claims.addMarkValidation(EPPLaunchPolicyPhase.MarkValidation.signedMark);
		claims.addInfoPhase(new EPPLaunchPolicyInfoPhase(EPPLaunchPolicyPhase.Phase.claims, "landrush"));
		claims.addInfoPhase(new EPPLaunchPolicyInfoPhase(EPPLaunchPolicyPhase.Phase.claims, "open"));
		claims.addCreateForm(EPPLaunchPolicyPhase.CreateForm.claims);
		claims.addCreateForm(EPPLaunchPolicyPhase.CreateForm.general);
		claims.setCreateValidateType(true);

		zone.addPhase(claims);

		// Custom LRP2
		EPPLaunchPolicyPhase lrp2 = new EPPLaunchPolicyPhase(EPPLaunchPolicyPhase.Phase.custom,
		      new GregorianCalendar(2018, 2, 15, 0, 0).getTime());
		lrp2.setName("lrp2");
		lrp2.setMode(EPPLaunchPolicyPhase.Mode.pendingRegistration);
		lrp2.setEndDate(new GregorianCalendar(2018, 3, 15, 0, 0).getTime());
		lrp2.setValidatePhase(true);
		lrp2.addValidatorId("lrp2-custom");
		lrp2.addStatus(
		      new EPPLaunchPolicyPhaseStatus(EPPLaunchPolicyPhaseStatus.Status.custom, "pendingInternalValidation"));
		lrp2.addStatus(new EPPLaunchPolicyPhaseStatus(EPPLaunchPolicyPhaseStatus.Status.allocated));
		lrp2.addStatus(new EPPLaunchPolicyPhaseStatus(EPPLaunchPolicyPhaseStatus.Status.rejected));
		lrp2.setPendingCreate(true);
		lrp2.setPollPolicy(new EPPLaunchPolicyPollPolicy(true, false, false));
		lrp2.addCheckForm(EPPLaunchPolicyPhase.CheckForm.claims);
		lrp2.addCheckForm(EPPLaunchPolicyPhase.CheckForm.availability);
		lrp2.addCheckForm(EPPLaunchPolicyPhase.CheckForm.trademark);
		lrp2.addMarkValidation(EPPLaunchPolicyPhase.MarkValidation.signedMark);
		sunrise.setMaxMarks(1);
		sunrise.addSignedMarkSupported("http://www.example.com/epp/lrp2-custom-1.0");
		sunrise.addEncodedSignedMarkSupported("http://www.example.com/epp/lrp2-custom-1.0");
		lrp2.addInfoPhase(new EPPLaunchPolicyInfoPhase(EPPLaunchPolicyPhase.Phase.claims, "open"));
		lrp2.addInfoPhase(new EPPLaunchPolicyInfoPhase(EPPLaunchPolicyPhase.Phase.custom, "lrp2"));
		lrp2.addCreateForm(EPPLaunchPolicyPhase.CreateForm.sunrise);
		lrp2.addCreateForm(EPPLaunchPolicyPhase.CreateForm.general);
		lrp2.addCreateForm(EPPLaunchPolicyPhase.CreateForm.claims);
		lrp2.addCreateForm(EPPLaunchPolicyPhase.CreateForm.mixed);
		lrp2.setCreateValidateType(true);

		zone.addPhase(lrp2);

		// Open
		EPPLaunchPolicyPhase open = new EPPLaunchPolicyPhase(EPPLaunchPolicyPhase.Phase.open,
		      new GregorianCalendar(2018, 3, 15, 0, 0).getTime());
		open.setValidatePhase(false);

		zone.addPhase(open);

		return zone;
	}

}
