/*******************************************************************************
 * Copyright (c) 2004 Actuate Corporation. All rights reserved. This program and
 * the accompanying materials are made available under the terms of the Eclipse
 * Public License v1.0 which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors: Actuate Corporation - initial API and implementation
 ******************************************************************************/

package org.eclipse.birt.test.performance.parser;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

public class CaseLogger
{

	Map taskMap = new HashMap( );

	public String toString( )
	{
		StringBuffer sb = new StringBuffer( );
		sb.append( taskMap );

		return sb.toString( );
	}

	public static class TaskEntry
	{

		String taskName;

		// id to ThreadEntry
		Map threadMap = new TreeMap( );

		TaskEntry( String taskName )
		{
			this.taskName = taskName;
		}

		void addThread( ThreadEntry thread )
		{
			this.threadMap.put( String.valueOf( thread.threadId ), thread );
		}

		public ThreadEntry getThread( int id )
		{
			return (ThreadEntry) this.threadMap.get( String.valueOf( id ) );
		}

		// return sorted thread list, sort by thread id.
		public List sortedThreadList( )
		{
			return new ArrayList( threadMap.values( ) );
		}

		public String toString( )
		{
			StringBuffer sb = new StringBuffer( );
			sb.append( taskName );
			sb.append( "\n" );
			sb.append( "threadMap:" );
			sb.append( threadMap );
			return sb.toString( );
		}

		/**
		 * Returns average duration list, each of the element is a
		 * <code>DurationEntry</code>, duration timespan is the average
		 * execution time for a specific report by all thread.
		 * 
		 */

		public List avgDurations( )
		{
	
			// report id to average duration.
			Map reportIdDurations = new TreeMap( );

			// report id to thread count
			Map reportIdThreadCount = new HashMap( );

			Iterator threadIter = this.threadMap.values( ).iterator( );
			while ( threadIter.hasNext( ) )
			{
				ThreadEntry thread = (ThreadEntry) threadIter.next( );

				List durations = thread.sortedDurationList( );
				for ( int i = 0; i < durations.size( ); i++ )
				{
					DurationEntry duration = (DurationEntry) durations.get( i );

					DurationEntry avgDuration = (DurationEntry) reportIdDurations
							.get(duration.reportid );

					if ( avgDuration == null )
					{
						avgDuration = new DurationEntry( duration.reportid,
								duration.reportName, duration.timespan );
						reportIdDurations.put( String
								.valueOf( duration.reportid ), avgDuration );
					}
					else
					{
						avgDuration.timespan = avgDuration.timespan
								+ duration.timespan;
					}

					// increase the thread count for the report.

					Integer count = (Integer) reportIdThreadCount.get( String
							.valueOf( duration.reportid ) );
					if ( count == null )
						count = new Integer( 1 );
					else
						count = new Integer( count.intValue( ) + 1 );

					reportIdThreadCount.put(
							String.valueOf( duration.reportid ), count );

				}
			}

			// calc for the average time
			Iterator iter = reportIdDurations.values( ).iterator( );
			while ( iter.hasNext( ) )
			{
				DurationEntry duration = (DurationEntry) iter.next( );
				Integer threadcount = (Integer) reportIdThreadCount.get( String
						.valueOf( duration.reportid ) );

				assert threadcount != null;
				duration.timespan = duration.timespan / threadcount.intValue( );
			}

			return new ArrayList( reportIdDurations.values( ) ) ;
		}
	}

	public static class ThreadEntry
	{

		int threadId;

		Comparator c = new Comparator( ) {

			public int compare( Object o1, Object o2 )
			{
				int reportid1 = ( (Integer) o1 ).intValue( );
				int reportid2 = ( (Integer) o2 ).intValue( );
				return reportid1 - reportid2;
			}
		};

		// report name to DurationEntry.
		Map durationMap = new TreeMap( );

		ThreadEntry( int threadId )
		{
			this.threadId = threadId;
		}

		public String toString( )
		{
			StringBuffer sb = new StringBuffer( );
			sb.append( "threadid[" );
			sb.append( threadId );
			sb.append( "]\n" );
			sb.append( durationMap );
			return sb.toString( );
		}

		void addDuration( DurationEntry duration )
		{
			this.durationMap
					.put( String.valueOf( duration.reportid ), duration );
		}

		DurationEntry getDuration( String report )
		{
			return (DurationEntry) this.durationMap.get( report );
		}

		public int getId( )
		{
			return this.threadId;
		}

		// return sorted duration list, sorted by report id.
		public List sortedDurationList( )
		{
			return new ArrayList( this.durationMap.values( ) );
		}
	}

	public static class DurationEntry
	{

		String reportid;
		String reportName;
		long timespan;

		DurationEntry( String reportid, String reportName, long timespan )
		{
			this.reportid = reportid;
			this.reportName = reportName;
			this.timespan = timespan;
		}

		public String toString( )
		{
			StringBuffer sb = new StringBuffer( );
			sb.append( "duration[" );
			sb.append( reportid );
			sb.append( "," );
			sb.append( reportName );
			sb.append( "," );
			sb.append( timespan );
			sb.append( "ms" );
			sb.append( "\n" );
			return sb.toString( );
		}

		public String getReportName( )
		{
			return reportName;
		}

		public long getTimespan( )
		{
			return timespan;
		}

		public String getReportId( )
		{
			return this.reportid;
		}
	}

	/**
	 * 
	 * @param taskName
	 *            name for the task: "Run", "RenderN", "RenderAll" or
	 *            "RunAndRender"
	 * @param report
	 *            name of the running report
	 * @param threadId
	 *            thread id
	 * @param timespan
	 */
	public void logResult( String taskName, ReportDesignNode report,
			int threadId, long timespan )
	{
		TaskEntry taskEntry = (TaskEntry) this.taskMap.get( taskName );
		if ( taskEntry == null )
		{
			taskEntry = new TaskEntry( taskName );
			this.taskMap.put( taskName, taskEntry );
		}

		assert taskEntry != null;
		ThreadEntry threadEntry = taskEntry.getThread( threadId );
		if ( threadEntry == null )
		{
			threadEntry = new ThreadEntry( threadId );
			taskEntry.addThread( threadEntry );
		}

		threadEntry.addDuration( new DurationEntry( report.id, report.name,
				timespan ) );
	}

	/**
	 * Returns task list covered in the case.
	 * 
	 * @return
	 */
	public List taskList( )
	{
		return new ArrayList( this.taskMap.keySet( ) );
	}

	/**
	 * Returns <code>TaskEntry</code> by a task name.
	 * 
	 * @param taskName
	 * @return
	 */

	public TaskEntry taskEntry( String taskName )
	{
		return (TaskEntry) this.taskMap.get( taskName );
	}

}
