sysperfana/heapanalyser/Libraries/Engine/HeapComparisonLib/CSV/Workers/CSVWorkerTwoDataSetComparator.cs
author Matti Laitinen <matti.t.laitinen@nokia.com>
Tue, 15 Jun 2010 12:47:20 +0300
changeset 8 15296fd0af4a
permissions -rw-r--r--
HeapAnalyser 1.1.0

/*
* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
*   this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
*   this list of conditions and the following disclaimer in the documentation
*   and/or other materials provided with the distribution.
* - Neither the name of Nokia Corporation nor the names of its contributors
*   may be used to endorse or promote products derived from this software
*   without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* 
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description: 
*
*/

using System;
using System.IO;
using System.Collections.Generic;
using System.Threading;
using SymbianUtils;

namespace HeapComparisonLib.CSV
{
    internal class CSVWorkerTwoDataSetComparator : DisposableObject
	{
		#region Observer related
		public enum TEvent
		{
			EExportingStarted = 0,
			EExportingProgress,
			EExportingComplete
		}

        public delegate void Observer( TEvent aEvent, string aFullName );
		public event Observer eObserver;
		#endregion

		#region Constructors & destructor
        public CSVWorkerTwoDataSetComparator( CSVDataSet aCol1, CSVDataSet aCol2, string aOutputFileName )
		{
            // Make copies because we actually dequeue items from the list as we processed them
            // and we must not alter the originals or else we'll break the subsequent comparison(s)
			iCol1 = new CSVDataSet( aCol1 );
			iCol2 = new CSVDataSet( aCol2 );
            iExcelExporter = new CSVExcelExporterTwoDataSets( aOutputFileName, aCol1.FileName, aCol2.FileName );
		}
		#endregion

		#region API
		public void CompareAndSaveAsync()
		{
            iWorkerThread = new System.Threading.Thread( new ThreadStart( ThreadFunction ) );
            iWorkerThread.Start();
		}
		#endregion

		#region Properties
		public int Progress
		{
			get
            {
                int count = 0;
                int index = 0;
                //
                lock ( this )
                {
                    index = iIndex;
                    count = iPairings.Count;
                }

                float ret = (float) index / (float) count;
                ret *= 100.0f;
                return (int) ret;
            }
		}
		#endregion

        #region From DisposableObject
        protected override void CleanupManagedResources()
        {
            try
            {
                if ( iExcelExporter != null )
                {
                    iExcelExporter.Dispose();
                    iExcelExporter = null;
                }
            }
            finally
            {
                base.CleanupManagedResources();
            }
        }
        #endregion

        #region Thread function
        private void ThreadFunction()
        {
            // Report started
            if ( eObserver != null )
            {
                eObserver( TEvent.EExportingStarted, null );
            }

            // Create our list of sorted comparison pairs.
            BuildPairs();

            // Now compare them and export to excel
            CompareAndExport();

            // Dispose excel object - closes file
            iExcelExporter.Dispose();
            iExcelExporter = null;

            // Report finished
            if ( eObserver != null )
            {
                eObserver( TEvent.EExportingComplete, null );
            }
        }
		#endregion

		#region Internal methods
        private void BuildPairs()
        {
            // Treat the first collection as the master list. 
            int count = iCol1.Count;
            for ( int i = count - 1; i >= 0; i-- )
            {
                CSVThread master = iCol1[ i ];

                // Remove primary entry also
                iCol1.Remove( master );

                // Create or locate secondary
                CSVThread secondary = FindAppropriateSecondary( master, iCol2 );

                // Create a pairing
                iPairings.Add( master.FullName, new CSVThreadPair( master, secondary ) );
            }

            // Now do the same but for the secondary list this time. It should
            // be largely empty. The only entries that will remain are threads
            // which don't exist in the primary list.
            count = iCol2.Count;
            for ( int i = count - 1; i >= 0; i-- )
            {
                CSVThread master = iCol2[ i ];

                // Remove primary entry also
                iCol2.Remove( master );

                // Create or locate secondary
                CSVThread secondary = FindAppropriateSecondary( master, iCol1 );

                // Create a pairing - but this time the master is the 2nd entry 
                // in the pair. This ensures we keep the threads in the correct
                // columns in the final excel spreadsheet.
                iPairings.Add( master.FullName, new CSVThreadPair( secondary, master ) );
            }
        }

        private CSVThread FindAppropriateSecondary( CSVThread aMaster, CSVDataSet aSecondaryCol )
        {
            System.Diagnostics.Debug.Assert( aMaster.FullName != string.Empty );

            // We must try to find the corresponding secondary thread with which to compare
            // aMaster.
            CSVThread secondary = aSecondaryCol[ aMaster.FullName ];
            if ( secondary == null )
            {
                // Secondary collection doesn't contain this thread, so make a default entry.
                secondary = CSVThread.NewDefault( aMaster.FullName );
            }
            else
            {
                aSecondaryCol.Remove( secondary );
            }

            return secondary;
        }

        private void CompareAndExport()
        {
            lock ( this )
            {
                iIndex = 0;
            }

            foreach ( KeyValuePair<string, CSVThreadPair> kvp in iPairings )
            {
                CSVThreadPair pair = kvp.Value;

                // Report progress to any observers
                if ( eObserver != null )
                {
                    eObserver( TEvent.EExportingProgress, kvp.Key );
                }

                lock ( this )
                {
                    ++iIndex;
                }

                CompareAndExport( pair.Master, pair.Secondary );
            }
        }

        private void CompareAndExport( CSVThread aMaster, CSVThread aSecondary )
        {
            iExcelExporter.CompareThread( aMaster, aSecondary );
        }
		#endregion

		#region Data members
        private readonly CSVDataSet iCol1;
        private readonly CSVDataSet iCol2;
        private CSVExcelExporterTwoDataSets iExcelExporter = null;
        private SortedList<string, CSVThreadPair> iPairings = new SortedList< string, CSVThreadPair>();
        private System.Threading.Thread iWorkerThread;
        private int iIndex = 0;
		#endregion
	}
}