/***********************************************************
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.codec.gen;

import java.io.ByteArrayOutputStream;
import java.io.PrintWriter;

import com.verisign.epp.util.TestThread;

/**
 * <code>EPPEncodeDecodeStats</code> capture the statistics related to a single
 * Encode/Decode Test. An Encode/Decode Test requirements are based on the
 * EPPCodecTst.testEncodeDecode method. The
 * <code>EPPCodecTst.testEncodeDecode</code> method will return an instance of
 * <code>EPPEncodeDecodeStats</code>, which provides an interface to select
 * individual attributes, or can be printed to an output stream with the
 * <code>toString</code> method. <br>
 * <br>
 * <code>EPPFactory</code> is initialized with the set of available EPP Command
 * Mappings. A method is provided to retrieve the list <code>EPPService</code>
 * descriptions of available EPP Command Mappings. The list of available EPP
 * Command Mappings can be used in <code>EPPGreeting</code> and in
 * <code>EPPLoginCmd</code>.
 */
public class EPPEncodeDecodeStats {
	/** Name of the test */
	private String name;

	/** Number of XML iterations */
	private long xmlIterations = 0;

	/** XML packet sime */
	private int xmlSize = 0;

	/** Start of XML test */
	private long xmlStartTime = 0;

	/** End of XML test */
	private long xmlEndTime = 0;

	/** Total XML test time */
	private long xmlTotalTime = 0;

	/** Formatted XML document */
	private byte[] xmlFormat = null;

	/** XML validation enabled? */
	private boolean xmlValidating = false;

	/** Number of Java serialization iterations */
	private long serialIterations = 0;

	/** Java serialization packet size */
	private int serialSize = 0;

	/** Java serialization test start time */
	private long serialStartTime = 0;

	/** Java serialization test end time */
	private long serialEndTime = 0;

	/** Java serialization test total time */
	private long serialTotalTime = 0;

	/**
	 * Construct an <code>EPPEncodeDecodeStats</code> instance with an
	 * <code>EPPMessage</code>, which will be used to set the name attribute.
	 *
	 * @param aMessage
	 *           {@link EPPMessage} being tested
	 */
	public EPPEncodeDecodeStats(EPPMessage aMessage) {
		name = "Message: " + aMessage.getClass().getName();
	}

	/**
	 * Construct an <code>EPPEncodeDecodeStats</code> with a specific name name.
	 *
	 * @param aName
	 *           Name of test.
	 */
	public EPPEncodeDecodeStats(String aName) {
		name = aName;
	}

	/**
	 * Is XML validation turned on?
	 *
	 * @return <code>true</code> if validation is on; <code>false</code>
	 *         otherwise.
	 */
	public boolean isXmlValidating() {
		return xmlValidating;
	}

	/**
	 * Set if XML validation is turned on? The validation setting will be
	 * reflected in the output generated by <code>toString</code>.
	 *
	 * @param aXmlValidating
	 *           <code>true</code> if validation is on; <code>false</code>
	 *           otherwise.
	 */
	void setXmlValidating(boolean aXmlValidating) {
		xmlValidating = aXmlValidating;
	}

	/**
	 * Gets the name of the test. This value is either explicitly set or is
	 * derived from the concrete <code>EPPMessage</code> class name.
	 *
	 * @return Name of test.
	 */
	public String getName() {
		return name;
	}

	/**
	 * Sets the name of the test. The name setting will be reflected in the
	 * output generated by <code>toString</code>.
	 *
	 * @param aName
	 *           Name of the test
	 */
	void setName(String aName) {
		name = aName;
	}

	/**
	 * Starts the timer for the run of an XML test. <code>stopXmlTimer</code>
	 * should be called to stop the timer, than <code>toString</code> can be
	 * called to output the result.
	 */
	public void startXmlTimer() {
		xmlStartTime = System.currentTimeMillis();
	}

	/**
	 * Stops the timer started by <code>startXmlTimer</code>. A call to
	 * <code>startXmlTimer</code> should be called prior to this method.
	 */
	public void stopXmlTimer() {
		if (xmlStartTime != 0) {
			xmlEndTime = System.currentTimeMillis();

			xmlTotalTime += (xmlEndTime - xmlStartTime);

			xmlStartTime = 0;

			xmlIterations++;
		}
	}

	/**
	 * Gets the total time to run an XML test(s) based on the calls to
	 * <code>startXmlTimer</code> and <code>stopXmlTimer</code>. The total time
	 * is cumlative across multiple iterations of an XML test.
	 *
	 * @return Total time to run XML tests in milliseconds.
	 */
	public long getXmlTotalTime() {
		return xmlTotalTime;
	}

	/**
	 * Gets the number of XML test iterations. Dividing the value of
	 * <code>getXmlTotalTime</code> by <code>getXmlIterations</code> will provide
	 * the average time in milliseconds of each iteration.
	 *
	 * @return Number of XML test iterations.
	 */
	public long getXmlIterations() {
		return xmlIterations;
	}

	/**
	 * Gets the package size of the XML packet in bytes.
	 *
	 * @return XML packet size in bytes.
	 */
	public int getXmlSize() {
		return xmlSize;
	}

	/**
	 * Sets the package size of the XML packet in bytes.
	 *
	 * @param aXmlSize
	 *           XML packet size in bytes.
	 */
	public void setXmlSize(int aXmlSize) {
		xmlSize = aXmlSize;
	}

	/**
	 * Gets the formatted EPP XML document that can be sent to an OutputStream.
	 *
	 * @return Formatted EPP XML document
	 */
	public byte[] getXmlFormat() {
		return xmlFormat;
	}

	/**
	 * Sets the formatted EPP XML document.
	 *
	 * @param aXmlFormat
	 *           Formatted EPP XML document
	 */
	public void setXmlFormat(byte[] aXmlFormat) {
		xmlFormat = aXmlFormat;
		xmlSize = xmlFormat.length;
	}

	// ---------- Java Serialization Statistics Methods ---------------

	/**
	 * Starts the timer for the run of an Java Serialization test.
	 * <code>stopSerialTimer</code> should be called to stop the timer, than
	 * <code>toString</code> can be called to output the result.
	 */
	public void startSerialTimer() {
		serialStartTime = System.currentTimeMillis();
	}

	/**
	 * Stops the timer started by <code>startSerialTimer</code>. A call to
	 * <code>startSerialTimer</code> should be called prior to this method.
	 */
	public void stopSerialTimer() {
		if (serialStartTime != 0) {
			serialEndTime = System.currentTimeMillis();

			serialTotalTime += (serialEndTime - serialStartTime);

			serialStartTime = 0;

			serialIterations++;
		}
	}

	/**
	 * Gets the total time to run an Java Serialization test(s) based on the
	 * calls to <code>startSerialTimer</code> and <code>stopSerialTimer</code>.
	 * The total time is cumlative across multiple iterations of a Java
	 * Serialization test.
	 *
	 * @return Total time to run Java Serialization tests in milliseconds.
	 */
	public long getSerialTotalTime() {
		return serialTotalTime;
	}

	/**
	 * Gets the number of Java Serialization test iterations. Dividing the value
	 * of <code>getSerialTotalTime</code> by <code>getSerialIterations</code>
	 * will provide the average time in milliseconds of each iteration.
	 *
	 * @return Number of Java Serialization test iterations.
	 */
	public long getSerialIterations() {
		return serialIterations;
	}

	/**
	 * Gets the package size of the Java Serialization packet in bytes.
	 *
	 * @return Java Serialization packet size in bytes.
	 */
	public int getSerialSize() {
		return serialSize;
	}

	/**
	 * Sets the package size of the Java Serialization packet in bytes.
	 *
	 * @param aSerialSize
	 *           Java Serialization packet size in bytes.
	 */
	public void setSerialSize(int aSerialSize) {
		serialSize = aSerialSize;
	}

	/**
	 * Format the <code>EPPEncodeDecodeStats</code> statistics to a
	 * <code>String</code> in the expectation that it will be written to an
	 * <code>OutputStream</code> like <code>System.out</code>.
	 *
	 * @return Encode/Decode statistics formatted in a <code>String</code>.
	 */
	public String toString() {
		ByteArrayOutputStream ret = new ByteArrayOutputStream();

		try {
			PrintWriter writer = new PrintWriter(ret);

			writer.println("");

			if (Thread.currentThread() instanceof TestThread) {
				writer.println(Thread.currentThread().getName() + ": " + name);
			}
			else {
				writer.println(name);
			}

			writer.println("-------------------------------------------------------------------------------------");
			writer.println("");

			if (xmlFormat != null) {
				writer.println("XML Format:");
				writer.flush();
				ret.write(xmlFormat);
				writer.println("");
				writer.println("");
			}

			writer.println("XML Size:                  " + xmlSize + " bytes");
			writer.println("XML Iterations:            " + xmlIterations);
			writer.println("XML Validating:            " + xmlValidating);
			writer.println("XML Total Time:            " + xmlTotalTime + " milliseconds");

			if (xmlIterations != 0) {
				writer.println("XML Time per Iteration:    " + (xmlTotalTime / xmlIterations) + " milliseconds");
			}

			writer.println("Serial Size:               " + serialSize + " bytes");
			writer.println("Serial Iterations:         " + serialIterations);
			writer.println("Serial Total Time:         " + serialTotalTime + " milliseconds");

			if (serialIterations != 0) {
				writer.println("Serial Time per Iteration: " + (serialTotalTime / serialIterations) + " milliseconds");
			}

			writer.println("");
			writer.flush();
			writer.close();
		}
		catch (java.io.IOException e) {
			e.printStackTrace();
		}

		return ret.toString();
	}

}
