/***********************************************************
Copyright (C) 2019 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.loginsecpolicy.v04;

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.EPPTransId;
import com.verisign.epp.codec.registry.v02.EPPRegistryInfoResp;
import com.verisign.epp.codec.registry.v02.EPPRegistrySystemInfo;
import com.verisign.epp.codec.registry.v02.EPPRegistryTst;
import com.verisign.epp.util.TestThread;

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

/**
 * Test of the packet encoder and decoder (CODEC) for the Login Security Policy
 * Extension. The Login Security Policy Extension is a command / response
 * extension of a zone object in the Registry Mapping. The
 * {@link EPPRegistryTst} utility methods are used to supporting creating a full
 * Registry Mapping command or response that is extended by the Login Security
 * Policy Extension.
 */
public class EPPLoginSecPolicyTst extends TestCase {
	/**
	 * Number of unit test iterations to run. This is set in
	 * {@code EPPCodecTst.main}
	 */
	static private long numIterations = 1;

	public EPPLoginSecPolicyTst(String name) {
		super(name);
	}

	/**
	 * Test the registry info response for the zone info that includes the Launch
	 * Policy Extension.
	 */
	public void testRegistryInfoSystemInfo() {
		EPPCodecTst.printStart("testRegistryInfoSystemInfo");

		// Create a Registry Info Response
		EPPTransId theTransId = new EPPTransId("ABC-12345", "54321-XYZ");
		EPPRegistrySystemInfo systemInfo = EPPRegistryTst.createSystemInfo();
		EPPRegistryInfoResp theResponse = new EPPRegistryInfoResp(theTransId, systemInfo);

		// Add the Login Security Policy Extension
		EPPLoginSecPolicyInfData loginSecPolicyExt = new EPPLoginSecPolicyInfData(buildLoginSecSystem());
		theResponse.addExtension(loginSecPolicyExt);

		EPPEncodeDecodeStats responseStats = EPPCodecTst.testEncodeDecode(theResponse);
		System.out.println(responseStats);

		EPPCodecTst.printEnd("testRegistryInfoSystemInfo");
	}

	/**
	 * 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
	 *           Program 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("EPPLoginSecPolicyTst Thread " + i, EPPLoginSecPolicyTst.suite());
				thread.start();
			}
		}
		else { // Single threaded mode.
			junit.textui.TestRunner.run(EPPLoginSecPolicyTst.suite());
		}
	}

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

		TestSuite suite = new TestSuite(EPPLoginSecPolicyTst.class);

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

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

		// Add the factories to the EPPCodec.
		try {
			EPPFactory.getInstance().addMapFactory("com.verisign.epp.codec.registry.v02.EPPRegistryMapFactory");
			EPPFactory.getInstance()
			      .addExtFactory("com.verisign.epp.codec.loginsecpolicy.v04.EPPLoginSecPolicyExtFactory");
		}
		catch (EPPCodecException e) {
			Assert.fail("EPPCodecException adding factories to EPPCodec: " + e);
		}

		return suite;
	}

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

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

	/**
	 * 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;
	}

	/**
	 * Build a populated {@link EPPLoginSecPolicyEvent} 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 EPPLoginSecPolicyEvent}
	 * 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 EPPLoginSecPolicyEvent} based on the sample
	 *         included in draft-gould-regext-launch-policy.
	 */
	public static EPPLoginSecPolicySystem buildLoginSecSystem() {
		EPPLoginSecPolicySystem theSystem = new EPPLoginSecPolicySystem();

		EPPLoginSecPolicyPassword thePassword = new EPPLoginSecPolicyPassword();
		thePassword.setExpression(
		      "(?=.*\\d)(?=.*[a-zA-Z])(?=.*[\\x21-\\x2F\\x3A-\\x40\\x5B-\\x60\\x7B-\\x7E])(?!^\\s+)(?!.*\\s+$)(?!.*\\s{2,})^[\\x20-\\x7e]{16,32}$");
		thePassword.setDescription(
		      "16 to 32 printable characters (alphanumeric, space, and special characters) with at least one number, letter, and special character, with no leading or trailing whitespace, and with no consecutive spaces.");

		thePassword.setSpecialRules(Boolean.FALSE);
		thePassword.setRestrictedWords(Boolean.TRUE);
		thePassword.setRestrictedWordsUrl("http://example.com/restrictedwords");

		theSystem.setPassword(thePassword);

		theSystem.setUserAgentSupport(Boolean.TRUE);

		EPPLoginSecPolicyEvent theEvent;

		// Type "password"
		theEvent = new EPPLoginSecPolicyEvent();
		theEvent.setType(EPPLoginSecPolicyEvent.EventType.password);
		theEvent.addLevel(EPPLoginSecPolicyEvent.EventLevel.error);
		theEvent.addLevel(EPPLoginSecPolicyEvent.EventLevel.warning);
		theEvent.setExDate(Boolean.TRUE);
		theEvent.setExPeriod("P90D");
		theEvent.setWarningPeriod("P15D");
		theEvent.setErrorAction(EPPLoginSecPolicyEvent.EventErrorAction.login);
		theSystem.addEvent(theEvent);

		// Type "certificate"
		theEvent = new EPPLoginSecPolicyEvent();
		theEvent.setType(EPPLoginSecPolicyEvent.EventType.certificate);
		theEvent.addLevel(EPPLoginSecPolicyEvent.EventLevel.error);
		theEvent.addLevel(EPPLoginSecPolicyEvent.EventLevel.warning);
		theEvent.setExDate(Boolean.TRUE);
		theEvent.setWarningPeriod("P15D");
		theEvent.setErrorAction(EPPLoginSecPolicyEvent.EventErrorAction.connect);
		theSystem.addEvent(theEvent);

		// Type "cipher"
		theEvent = new EPPLoginSecPolicyEvent();
		theEvent.setType(EPPLoginSecPolicyEvent.EventType.cipher);
		theEvent.addLevel(EPPLoginSecPolicyEvent.EventLevel.warning);
		theEvent.setExDate(Boolean.FALSE);
		theSystem.addEvent(theEvent);

		// Type "tlsProtocol"
		theEvent = new EPPLoginSecPolicyEvent();
		theEvent.setType(EPPLoginSecPolicyEvent.EventType.tlsProtocol);
		theEvent.addLevel(EPPLoginSecPolicyEvent.EventLevel.warning);
		theEvent.setExDate(Boolean.FALSE);
		theSystem.addEvent(theEvent);

		// Type "stat" "failedLogins"
		theEvent = new EPPLoginSecPolicyEvent();
		theEvent.setType(EPPLoginSecPolicyEvent.EventType.stat);
		theEvent.setName("failedLogins");
		theEvent.addLevel(EPPLoginSecPolicyEvent.EventLevel.warning);
		theEvent.setExDate(Boolean.FALSE);
		theEvent.setThreshold(Integer.valueOf(100));
		theEvent.setPeriod("P1D");
		theSystem.addEvent(theEvent);

		// Type "custom" "myCustomEvent"
		theEvent = new EPPLoginSecPolicyEvent();
		theEvent.setType(EPPLoginSecPolicyEvent.EventType.custom);
		theEvent.setName("myCustomEvent");
		theEvent.addLevel(EPPLoginSecPolicyEvent.EventLevel.warning);
		theEvent.setExDate(Boolean.FALSE);
		theSystem.addEvent(theEvent);

		return theSystem;
	}
}
