tsrc/testing/tools/testdoc.pl
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 25 May 2010 12:44:54 +0300
branchRCL_3
changeset 15 8f0df5c82986
parent 0 96612d01cf9f
permissions -rw-r--r--
Revision: 201019 Kit: 2010121

#
# Copyright (c) 2006 Nokia Corporation and/or its subsidiary(-ies).
# All rights reserved.
# This component and the accompanying materials are made available
# under the terms of "Eclipse Public License v1.0"
# which accompanies this distribution, and is available
# at the URL "http://www.eclipse.org/legal/epl-v10.html".
#
# Initial Contributors:
# Nokia Corporation - initial contribution.
#
# Contributors:
#
# Description: 
#

#-----------------------------------------------
# Sequence
#-----------------------------------------------
# Reads parameters -> [if !ok params] ShowHelp
# ReadConfigFiles
#	-> ParseCfg
#	-> ReadCase
#
#    for all testreports:
#       ReadTestRunInfoFromStifReport
#           GetReportLogFileNames
#       ParseResultsAndLogs
#
#    ParseResultsAndLogs
#        WriteCaseLog
#			LogLineTimeMatchesForCase
#			FormatLogLine
#        UpdateCase
#        CheckCaseEntriesInLog
#
# OLD:
#	-> ParseReportFile
#		-> ReadReportLogs
#		-> WriteCaseLog
#			-> LogLineTimeMatchesForCase
#			-> FormatLogLine
#		-> CheckCaseEntriesInLog
#
# ReportNotDocumentedCases
# SortCases
# CalculateStats
# WriteOfficeXml -> XmlReadyText
# exit()

#-----------------------------------------------
# Other functions:
#-----------------------------------------------
# RemoveWhiteSpaces
# SpecialChars
# ReplaceChar
# GetCaseField
# GetCase (id or name)
# GetCaseDesc (id or name)
# PrintCases
# JustFormatLogFile

#
#
#
# STIF CFG:
#************************************************************************************
#[IptvETDescription]
# Testname: <insert text here>
#
# Purpose: <insert text here>
#
# Means: <insert text here>
#
# Required environment settings: <insert text here>
#
# Verification: <insert text here>
#
# Note: <insert text here>
#
# Related requirements: <reqid> <reqid> <reqid> ..
#
#[EndIptvETDescription]
#------------------------------------------------------------------------------------
#[Test]
# do stuff here
#[Endtest]

#------------------------------------------------------------------------------------
# Includes
#------------------------------------------------------------------------------------
#use strict;
use warnings;
use Cwd; # for cwd
use FindBin; # for FindBin:Bin
use File::Path; # for mkpath
use File::Copy;
use Date::Calc;

#------------------------------------------------------------------------------------
# Globals
#------------------------------------------------------------------------------------

my $lastCaseLogLine = 0;

my $ALT_RESULTCOUNT = 10; # maximum number of runs in alternative report

my @cases; #references to case arrays
my @gCfgFiles; # list of cfg files.
my @caseDescs; # case description and the case itself in text
my @notDocumentedCases; #array to hold information about the cases without documentation

$regexpCaseName = '[\x3C\x3E\(\)\[\]\w.,\/:_\-&\' ]+';

my $caseDefaultStatus = 			"NOT RUN";

#
# Case field numerations
#

my $CASE_NAME = 					0;
my $CASE_ID = 						1;
my $CASE_RUN_TIMES = 				2;
my $CASE_CRASHED = 					3;
my $CASE_FAILED = 					4;
my $CASE_PASSED = 					5;
my $CASE_STATUS = 					6;
my $CASE_PURPOSE = 					7;
my $CASE_MEANS = 					8;
my $CASE_REQUIRED_SETTINGS = 		9;
my $CASE_RELATED_REQUIREMENTS = 	10;
my $CASE_VERIFICATION = 			11;
my $CASE_NOTE = 					12;
my $CASE_REASON = 					13; # where crashed or what returned the error code
my $CASE_RESULT = 					14; # error code
my $CASE_LOG_FILE = 				15; # test case specific log file.
my $CASE_LOG_FILE_SCRIPTER = 	    16; # test case specific log from STIF testscripter logs.
my $CASE_CHECK_RESULT_LOG_FILE = 	17; # set if the case is in the log files, if next line is found: >>>Case start: ETxxxxx CaseName
									# or STIF own trace: Starting testcase [ET1000 Add multiple Iaps] (usually from fasttrace or emulator log)
my $CASE_CFG_FILE = 				18;
my $CASE_RUN_TIME_SECONDS = 		19; # how many seconds it took to run the case
my $CASE_REPORTLINE1 =              20;
my $CASE_REPORTLINE2 =              21;
my $CASE_REPORTLINE3 =              22;
my $CASE_ENTRY_LOG_START =          23;

my $TDTOOLRESULTFILE = ".\\text_file.txt";
my $XML_OUTPUT_FILE = ".\\test_cases.xml";
my $XML_BRIEF_OUTPUT_FILE = ".\\test_cases_brief.xml";
my $NOT_DOCUMENTED_CASES_FILE = ".\\test_cases_notdocumented.txt";

my @globalTempFiles;

#
# Tags inside the xml, will be replaced by case data when writing the xml file
#

my $CaseCountMul8 = "CASE_COUNT_MUL8";

my $STYLE_ID_STATUS_TAG = "STYLE_ID_STATUS"; # must be in the xml data

my $STYLE_ID_STATUS_FAILED = "s36";
my $STYLE_ID_STATUS_PASSED = "s37";
my $STYLE_ID_STATUS_CRASHED = "s38";
my $STYLE_ID_STATUS_UNKNOWN = "s401";
my $STYLE_ID_STATUS_NA = "s39";

my $STYLE_ID_STATUS_FAILED_CENTERED = "s36centered";
my $STYLE_ID_STATUS_PASSED_CENTERED = "s37centered";
my $STYLE_ID_STATUS_CRASHED_CENTERED = "s38centered";
my $STYLE_ID_STATUS_UNKNOWN_CENTERED = "s401centered";
my $STYLE_ID_STATUS_NA_CENTERED = "s39centered";

# these must be in the xml data to get the results inserted into xml
my $xmlDataCaseName = "XML_DATA_CASE_NAME";
my $xmlDataCaseRunTimes = "XML_DATA_CASE_RUN_TIMES";
my $xmlDataCaseFailed = "XML_DATA_CASE_FAILED";
my $xmlDataCaseCrashed = "XML_DATA_CASE_CRASHED";
my $xmlDataCasePassed = "XML_DATA_CASE_PASSED";
my $xmlDataCaseStatus = "XML_DATA_CASE_STATUS";
my $xmlDataCasePurpose = "XML_DATA_CASE_PURPOSE";
my $xmlDataCaseMeans = "XML_DATA_CASE_MEANS";
my $xmlDataCaseRequiredSettings = "XML_DATA_CASE_REQUIRED_SETTINGS";
my $xmlDataCaseRelatedRequirements = "XML_DATA_CASE_RELATED_REQUIREMENTS";
my $xmlDataCaseVerification = "XML_DATA_CASE_VERIFICATION";
my $xmlDataCaseNote = "XML_DATA_CASE_NOTE";
my $xmlDataCaseReason = "XML_DATA_CASE_REASON";
my $xmlDataCaseResult = "XML_DATA_CASE_RESULT";
my $xmlDataCaseLink1 = "XML_DATA_CASE_LINK1";
my $xmlDataCaseLink2 = "XML_DATA_CASE_LINK2";

my $xmlDataSummaryCaseCount = "XML_DATA_SUMMARY_TOTAL_CASES";
my $xmlDataSummaryPassed = "XML_DATA_SUMMARY_PASSED";
my $xmlDataSummaryFailed = "XML_DATA_SUMMARY_FAILED";
my $xmlDataSummaryCrashed = "XML_DATA_SUMMARY_CRASHED";
my $xmlDataSummaryTimeout = "XML_DATA_SUMMARY_TIMEOUT";
my $xmlDataSummaryPassRateTotal = "XML_DATA_SUMMARY_PASS_RATE_TOTAL";
my $xmlDataSummaryPassRateRun = "XML_DATA_SUMMARY_PASS_RATE_RUN";
my $xmlDataSummaryRunRate = "XML_DATA_SUMMARY_RUN_RATE";

my $xmlDataAltDateX = "XML_DATA_ALTDATE";

my $xmlDataAltResultX = "XML_DATA_ALTRESULT";

my $xmlDataCfgFile = "XML_DATA_CFG_FILE";

#
# Statistics
#

my $summaryCaseCount = 0;
my $summaryPassedCases = 0;
my $summaryFailedCases = 0;
my $summaryCrashedCases = 0;
my $summaryTimeoutCases = 0;
my $summaryPassRateTotal = 0;
my $summaryPassRateRun = 0;
my $summaryRunRate = 0;

#
# Xml data
#

my $xmlHeader;
my $xmlHeaderTableColumns;
my $xmlHeaderTableColumnsBrief;
my $xmlFooter;
my $xmlDataEmptyRow;
my $xmlSummaryData;
my $xmlData;
my $xmlDataCaseStatusDisabled;
my $xmlData2;
my $xmlDataBriefHeader;
my $xmlDataBrief;
my $xmlCfgFileBrief;
my $xmlHeaderTableColumnsAlt;
my $xmlCfgFileAltHeader;
my $xmlCfgFileAltData;

InitXmlData();

#------------------------------------------------------------------------------------
# GLOBAL CODE
#------------------------------------------------------------------------------------

my $argcount = scalar(@ARGV);

my $optionSortCases = 0;
my $optionShowMessages = 0;
my $optionHtml = 0;
my $optionLogAllCases = 1;
my $optionNoLogs = 0;
my $optionNoSecurityTests = 0;
my $optionNoLiveTvTests = 0;
my $optionCaseIncludedInLog = 0;
my $optionGoodIsBetter = 1;
my $optionPrintCfgSummaries = 0;
my $optionCaseRunTimes = 0;
my $optionFinalDoc = 1;
my $optionFixFilename = "";
my $optionDebug = 0;
my $optionCaseList = "";
my $optionAltResults = 0;
my $optionLogFileName = "fusion";

while(scalar(@ARGV) >= 1)
{
	my $argument = shift(@ARGV);

	if($argument eq "-h")
	{
		ShowHelp();
	}

	elsif($argument eq "-e")
	{
		$optionShowMessages = 1;
	}

	elsif($argument eq "-s")
	{
		$optionSortCases = 1;
	}

	elsif($argument eq "-html")
	{
		$optionHtml = 1;
	}

	elsif($argument eq "-logall")
	{
		$optionLogAllCases = 1;
	}

	elsif($argument eq "-nologs")
	{
		$optionNoLogs = 1;
	}

	elsif($argument eq "-nosecuritytests")
	{
		$optionNoSecurityTests = 1;
	}

	elsif($argument eq "-nolivetvtests")
	{
		$optionNoLiveTvTests = 1;
	}

	elsif($argument eq "-i")
	{
		$optionCaseIncludedInLog = 1;
	}

	elsif($argument eq "-file")
	{
		$file = shift(@ARGV);

		JustFormatLogFile($file);
		exit;
	}
	elsif($argument eq "-runtimes")
	{
		$optionCaseRunTimes = 1;
	}

	elsif($argument eq "-xxx")
	{
		$optionCaseIncludedInLog = 1;
		$optionNoLiveTvTests = 1;
		$optionNoSecurityTests = 1;
		$optionHtml = 1;
	}
	elsif($argument eq "-good")
	{
		$optionGoodIsBetter = 1;
	}
	elsif($argument eq "-cfgsum")
	{
		$optionPrintCfgSummaries = 1;
	}
	elsif($argument eq "-finalize")
	{
		$optionFinalDoc = 1;
	}
	elsif($argument eq "-fix") {
		$optionFixFilename = shift(@ARGV);
		FixExcelLogPaths();
        exit();
	}
	elsif($argument eq "-debug") {
	    $optionShowMessages = 1;
	    $optionDebug = 1;
	}
	elsif($argument eq "-caselist") {
	    $optionCaseList = shift(@ARGV);
	}
	elsif($argument eq "-alt") {
	    $optionAltResults = 1;
	}
	elsif( $argument eq "-logfile") {
		$optionLogFileName = shift(@ARGV);
	}
	else
	{
	    ShowHelp();
	}
}

UnzipAndCopyFiles();

my $totalExecutionTime = 0;

my $caseLogOutDir = "testcase_logs\\testcase_logs\\";

my @caseList;

if($optionCaseList ne "")
{
    ReadCaseList(\@caseList, $optionCaseList);
}

# Find cfg files.
FindCfgFiles( ".", \@gCfgFiles );

# None found from current dir, see one dir lower.
FindCfgFiles( "..", \@gCfgFiles ) if( scalar( @gCfgFiles ) < 1 );

# Parse results
if($optionPrintCfgSummaries)
{
	PrintCfgSummaries();
}
elsif( !$optionAltResults )
{
    my $res = ReadTestReports();

	if( $res == 0 )
	{
        foreach my $file ( @globalTempFiles )
        {
            unlink $file if( -e $file );
        }
		print("No reports to read.\n");
		exit;
	}

    #ReportNotDocumentedCases($NOT_DOCUMENTED_CASES_FILE);

    if($optionSortCases)
    {
	    @cases = sort SortCases @cases;
    }

    CalculateStats();

    #WriteOfficeXml($XML_OUTPUT_FILE, 0);
    WriteOfficeXml($XML_BRIEF_OUTPUT_FILE, 1);
}
else
{
    my @runs;
    ReadTestReportsAlt(\@runs);

    WriteOfficeXmlAlt($XML_BRIEF_OUTPUT_FILE, \@runs);
}

#print("Total run time: " . $totalExecutionTime . "\n") if( $optionCaseRunTimes );

foreach my $file ( @globalTempFiles )
{
    unlink $file if( defined( $file ) && -e $file );
}

exit();

#------------------------------------------------------------------------------------
# UnzipAndCopyFiles
#------------------------------------------------------------------------------------
sub UnzipAndCopyFiles
{
	my @files;
	system("rmdir ziptemp /s /q>NUL") if( -e "ziptemp" );
	
	# Unzip zips in current directory and one level of subdirectories. -> ATS results.
	GetAllFiles( ".", \@files, 1 );
	
	foreach my $file ( @files )
	{
		if( $file =~ m/\.zip/i )
		{
			my $fileName = GetPathFileName( $file );
			
			mkdir ("ziptemp");
			my $cmd = "unzip -o \"$file\" -d ziptemp\\$fileName >NUL";
			print("Unzipping $file\n") if( $optionShowMessages );
			system( $cmd );
		}
	}

	undef( @files );
	GetAllFiles( ".", \@files, -1 );

	# Copy files to current dir.

	my $currDir = cwd;
	
	foreach my $file ( @files )
	{
	    next if( -d $file );
	    
	    $file =~ s/\//\\/g;
	    
    	# Do nothing for files which are in current dir.
    	my $srcDir = GetPathDir( $file );
    	my $currpath = cwd;
    	$currpath =~ s/\//\\/g;
    	next if( $srcDir eq $currpath );
	    
	    my $filename = GetPathFileName( $file );
	    
	    # LOOP all testreport*.txt testscripter*.txt
	    # if file is testreport.txt
	    #   lastFolder = last folder from the path
	    #     LOOP all fusion*.txt
	    #       LOOP remove tailing text from lastFolder starting from last index of '.' until it matches with folder of fusion*.txt
	    #          pair fusion*.txt with testreport
	    
	    
		if( ( $filename =~ m/testreport/i || $filename =~ m/testscripter/i ) && $filename =~ m/\.txt/i )
		#if( ( $filename =~ m/$optionLogFileName/i || $filename =~ m/testreport/i || $filename =~ m/testscripter/i ) && $filename =~ m/\.txt/i )
		{
		    my $dst = "";
		    
		    if( $filename =~ m/testreport/i )
		    {
		        # Pair testreports and logs.
		        CopyTestReportWithLog( $file, \@files );
		    }
		    else
		    {
		        print("Copying file $file\n") if( $optionDebug );
		        # For other files we just need unique filename and copy them.
            	$dst = $filename;
            	
            	if( -e $filename )
            	{
                	# Separate file's name and extension.
                	my $name = "";
                	my $ext = "";
                	my $pos = index($filename, ".");
                	if( $pos != -1) 
                	{
                		$ext = substr( $filename, $pos );
                		$name = substr( $filename, 0, $pos );
                		
                		my $count = 0;
                		while( 1 )
                		{
                		    $dst = "$name" . "_" . $count . $ext;
                		    last if( ! -e "$dst" );
                		    $count++;
                		    if( $count > 1000 )
                		    {
                		        $dst = "";
                		        last;
                		    }
                		}
                	}
                }
    			push @globalTempFiles, $dst;
    			
    			print("Dest: $dst\n") if( $optionDebug );
    			
    			copy( $file, $dst ) or die "Could not copy '$file' to '$dst'\n";
		    }
		}
	}

	system("rmdir ziptemp /s /q>NUL") if( -e "ziptemp" );
}

sub CopyTestReportWithLog
{
    my ( $reportFileName, $refFiles ) = @_;
    
    print("\nTrying to pair: $reportFileName\n") if( $optionDebug );
    
    my $reportPath = GetPathDir( $reportFileName );
    
    my $logFileName = "";
    
#\ResultAndLogFiles_vod\22507.23325.1.4.25129-lab.net\TestReport.txt
#\ResultAndLogFiles_vod\22507.23325.1.4.25130-lab.net\Fusion.txt
#                       ^^^^^^^^^^^^^^^ matching part    
    # Find log file with about same path with the report.
    while( 1 )
    {    
        # Check the log files.
        foreach $file ( @$refFiles )
        {
            $file =~ s/\//\\/g;
            my $filename = GetPathFileName( $file );
            
            if( $filename =~ m/$optionLogFileName/i )
            {
                if( index( $file, $reportPath ) == 0 )
                {
                    $logFileName = $file;
                    
                    print("PAIRED: \n") if( $optionDebug );
                    print("reportPath: $reportPath\n") if( $optionDebug );
                    print("report: $reportFileName\n") if( $optionDebug );
                    print("log   : $logFileName\n") if( $optionDebug );
                    
                    print("Report log pair: $logFileName\n") if( $optionShowMessages && !$optionDebug );
                    last;
                }
            }
        }
        
        last if( $logFileName ne "" );
        
        # Remove all from last dot in the path.            
        my $pos = rindex( $reportPath, "." );
        last if( $pos == -1 );
        $reportPath = substr( $reportPath, 0, $pos );
        
        # The first 4 numbers might be same with multiple reports and logs. Ignore file if match is not found before.
        last if( rindex( $reportPath, "\\" ) == -1 );
        my $dotstr = substr( $reportPath, rindex( $reportPath, "\\" )+1 );
        last if( ! ( $dotstr =~ m/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/ ) );
        print( "DOT: $dotstr\n" ) if( $optionDebug );
    }

    if( $logFileName eq "" )
    {
        print("Could not find log file for: $reportFileName\n") if( $optionShowMessages );
    }
    
    my $dstReportFileName = "";
    my $dstReportLogName = "";

    # Find first available name for the report in current directory.
    my $fileNum = 0;

    my $filename = GetPathFileName( $reportFileName );
    
	# Separate file's name and extension.
	my $name = "";
	my $ext = "";

	my $pos = index($filename, ".");
	return if( $pos == -1);
	
	$ext = substr( $filename, $pos );
	$name = substr( $filename, 0, $pos );
	
	# Find free filename.
	while( 1 )
	{
	    $dstReportFileName = "$name" . "_" . $fileNum . $ext;
	    last if( ! -e "$dstReportFileName" );
	    $fileNum++;
	    if( $fileNum > 1000 )
	    {
	        die("Too many files to copy.");
	    }
	}
	
	if( $logFileName ne "" )
	{
    	# Get new name for the log with same numbering.
    	
    	$filename = GetPathFileName( $logFileName );
    	
        $pos = index($filename, ".");
    	return if( $pos == -1);
    	
    	$ext = substr( $filename, $pos );
    	$name = substr( $filename, 0, $pos );
    	
    	$dstLogFileName = "$name" . "_" . $fileNum . $ext;
    	die("Log filename already exists.") if( -e "$dstLogFileName" ); # Shouldn't happen.
    }
    
	# Copy the files.
	
    push @globalTempFiles, $dstReportFileName;
    push @globalTempFiles, $dstLogFileName;

	print("Copying $reportFileName\n") if( $optionShowMessages );
	print("Dest: $dstReportFileName\n") if( $optionShowMessages );
	
	copy( $reportFileName, $dstReportFileName ) or die "Could not copy '$reportFileName' to '$dstReportFileName'\n";	
	
	if( $logFileName ne "" )
	{	
	    print("Copying $logFileName\n") if( $optionShowMessages );
	    print("Dest: $dstLogFileName\n") if( $optionShowMessages );
	    copy( $logFileName, $dstLogFileName ) or die "Could not copy '$logFileName' to '$dstLogFileName'\n";	
    }
}

#------------------------------------------------------------------------------------
# ReadCaseList
#
#------------------------------------------------------------------------------------
sub ReadCaseList
{
    my ($refList, $filename) = @_;

	if( open(FILE_HANDLE, ".\\" . $filename) )
	{
		my @lines = <FILE_HANDLE>;
		close(FILE_HANDLE);
	    foreach $line (@lines)
	    {
	        my $caseId;

            if($line =~ m/^case /i)
            {
                if($line =~ m/^case ET([0-9]+) /i)
                {
                    $caseId = "ET" . $1;
                }
                else
                {
                    $caseId = substr($line, 4);
                }
                RemoveWhiteSpaces(\$caseId);
                push @$refList, $caseId;
            }
	    }
	}
}

#------------------------------------------------------------------------------------
# IsCaseInCaseList
#
#------------------------------------------------------------------------------------
sub IsCaseInCaseList
{
    my ($caseNameOrId) = @_;

     return 1 if(scalar(@caseList) <= 0);

    my $caseIdFromName = GetCaseIdFromName($caseNameOrId);

    foreach $caseId (@caseList)
    {
        if($caseId eq $caseNameOrId)
        {
            return 1;
        }
    }

    foreach $caseId (@caseList)
    {
        if($caseId eq $caseIdFromName)
        {
            return 1;
        }
    }

    return 0;
}

#------------------------------------------------------------------------------------
# FixExcelLogPaths
#
# Changes the paths on lines:
#<Cell ss:StyleID="s60" ss:HRef="C:\Documents and Settings\senbom\Desktop\testcase_logs\testcase_logs\ET17099_4371843802.txt"><Data>
# To:
#<Cell ss:StyleID="s60" ss:HRef="testcase_logs\ET17099_4371843802.txt"><Data>
#
# Because the absolute path does not work in Excel.
#
#------------------------------------------------------------------------------------
sub FixExcelLogPaths
{
	if( open(FILE_HANDLE, ".\\" . $optionFixFilename) )
	{
		my @lines = <FILE_HANDLE>;
		close(FILE_HANDLE);

		if(!open(FILE_HANDLE, ">" . $optionFixFilename) )
		{
			die("Could not write to file $file\n");
		}

		foreach my $line(@lines)
		{
			my $pos = index($line, "\\testcase_logs\\testcase_logs\\");
			if($pos != -1)
			{
				my $start = rindex($line, "\"", $pos);
				my $remstr = substr($line, $start+1, $pos-$start + length("\\testcase_logs") );

				$line = substr( $line, 0, index($line, $remstr) ) .
						   substr( $line, index($line, $remstr) + length($remstr) );

			}

			print FILE_HANDLE ($line);

		}
		close(FILE_HANDLE);

		print("Fixed paths in $optionFixFilename\n");
	}
	else
	{
	    die("Coult not open file $optionFixFilename\n");
	}
}

#------------------------------------------------------------------------------------
# CalculateStats
#------------------------------------------------------------------------------------
sub CalculateStats
{
	$summaryCaseCount = scalar( @cases );
	$summaryPassedCases = 0;
	$summaryFailedCases = 0;
	$summaryCrashedCases = 0;
	$summaryTimeoutCases = 0;
	$summaryPassRateTotal = 0;
	$summaryPassRateRun = 0;
	$summaryRunRate = 0;

	foreach $case(@cases)
	{
		if(defined(@{$case}[$CASE_STATUS]))
		{
			my $status = @{$case}[$CASE_STATUS];

			$summaryPassedCases++ if($status eq "PASSED");
			$summaryFailedCases++ if($status eq "FAILED");
			$summaryCrashedCases++ if($status eq "CRASHED");
		}
	}
	
	my $runCases = $summaryPassedCases + $summaryFailedCases + $summaryCrashedCases;
	
	$summaryPassRateTotal = $summaryPassedCases / $summaryCaseCount * 100;
	$summaryPassRateRun = $summaryPassedCases / $runCases * 100;
	$summaryRunRate = $runCases / $summaryCaseCount * 100;
}

#------------------------------------------------------------------------------------
# SortCases
#------------------------------------------------------------------------------------
sub SortCases()
{
	$aprio = 0;
	$bprio = 0;

	#print @{$a}[$CASE_STATUS] . " - " . $a . " vs " . $b . " - " . @{$b}[$CASE_STATUS] . "\n";

	if(@{$a}[$CASE_STATUS] eq "CRASHED") { $aprio = 5; }
	elsif(@{$a}[$CASE_STATUS] eq "FAILED") { $aprio = 4; }
	elsif(@{$a}[$CASE_STATUS] eq "PASSED") { $aprio = 3; }

	if(@{$b}[$CASE_STATUS] eq "CRASHED") { $bprio = 5; }
	elsif(@{$b}[$CASE_STATUS] eq "FAILED") { $bprio = 4; }
	elsif(@{$b}[$CASE_STATUS] eq "PASSED") { $bprio = 3; }

	if($aprio == $bprio)
	{
		return lc(@{$a}[$CASE_NAME]) cmp lc(@{$b}[$CASE_NAME]);
	}

	return $bprio cmp $aprio;
}


#------------------------------------------------------------------------------------
# ShowHelp
#------------------------------------------------------------------------------------
sub ShowHelp {

print <<USAGE_EOF;
testdoc.pl

Create folder to VaDo root folder for STIF results and copy this script and 
the results there. STIF CFG files are searched from . and .. from the script 
run folder. The STIF results can be either ATS results zips or multiple 
TestReport*.txt and fusion*.txt files as long as they have the same ending 
in the name. Script also parses the STIF testscripter logs it finds.

Options:
-i: STIF case will be included in the start of the case log
-s: cases will be sorted by status
-e: Shows extra information during the tool run
-html: Case logs are generated in html format instead of text
-logall: Logs are created for passed cases too.
-nologs: Logs are not processed.
-nosecuritytests: Security tests are not included in the reports.
-nolivetvttests: Live TV tests are not included in the reports.
-i: Test case from the CFG is included in the log file
-file <file>: Only formats defined log file into html
-runtimes: Result of the case will contain the case execution time in seconds.
-good: If case has passed once it will be marked as passed no matter how many 
 times it has failed.
-cfgsum: Prints summary info for cfgs: how many cases and how long the cfg did 
 take to execute.
-finalize
-fix if you save the file in Excel the log paths will come absolute and don't 
 work if moved to another directory. use this fix it.
-caselist <file>: Only reports the cases in caselist.txt, see genrerun.pl for 
 file format.
-logfile <file>: Sets filter for log filenames. Default is fusion.
-slogs: Reads STIF testscripter logs instead of custom logs.
These files will be generated:
	test_cases.xml
	test_cases_brief.xml
	test_cases_notdocumented.txt

Case specific log files are generated in testcase_logs directory and result 
file has links to them.

USAGE_EOF

	exit();

};

#------------------------------------------------------------------------------------
# ReadReportLogs
#
# Parameters:
#	$fileName
#	$refLogLines
#
# Reads log file of specific TestReport.
#
# The function has two different behaviours:
#
# Filenames for test report and log must match. For example
# if test report file is TestReport_XXX.txt then fusion_XXX.txt is read if found.
#
# If fileName is * then *fusion*.txt files will be read one by one and processed by function CheckCaseEntriesInLog()
#------------------------------------------------------------------------------------
sub ReadReportLogs
{
	my ($fileName, $refLogLines) = @_;

	return if($optionNoLogs || $optionPrintCfgSummaries);

	opendir(DIR, ".");
	my @filelist = sort(readdir(DIR));
	closedir(DIR);

	#default mask for logs
	my $filemask = "^$optionLogFileName\.TXT";

	#create file mask for logs if testreport.txt is in format: testreport_*.txt
	if(index($fileName, "_") != -1)
	{
		my $spos = index($fileName, "_");
		my $epos = rindex($fileName, ".");

		$filemask = substr($fileName, $spos, $epos - $spos);
		#print("filemask: $filemask\n");

		#$filemask = "$optionLogFileName" . $filemask . "[a-z\-0-9_]*\.txt"; # this finds $optionLogFileName_xxx*.txt
		$filemask = "$optionLogFileName" . $filemask . "\.txt"; # this finds only $optionLogFileName_xxx.txt
		#print("filemask: $filemask\n");
		#die();
	}

	my $processLogsHere = 0;

	if($fileName eq "*")
	{
		$processLogsHere = 1;
		$filemask = $optionLogFileName . "[a-z\-0-9_]*\.txt"
	}

	my $i;

	#read the files into refLogLines array
	foreach $file(@filelist)
	{
		#if($file =~ m/^$optionLogFileName[a-z0-9_]+\.TXT$/i or $file =~ m/^$optionLogFileName\.TXT$/i )
		if($file =~ m/$filemask/i )
		{
			print("Reading log file: " . $file . ".");

			if( open(FILE_HANDLE, ".\\" . $file) )
			{
				my @tempArray = <FILE_HANDLE>;
				close(FILE_HANDLE);

				FormatFasttraceTraces(\@tempArray);

				if($processLogsHere)
				{
					FindAndMarkCaseEntriesInLog(\@tempArray, \@cases);

					CheckCaseEntriesInLog(\@tempArray);
				}
				else
				{
					while(scalar(@tempArray) > 0)
					{
						push @$refLogLines, (shift(@tempArray));
					}
				}
			}
		}
	}

	FindAndMarkCaseEntriesInLog($refLogLines, \@cases);
}

#------------------------------------------------------------------------------------
# GetReportLogFileNames
#
# Parameters:
#	$fileName
#	$refLogFiles
#
# Gets log filenames for specific testreport.
#
# The function has two different behaviours:
#
# Filenames for test report and log must match. For example
# if test report file is TestReport_XXX.txt then $optionLogFileName_XXX.txt is read if found.
#
# If fileName is * then *$optionLogFileName*.txt files will be read one by one and processed by function CheckCaseEntriesInLog()
#------------------------------------------------------------------------------------
sub GetReportLogFileNames
{
	my ($fileName, $refLogFiles) = @_;

	return if($optionNoLogs || $optionPrintCfgSummaries);

	opendir(DIR, ".");
	my @filelist = sort(readdir(DIR));
	closedir(DIR);

	#default mask for logs
	my $filemask = "^$optionLogFileName\.TXT";

	#create file mask for logs if testreport.txt is in format: testreport_*.txt
	if(index($fileName, "_") != -1)
	{
		my $spos = index($fileName, "_");
		my $epos = rindex($fileName, ".");

		$filemask = substr($fileName, $spos, $epos - $spos);
		$filemask = "$optionLogFileName" . $filemask . "\.txt"; # this finds only $optionLogFileName_xxx.txt
	}

	if($fileName eq "*")
	{
		$filemask = $optionLogFileName . "[a-z0-9_]*\.txt"
	}

	foreach $file(@filelist)
	{
		if($file =~ m/$filemask/i )
		{
			push @$refLogFiles, $file;
		}
	}
}

#------------------------------------------------------------------------------------
# FindAndMarkCaseEntriesInLog
#
# Parameters:
#	$refLogLines
#
# Searches for case entries in the log and if found then marks the case in @cases array
#------------------------------------------------------------------------------------
sub FindAndMarkCaseEntriesInLog
{
	my ($refLogLines, $refCases) = @_;

	my $line;

	print(" - Searching case start entries from log\n") if($optionShowMessages);

    my $startLineIndex = 0;

	# scan the log thru and mark if there's log start entries
	for( my $i = 0; $i < scalar(@$refLogLines); $i++ )
	{
	    my $line = @$refLogLines[$i];

		my $caseStartInLog = 0;

		my $caseId = "";

		if($line =~ m/>>> Case start:/i)
		{
			$startLineIndex = $i;
			$caseStartInLog = 1;
			$caseId = substr($line, index($line, ">>> Case start:") + length(">>> Case start:"));
			print("Found case start: $caseId\n") if($optionShowMessages);
		}

		if($caseStartInLog)
		{
			RemoveWhiteSpaces(\$caseId);

			my $refCase = GetCase($caseId, $refCases);

			if(defined($refCase))
			{
				@$refCase[$CASE_CHECK_RESULT_LOG_FILE] = 1;
				@$refCase[$CASE_ENTRY_LOG_START] = $startLineIndex;
			}
			else
			{
				print("Case start in log found: $caseId\n") if($optionShowMessages);
				print("ERROR! The start in log found but case is not found from report or cfg.\n");
			}
		}
	}
}

#------------------------------------------------------------------------------------
# FormatFasttraceTraces
#
# Parameters:
#	$refLogArray
#------------------------------------------------------------------------------------
sub FormatFasttraceTraces
{
	my ($refLogArray) = @_;

	my $ftDebug = 0;

	# strip fasttrace logging text from the start of lines
	#[13:58:17.234] sti: MCU_ASCII_PRINTF; channel:0xE0; msg:$optionLogFileName.TXT 09/10/2006¿1:57:08¿C$optionLogFileName::CheckIsPluginRunning

	my $stripFasttrace = 0;
	# find first occurance of Musti message, remove anything before that
	my $i;

	for($i= 0; $i<100; $i++)
	{
		if(defined(@$refLogArray[$i]))
		{
			if(@$refLogArray[$i] =~ m/MCU_ASCII_PRINTF/i)
			{
				$stripFasttrace = 1;
				last;
			}
		}
	}

	print("fasttrace: end $i, strip: $stripFasttrace\n") if($ftDebug);

	#remove the fasttrace specific lines
	print("fasttrace: lines before: " . scalar(@$refLogArray) . "\n") if($ftDebug);

	splice(@$refLogArray, 0, $i) if($stripFasttrace);

	return if(!$stripFasttrace);

	print("fasttrace: lines " . scalar(@$refLogArray) . "\n") if($ftDebug);

	#remove the fasttrace line startings and change format of STIF messages

	for($i = 0; $i<scalar(@$refLogArray); $i++)
	{
		#before: [14:38:40.641] sti: MCU_ASCII_PRINTF; channel:0xE0; msg:TestCase [ET1024 Sort IapList when it has no IAPs] finished with verdict[0]
		#after:  [14:38:40.641] sti: MCU_ASCII_PRINTF; channel:0xE0; msg:$optionLogFileName.TXT 18/10/2006¿2:37:37¿TestCase [ET1024 Sort IapList when it has no IAPs] finished with verdict[0]
		if(@$refLogArray[$i] =~ m/TestCase \[([[a-z0-9_]+) ($regexpCaseName)\] finished with verdict\[[-]?([0-9]+)/i)
		{
			#die(@$refLogArray[$i]);

			my $startStr = substr(@$refLogArray[$i], 0, index(@$refLogArray[$i], "TestCase"));
			my $endStr = substr(@$refLogArray[$i], index(@$refLogArray[$i], "TestCase"));

			my $timeStr = FasttraceLogFindIptvTraceTime($refLogArray, $i);

			@$refLogArray[$i] = $startStr . "$optionLogFileName.TXT " . $timeStr . "\t" . $endStr;

			print("fasttrace: " . @$refLogArray[$i] . "\n") if($ftDebug);

			#print("\n\n" . $startStr . "'\n$optionLogFileName.TXT \n" . $timeStr . "'\n" . $endStr . "'\n" );
			#die();
		}

		#change the lines where is STIF message saying starting testcase to "$optionLogFileName.TXT <TIME> >>> Case start: <CASEID>" format, otherwise it will be not be recognized later
		if(@$refLogArray[$i] =~ m/Starting testcase \[([[a-z0-9_]+) ($regexpCaseName)\]/i)
		{
			print("debug: " . @$refLogArray[$i] . "\n");
			@$refLogArray[$i] = substr(@$refLogArray[$i], 0, index(@$refLogArray[$i], "Starting testcase"));

			my $timeStr = FasttraceLogFindIptvTraceTime($refLogArray, $i);

			@$refLogArray[$i] .= "$optionLogFileName.TXT $timeStr\t>>> Case start: $1" . "\r\n";

			print("fasttrace: '" . @$refLogArray[$i] . "'\n") if($ftDebug);

			#@$refLogArray[$i] = "[14:38:37.953] sti: MCU_ASCII_PRINTF; channel:0xE0; msg:$optionLogFileName.TXT 18/10/2006\t2:37:34\t>>> Case start: $1";
		}

		if(@$refLogArray[$i] =~ m/channel\:[0-9a-z]+; msg:$optionLogFileName.TXT [0-9]+\/[0-9]+\/[0-9]+/i)
		{
			@$refLogArray[$i] = substr(@$refLogArray[$i], index(@$refLogArray[$i], "msg:$optionLogFileName.TXT") + length("msg:$optionLogFileName.TXT") + 1);

			#replace fasttrace tab chars
			@$refLogArray[$i] =~ s/¿/\t/g;
			#print(@$refLogArray[$i]);

		}
		else
		{
			# if there's no match then this is not a trace for $optionLogFileName
			splice(@$refLogArray, $i, 1);
			$i--;
		}
	}
}


#------------------------------------------------------------------------------------
# FastTraceLogFindIptvTraceTime
#
# Parameters:
#	$refLines: reference to array of the log line
# 	$startLine: line where to start looking for
#
# Finds next time stamp of Iptvengine from Fasttrace log
#------------------------------------------------------------------------------------
sub FasttraceLogFindIptvTraceTime
{
	my ($refLines, $startLine) = @_;

	#find next trace of iptvengine and get the time and date
	my $timeStr = "";
	for(my $e = $startLine+1; $e < scalar(@$refLines); $e++)
	{
		if(@$refLines[$e] =~m/msg:$optionLogFileName.TXT/)
		{
			my $line = @$refLines[$e];
			#remove the fasttrace trace from line start, we don't want it's time
			$line = substr($line, index($line, "msg:$optionLogFileName.TXT"));

			if($line =~ m/([0-9]+\/[0-9]+\/[0-9]+)/i)
			{
				$timeStr .= $1 . "\t";
			}

			if($line =~ m/([0-9]+:[0-9]+:[0-9]+)/i)
			{
				$timeStr .= $1;
			}
			last if($timeStr ne "");
		}
	}

	return $timeStr;
}

#------------------------------------------------------------------------------------
# ReportNotDocumentedCases
#
# Parameters:
#	$file
#
# Writes the @notDocumentedCases array into a file
#------------------------------------------------------------------------------------
sub ReportNotDocumentedCases
{
	my ($file) = @_;

	if(scalar(@notDocumentedCases) > 0)
	{
		if(!open(FILE_HANDLE, ">" . $file) )
		{
			print("ERROR! Could not open file '" . $file . "'\n");
		} else {
			print FILE_HANDLE ( @notDocumentedCases );
			close(FILE_HANDLE);
			print("Report " . $NOT_DOCUMENTED_CASES_FILE . " written.\n");
		}
	} else
	{
		print("All cases are documented.");
	}
}

#------------------------------------------------------------------------------------
# ReadTestReports
#
# Reads TestReportXX.txt files from the current directory and updates the cases with the results.
# Reads also logs for the report and creates case specific logs.
#------------------------------------------------------------------------------------
sub ReadTestReports
{
	# Read filelist of current directory
	opendir(DIR, ".");
	my @filelist = sort(readdir(DIR));
	closedir(DIR);

	my $readSomething = 0;

    my @testScripterLogLines;
    ReadTestScripterLogs( \@testScripterLogLines );
    
    # Read reports and logs in the current directory
	foreach $file(@filelist)
	{
		next if( -d $file or $file eq "." or $file eq "..");

        # Read results STIF testreport
		if($file =~ m/^TestReport[a-z\-0-9_]+\.txt$/i or $file =~ m/^TestReport\.txt$/i )
		{
			if($optionShowMessages) { print("***************************\n"); };
			print("Report file: " . $file . "\n");

			my @logFiles;
			my @caseResults;

			ReadTestRunInfoFromStifReport( $file, \@caseResults, \@logFiles );
			ParseResultsAndLogs( \@caseResults, \@logFiles, \@testScripterLogLines );

			undef(@logFiles);
			undef(@caseResults);

			$readSomething++;
		}
	}

	return if($optionPrintCfgSummaries);

	# No testreports found. Read all logs and parse them.
	if($readSomething == 0)
	{
		print("\nNo test reports found in the current directory. Trying to read all the logs.\n");

		my @logFileLines;

		ReadReportLogs("*", \@logFileLines);
		
		if( scalar( @logFileLines ) > 0 )
		{
			$readSomething = 1;
		}

		undef(@logFileLines);
	}

	return $readSomething;
}

#------------------------------------------------------------------------------------
# ReadTestReportsAlt
#
# Every test report is one run and those should have as much same cases as possible.
#------------------------------------------------------------------------------------
sub ReadTestReportsAlt
{
    my ($refRuns) = @_;

	# Read filelist of current directory
	opendir(DIR, ".");
	my @filelist = sort(readdir(DIR));
	closedir(DIR);

    my @runs;

    # Read reports and logs in the current directory
	foreach $file(@filelist)
	{
		if($file eq "." or $file eq "..") {next};

        # Read results STIF testreport
		if($file =~ m/^TestReport[a-z0-9_]+\.txt$/i or $file =~ m/^TestReport\.txt$/i )
		{
			if($optionShowMessages) { print("***************************\n"); };
			print("Report file: " . $file . "\n");

            # Store report filename, run date and then cases into array

        	# Read date from report
        	if( !open(FILE_HANDLE, $file) ) {
        		print("ERROR! Could not open file '" . $file . "'\n");
        		return;
        	}
        	my @array = <FILE_HANDLE>;
        	close(FILE_HANDLE);

        	#Monday 25th August 2008
        	my @pieces = split(' ', $array[1]);

            $pieces[1] =~ s/st//;
            $pieces[1] =~ s/nd//;
            $pieces[1] =~ s/rd//;
            $pieces[1] =~ s/th//;

            undef(@array);

            my @runInfo;
			$runInfo[0] = $file;
			$runInfo[1] = substr( $pieces[0], 0, 3 ) . " " . $pieces[1] . " " . substr( $pieces[2], 0, 3 );

			my @runResults;
			my @logFiles;
			ReadTestRunInfoFromStifReport($file, \@runResults, \@logFiles );
            $runInfo[2] = \@runResults;

	        push @$refRuns, \@runInfo;
		}
	}
}

#------------------------------------------------------------------------------------
# ReadTestScripterLogs
#------------------------------------------------------------------------------------
sub ReadTestScripterLogs
{
    my ( $refLogLines ) = @_;
    
    return if($optionNoLogs || $optionPrintCfgSummaries);
    
	opendir(DIR, ".");
	my @filelist = sort(readdir(DIR));
	closedir(DIR);
	
	foreach $file(@filelist)
	{
		if($file =~ m/^testscripter[a-z0-9_]+.txt/i )
		{
		    print("Reading scripter log: $file\n") if( $optionDebug );
		    if( open(FILE_HANDLE, $file) )
    		{
    			my @tempArray = <FILE_HANDLE>;
    			close(FILE_HANDLE);
    
    			while(scalar(@tempArray) > 0)
    			{
    				push @$refLogLines, ( shift( @tempArray ) );
    			}
    			undef(@tempArray);
    		}
    		else
    		{
    		    print("ERROR: Could not open the log file: $file!\n");
    		}			
		}
		else
		{
		    print("Not a scripter log: $file\n") if( $optionDebug );
		}
	}
}


#------------------------------------------------------------------------------------
# ReadTestReportDates
#
# Reads the date from each testreport in current directory
#------------------------------------------------------------------------------------
sub ReadTestReportDates
{
    my ($refDates) = @_;

	# Read filelist of current directory
	opendir(DIR, ".");
	my @filelist = sort(readdir(DIR));
	closedir(DIR);

    my @runs;

    # Read reports and logs in the current directory
	foreach $file(@filelist)
	{
		if($file eq "." or $file eq "..") {next};

        # Read results STIF testreport
		if($file =~ m/^TestReport[a-z0-9_]+\.txt$/i or $file =~ m/^TestReport\.txt$/i )
		{
			my @fileDate;
			$fileDate[0] = $file;

        	if( !open(FILE_HANDLE, $file) ) {
        		print("ERROR! Could not open file '" . $file . "'\n");
        		return;
        	}
        	my @array = <FILE_HANDLE>;
        	close(FILE_HANDLE);

        	#Monday 25th August 2008
        	my @pieces = split(' ', $array[1]);

            $pieces[1] =~ s/st//;
            $pieces[1] =~ s/nd//;
            $pieces[1] =~ s/rd//;
            $pieces[1] =~ s/th//;

        	$fileDate[1] = substr( $pieces[0], 0, 3 ) . " " . $pieces[1] . " " . substr( $pieces[2], 0, 3 );

            undef(@array);

	        push @$refDates, \@fileDate;
		}
	}
}

#------------------------------------------------------------------------------------
# ParseTimeFromLine
#
#------------------------------------------------------------------------------------
sub ParseTimeFromLine
{
    my ($line) = @_;

    my $timestr = "";

    if($line =~ m/([0-9]+)(:[0-9]+:[0-9]+\,[0-9]*)/i || $line =~ m/([0-9]+)(:[0-9]+:[0-9]+\.[0-9]*)/i)
    {
        $timestr = "" . $1 . $2;
        if($1 > 12)
        {
            $timestr = "" . ($1-12) . $2;
        }
    }

    return $timestr;
}

#------------------------------------------------------------------------------------
# ReadTestRunInfoFromStifReport
#
# Parameters:
#	$file, the testreport
#   $refCaseResults, results for all cases of the testreport
#   $refLogFiles, filenames for the log files of the testreport
#------------------------------------------------------------------------------------
sub ReadTestRunInfoFromStifReport
{
	my ($file, $refCaseResults, $refLogFiles) = @_;

	if( !open(FILE_HANDLE, $file) ) {
		print("ERROR! Could not open file '" . $file . "'\n");
		return;
	}
	my @array = <FILE_HANDLE>;
	close(FILE_HANDLE);

    # Get log files for the report
    GetReportLogFileNames($file, $refLogFiles);

	my $index = 0;
	my $line = "";

	for(my $i = 0; $i < scalar(@array); $i++)
	{
		$line = $array[$i];
		RemoveWhiteSpaces(\$line);

#[testscripter_iptvservicetest][C:\TestFramework\IptvServiceTest.cfg][10] Title:[ET9009 Set id]
#[testscripter][c:\testframework\iptvvoddlapitest2.cfg][2] Title:[ET12100 Purchase]
#	StartTime: 8:54:23.5565 PM, EndTime: 8:54:24.3471 PM
#	Result: 0 [] ==> PASSED
#	Info: xxx

		# found a start of a result
		#[1] Title:[ET1000 Add multiple Iaps]
		my $cfgFile = "";

		if($line =~ m/([a-z_0-9.]+)\]\[[0-9]+\][ ]+Title:\[/i)
		{
			$cfgFile = $1;
			if($optionShowMessages) { print(" - Cfg: $cfgFile\n"); };
			
			for( my $e = 0; $e < scalar( @gCfgFiles ); $e++ )
			{
			    if( $gCfgFiles[$e] =~ m/$cfgFile/i )
			    {
			        my $caseCount = ParseCfg( $gCfgFiles[$e] );
			        $gCfgFiles[$e] = ""; # We don't want to read it again.
			    }
			}
		}

		if($line =~ m/\[[0-9]+\][ ]+Title:\[($regexpCaseName)\]$/i)
		{
			if($optionShowMessages) { print(" - Case: " . $1 . "\n"); };

			#get the case name
			my $caseName = $1;
			my $caseId = GetCaseIdFromName($caseName);
			my $caseRunTime = CountCaseRunTime($array[$i+1]);

            # Save case report lines for later use
            my $caseLine1 = $array[$i];
            my $caseLine2 = $array[$i+1];
            my $caseLine3 = $array[$i+2];

			# Read the case result

			#	StartTime: 3:54:10.1670 PM, EndTime: 3:54:23.8226 PM
			$line = $array[$i+2];
			RemoveWhiteSpaces(\$line);

			my $info = "";
			my $result = "N/A";
			my $status = "$caseDefaultStatus";
			my $reason = "";

			# Result: 0 [] ==> PASSED / something
			if($line =~ m/^Result:[ ]([-]*[0-9]+)[ ]\[[\w]*\][ ]==>[ ]([\w ]+)$/i)
			{
				$result = $1;
				$status = $2;
			}
            # Result: -2 [CTestRunner::RunError [CTestRunner::ExecuteCommandL returned error]] ==> FAILED
			# Result: -2 [CTestRunner::ExecuteCommandL returned error] ==> FAILED
			elsif($line =~ m/^Result:[ ]([-]*[0-9]+)[ ]\[([\w: ]+)\][ ]==>[ ]([\w]+)$/i or
			      $line =~ m/^Result:[ ]([-]*[0-9]+)[ ]\[[\w: ]+\[([\w: ]+)\]\][ ]==>[ ]([\w]+)$/i )
			{
				$result = $1;
				$status = $3;
				$reason = $2;
			}

			#CaseExecutionResult: Test case execution fails with -15
			elsif($line =~ m/^CaseExecutionResult:[ ]Test case execution fails with ([-]*[0-9]+)$/i)
			{
				$result = $1;
				$status = "FAILED";
				$reason = "Test case execution failed.";
			}

			# CaseExecutionResult: Leave during case: with -4
			elsif($line =~ m/^CaseExecutionResult:[ ]Leave during case: with ([-]*[0-9]+)$/i)
			{
				$result = $1;
				$status = "FAILED";
				$reason = "Leave during case";
			}
			#CaseExecutionResult: Crash reason:Error in test ca with 69
			#CaseExecutionResult: Crash reason:IptvEngineServer with 13
			elsif($line =~ m/^CaseExecutionResult:[ ]Crash reason:([\w_ \-]+)[ ]with[ ]([-]*[0-9]+)$/i)
			{
				$result = $2;
				$status = "CRASHED";
				$reason = $1;
			}

			# Result: -2 [Crash reason:KERN-EXEC] ==> FAILED
			elsif($line =~ m/^Result:[ ]([-]*[0-9]+)[ ]\[Crash reason:([\w\-:\. ]+)\] ==> ([\w]+)/i)
			{
				$result = $1;
				$status = "CRASHED";
				$reason = $2;
			}

			# CaseExecutionResult: TestModule loading fails, cannot connect to the TestModule with -2
			elsif($line =~ m/^CaseExecutionResult: TestModule loading fails, cannot connect to the TestModule with ([-]*[0-9]+)/i)
			{
				$result = $1;
				$status = "FAILED";
				$reason = "Test module loading failed.";
			}
			else
			{
				print("Error while parsing case result line: " . $line . "\n");
			}

			$line = $array[$i+3];
			RemoveWhiteSpaces(\$line);

			#	Info: xxx
			if($line =~ m/^Info:/i)
			{
				$info = substr($line, 5) . " / ";
				RemoveWhiteSpaces(\$info);
				$info .= " ";
			}

            my @caseResult;

            $caseResult[$CASE_CFG_FILE] = $cfgFile;
            $caseResult[$CASE_NAME] = $caseName;
            $caseResult[$CASE_ID] = $caseId;
            $caseResult[$CASE_RUN_TIME_SECONDS] = $caseRunTime;
        	$caseResult[$CASE_NOTE] = $info;
        	$caseResult[$CASE_RESULT] = $result;
        	$caseResult[$CASE_STATUS] = $status;
        	$caseResult[$CASE_REASON] = $reason;
        	$caseResult[$CASE_REPORTLINE1] = $caseLine1;
        	$caseResult[$CASE_REPORTLINE2] = $caseLine2;
        	$caseResult[$CASE_REPORTLINE3] = $caseLine3;

            push @$refCaseResults, \@caseResult;
		}
	}
}

#------------------------------------------------------------------------------------
# ParseResultsAndLogs
#
# Parameters:
#   $refCaseResults
#	$refLogFiles
#   $refTestScripterLogLines
#------------------------------------------------------------------------------------
sub ParseResultsAndLogs
{
	my ($refCaseResults, $refLogFiles, $refTestScripterLogLines) = @_;

    my @logLines;

    # Read log files
	foreach $file (@$refLogFiles)
	{
        $file =~ s/\//\\/g;

    	print("Reading log file: " . $file . " .. ");

		if( open(FILE_HANDLE, $file) )
		{
			my @tempArray = <FILE_HANDLE>;
			close(FILE_HANDLE);

			FormatFasttraceTraces(\@tempArray);
			print " .. ";

			while(scalar(@tempArray) > 0)
			{
				push @logLines, (shift(@tempArray));
			}
			print " done.\n";

			undef(@tempArray);
		}
		else
		{
		    print("ERROR: Could not open the log file: $file!\n");
		}
	}
	
	FindAndMarkCaseEntriesInLog( \@logLines, $refCaseResults );

    my @caseSpecificLogs;

    foreach $refCaseResult (@$refCaseResults)
    {
        my $cfgFile = @$refCaseResult[$CASE_CFG_FILE];
        my $caseName = @$refCaseResult[$CASE_NAME];
        my $caseId = @$refCaseResult[$CASE_ID];
        my $caseRunTime = @$refCaseResult[$CASE_RUN_TIME_SECONDS];
    	my $info = @$refCaseResult[$CASE_NOTE];
    	my $result = @$refCaseResult[$CASE_RESULT];
    	my $status = @$refCaseResult[$CASE_STATUS];
    	my $reason = @$refCaseResult[$CASE_REASON];
    	my $reportLine1 = @$refCaseResult[$CASE_REPORTLINE1];
    	my $reportLine2 = @$refCaseResult[$CASE_REPORTLINE2];
    	my $reportLine3 = @$refCaseResult[$CASE_REPORTLINE3];

        if($optionShowMessages) { print(" - Case: " . $caseName . "\n"); };

		# Create case specific log into the log directory
		my $caseLogFile = GetCaseField($caseId, $CASE_LOG_FILE);
		my $caseScripterLogFile = GetCaseField($caseId, $CASE_LOG_FILE_SCRIPTER);
        my $refCaseDesc = GetCaseDesc($caseId);

        $caseLogFile = GetFileNameForCaseLog(  $reportLine1, $reportLine2, $reportLine3 );
        $caseScripterLogFile = GetFileNameForCaseLog(  $reportLine1, $reportLine2, $reportLine3, "_scripter" );

        if( -e $caseLogFile )
        {
            unlink ( $caseLogFile );
        }

        if( -e $caseScripterLogFile )
        {
            unlink ( $caseScripterLogFile );
        }

        my @logInfo;
        $logInfo[0] = $caseLogFile;
        if( defined( @$refCaseResult[$CASE_CHECK_RESULT_LOG_FILE] ) )
        {
            # Case start entry trace was found from log.
            $logInfo[1] = @$refCaseResult[$CASE_ENTRY_LOG_START];
        }
        else
        {
            $logInfo[1] = -1;
        }
        $logInfo[2] = $reportLine1;
        $logInfo[3] = $reportLine2;
        $logInfo[4] = $reportLine3;
        $logInfo[5] = $refCaseDesc;
        $logInfo[6] = $caseScripterLogFile;
        push @caseSpecificLogs, \@logInfo;

		# Update case
		my $refCase = GetCase($caseId, \@cases);
		if(!defined($refCase))
		{
			$refCase = GetCaseByNameOnly($caseName);
		}

		if(defined($refCase))
		{
			UpdateCase($refCase, $caseLogFile, $caseScripterLogFile, $result, $status, $info, $reason, $caseRunTime);
		}
		else
		{
		    # Case doesn't exist yet, add it.		    
			my @case;
			$case[$CASE_NAME] = $caseName;
			$case[$CASE_ID] = $caseId;
			$case[$CASE_RUN_TIMES] = 0;
			$case[$CASE_CRASHED] = 0;
			$case[$CASE_FAILED] = 0;
			$case[$CASE_PASSED] = 0;
			$case[$CASE_STATUS] = "$caseDefaultStatus";
			$case[$CASE_PURPOSE] = "N/A";
			$case[$CASE_MEANS] = "N/A";
			$case[$CASE_REQUIRED_SETTINGS] = "N/A";
			$case[$CASE_RELATED_REQUIREMENTS] = "N/A";
			$case[$CASE_VERIFICATION] = "N/A";
			$case[$CASE_NOTE] = "N/A";
			$case[$CASE_REASON] = "";
			$case[$CASE_RESULT] = "";
			$case[$CASE_LOG_FILE] = "";
			$case[$CASE_LOG_FILE_SCRIPTER] = "";
			$case[$CASE_CHECK_RESULT_LOG_FILE] = 0;
			$case[$CASE_CFG_FILE] = $cfgFile;
			$case[$CASE_RUN_TIME_SECONDS] = 0;

			$refCase = GetCaseByNameOnly($caseName);

			UpdateCase(\@case, $caseLogFile, $caseScripterLogFile, $result, $status, $info, $reason, $caseRunTime);

            # Insert case after other cases from same CFG, if any.

            my $indexToInsert = -1;
            
            for( my $i = 0; $i < scalar(@cases); $i++ )
        	{
        		my $case = $cases[$i];
        		
        		if( defined(@$case[$CASE_CFG_FILE]) )
		        {
		            if( @$case[$CASE_CFG_FILE] eq $cfgFile )
		            {
		                $indexToInsert = $i;
		            }
		        }
		    }
		    
		    if( $indexToInsert == -1 )
		    {
		        push @cases, [ @case ];
		    }
		    else
		    {
		        splice @cases, $indexToInsert+1, 0, [ @case ];
		    }
		}
    }

    my $caseCount = scalar( @$refCaseResults );

    my @testScripterLogCaseLocations;
    PrepareTestScripterLogs( $refTestScripterLogLines, \@testScripterLogCaseLocations );
    WriteCaseSpecificScripterLogs( \@caseSpecificLogs, $refTestScripterLogLines, \@testScripterLogCaseLocations );
    WriteCaseSpecificLogs( \@caseSpecificLogs, $caseCount, \@logLines );    

	if($caseCount >= 10 && $optionShowMessages == 0)
	{
	     print("\n"); #line break for the progress bar
	}
	elsif($optionShowMessages == 0)
	{
	    print("##########\n"); # fake it
	}

	undef(@logLines);
}

#------------------------------------------------------------------------------------
# WriteCaseSpecificLogs
#
# Parameters:
#   $refCaseSpecificLogs 
#	$caseCount
#   $refLogLines
#------------------------------------------------------------------------------------
sub WriteCaseSpecificLogs
{
    my ($refCaseSpecificLogs, $caseCount, $refLogLines ) = @_;

    my $caseLogProgress = 0;

    foreach my $refLogInfo ( @$refCaseSpecificLogs )
    {
        #@logInfo[1] = @$refCaseResult[$CASE_ENTRY_LOG_START];

        my $caseLogFile = @$refLogInfo[0];
        my $reportLine1 = @$refLogInfo[2];
        my $reportLine2 = @$refLogInfo[3];
        my $reportLine3 = @$refLogInfo[4];
        my $refCaseDesc = @$refLogInfo[5];

        my $logWritten = 0;
        if( @$refLogInfo[1] != -1 )
        {
            # Case start entry trace found from log files.
            $logWritten = WriteCaseLogFromEntry($caseLogFile, $refLogLines, @$refLogInfo[1], $reportLine1, $reportLine2, $reportLine3);
        }

        if( !$logWritten )
        {
		    # Use case start and end times to write case specific log.
		    WriteCaseLog($caseLogFile, $refLogLines, $refCaseDesc, $reportLine1, $reportLine2, $reportLine3);
		}

		# Show simple progress bar
		if($caseCount >= 10 && $optionShowMessages == 0)
		{
			$caseLogProgress++;
			if($caseLogProgress > $caseCount/10)
			{
				$caseLogProgress = 0;
				print("#");
			}
		}
    }

	if($caseCount >= 10 && $optionShowMessages == 0)
	{
	     print("\n"); #line break for the progress bar
	}
	elsif($optionShowMessages == 0)
	{
	    print("##########\n"); # fake it
	}   
}

#------------------------------------------------------------------------------------
# PrepareTestScripterLogs
#
# Parameters:
#	$refTestScripterLogLines
#   $refTestScripterLogCaseLocations
#------------------------------------------------------------------------------------
sub PrepareTestScripterLogs
{
    my ($refTestScripterLogLines, $refTestScripterLogCaseLocations ) = @_;

    for( my $i = 0; $i < scalar(@$refTestScripterLogLines); $i++ )
    {
        my $line = @$refTestScripterLogLines[$i];
        
        if( $line =~ m/RunTest:/ )
        {
            push @$refTestScripterLogCaseLocations, ( $i );
        }
    }
}

#------------------------------------------------------------------------------------
# WriteCaseSpecificScripterLogs
#
# Parameters:
#	$refLogFiles
#   $refCaseResults
#   $refTestScripterLogCaseLocations
#------------------------------------------------------------------------------------
sub WriteCaseSpecificScripterLogs
{
    my ($refCaseSpecificLogs, $refScripterLogLines, $refTestScripterLogCaseLocations ) = @_;

    foreach my $refLogInfo ( @$refCaseSpecificLogs )
    {        
        my $caseLogFile = @$refLogInfo[6];
        my $reportLine1 = @$refLogInfo[2];
        my $reportLine2 = @$refLogInfo[3];
        my $reportLine3 = @$refLogInfo[4];
        my $refCaseDesc = @$refLogInfo[5];

        WriteCaseLogFromTestScripterLogs( $caseLogFile, $refScripterLogLines, $refTestScripterLogCaseLocations, $refCaseDesc, $reportLine1, $reportLine2, $reportLine3);
    }
}

#------------------------------------------------------------------------------------
# WriteCaseLogFromTestScripterLogs
#
#------------------------------------------------------------------------------------
sub WriteCaseLogFromTestScripterLogs
{ 
    my ( $caseLogFile, $refLogLines, $refTestScripterLogCaseLocations, $refCaseDesc, $line1, $line2, $line3 ) = @_;

    print("### WriteCaseLogFromTestScripterLogs") if( $optionDebug );

	# Don't generate log files if we only print summary
	if($optionPrintCfgSummaries)
	{
		return;
	}

	RemoveWhiteSpaces(\$line1);
	RemoveWhiteSpaces(\$line2);
	RemoveWhiteSpaces(\$line3);

	my $lineBreak = "\n";
	$lineBreak = "<br>\n" if($optionHtml);

	my $caseName = "";

	if($line1 =~ m/\[[0-9]+\][ ]+Title:\[([a-z0-9]+$regexpCaseName)\]$/i)
	{
		#"' ultraedit
		$caseName = $1;
		print(" Writing scripter log for: $caseName.\n") if($optionShowMessages);
	}
	else
	{
	    return;
	}

	# Write header for case

	my @writeArray;

	# split the first line
	push @writeArray, ( "<hr>" ) if($optionHtml);
	push @writeArray, ( substr($line1, 0, index($line1, "Title:")) . $lineBreak );
	push @writeArray, ( substr($line1, index($line1, "Title:")) . $lineBreak );
	my $title = substr($line1, index($line1, "Title:"));

	#($line1 . "\n");
	push @writeArray, ($line2 . $lineBreak);
	push @writeArray, ($line3 . $lineBreak);
	push @writeArray, ("\n");
	push @writeArray, ( "<hr>" ) if($optionHtml);

	# Include the script for the case in the file?

	if($optionCaseIncludedInLog)
	{
		foreach $linexxx (@{$refCaseDesc})
		{
			push @writeArray, ("$linexxx");
			push @writeArray, ($lineBreak) if($optionHtml);
		}
		push @writeArray, ( "<hr>" ) if($optionHtml);
		push @writeArray, ("\n");
	}
	
	# Create log directory

	if ( !(-e "testcase_logs") )
	{
  		mkdir("testcase_logs");
	}

	if ( !(-e "$caseLogOutDir") )
	{
		mkdir($caseLogOutDir, 0755);
	}

    # Find start and end lines for the case.
    my $startLine = -1;
    my $endLine = -1;

    my $caseNameRegexp = $caseName;
    $caseNameRegexp =~s/\)/\\\)/;
    $caseNameRegexp =~s/\(/\\\(/;

    # Try to find case start from cached locations.
    foreach my $lineNum ( @$refTestScripterLogCaseLocations )
    {
        if( @$refLogLines[$lineNum] =~ m/RunTest: $caseNameRegexp/ )
        {
            print("  - found cached start: $lineNum") if( $optionDebug );
            $startLine = $lineNum;
            last;
        }
    }    

    for( my $i = $startLine; $i < scalar(@$refLogLines); $i++ )
    {
        $i++ if( $i < 0 );
        
        my $line = @$refLogLines[$i];

        next if( !defined $line );
        
        # Case start was not found from cached locations, find it as we go thru the lines.
        if( $startLine == -1 )
        {   
            if( $line =~ m/RunTest: $caseNameRegexp/ )
            {
                print("  - found start: $line") if( $optionDebug );
                $startLine = $i;
            }
        }
        else
        {
            if( $line =~ m/\*\*\*Testcase [a-z]+\*\*\*/i )
            {
                print("  - found end: $line") if( $optionDebug );
                $endLine = $i + 1;
                last;
            }
        }
    }

    if( $startLine == -1 || $endLine == -1 )
    {
        return;
    }

	# Write the log file

	my $fileMode = ">>";

	print(" - Case log file: " . $caseLogFile ."\n") if($optionShowMessages);

	if(	open(FILE_HANDLE, $fileMode . $caseLogFile) )
	{
		if($optionHtml)
		{
			print FILE_HANDLE (
			"<html>\n" .
			"<head>\n" .
			"<title>$title</title>\n" .
			"</head>\n" .
			"<body>\n" .
			"<basefont color=\"black\" face=\"arial\" size=\"4\">\n"
			);
		}

		foreach $line(@writeArray)
		{
			print FILE_HANDLE ($line);
		}

		for( my $i = $startLine; $i < $endLine; $i++ )
		{
			my $line = @$refLogLines[$i];
			FormatLogLine(\$line) if($optionHtml);

			print FILE_HANDLE ($line);
		}

		if($optionHtml)
		{
		print FILE_HANDLE (
			"</body>\n" .
			"</html>"
			);
		}

        print FILE_HANDLE ( $lineBreak );
		print FILE_HANDLE ( $lineBreak );

		close FILE_HANDLE;

	} else
	{
		print("ERROR: Could not write to file: " . $caseLogFile . "\n");
	}
}

#------------------------------------------------------------------------------------
# CheckCaseEntriesInLog
#
# Parameters:
#	$refLogLines: reference to array of log lines
#
# Finds if there's log entries for cases that are not reported in the testreport files
# and create case specific logs for them
#------------------------------------------------------------------------------------
sub CheckCaseEntriesInLog
{
	my ($refLogLines) = @_;

	foreach $case(@cases)
	{
		if(@{$case}[$CASE_CHECK_RESULT_LOG_FILE] == 1)
		{
			@{$case}[$CASE_CHECK_RESULT_LOG_FILE] = 0;

#create the next lines for WriteCaseLog function

#line1: [testscripter_iptvservicemanagementapitestasync][c:\TestFramework\IptvServiceManagementApiTestAsync.cfg][2] Title:[ET08203 Add valid hardcoded service_0 ASYNC]
#line2:	StartTime: 3:06:14.2212 PM, EndTime: 3:06:18.1037 PM
#line3:	Result: 0 [] ==> PASSED

			#starttime = case startline
			#endttime = next case starttline | lastline

			my $line1 = "[unknown.cfg][0] Title:[" . @{$case}[$CASE_NAME] . "]";
			my $line2 = "";
			my $line3 = "Result: 0 [] ==> UNKNOWN";

			my $startTime = "";
			my $endTime = "";
			my $status = "UNKNOWN";
			my $caseLogFile = "";
			my $result = "0";
			my $info = "";
			my $reason = "";

			my $caseId = "";
			foreach $line(@$refLogLines)
			{
				# take the times from lines where is case start text

				if($startTime eq "" && $line =~ m/>>> Case start:/i)
				{
					$caseId = substr($line, index($line, ">>> Case start:") + length(">>> Case start:"));

					RemoveWhiteSpaces(\$caseId);

					# set start time if case matches
					#02/08/2006	12:15:42	>>> Case start: ET00000 caseId
					if($caseId eq @{$case}[$CASE_ID])
					{
						#print("*** Reading case name\n\n");
						if($line =~ m/([0-9]+):([0-9]+):([0-9]+)/)
						{
							#print("CASESTART: $line\n");
							$startTime = "$1:$2:$3.0000";
							#print("*** READ TIME $startTime\n\n");
							next; # skip the rest of loop otherwise endtime will be same
						}
					}
				}

				# find endtime for case if starttime is set
				if($startTime ne "")
				{
					#[14:38:40.641] sti: MCU_ASCII_PRINTF; channel:0xE0; msg:TestCase [ET1024 Sort IapList when it has no IAPs] finished with verdict[0]

					#die("$line") if($line =~m/$caseId/i);
					#die("line: $line\n") if($line =~ m/finished with verdict/);

					if($line =~ m/$caseId/i and $line =~ m/finished with verdict\[([-]*[0-9]+)\]/)
					{

						$result = $1;

						if($1 eq "0")
						{
							$status = "PASSED";
							$line3 = "Result: $1 [] ==> PASSED";
						}
						else
						{
							$status = "FAILED";
							$line3 = "Result: $1 [] ==> FAILED";
						}
					}

					#if line has time then grab it
					if($line =~ m/([0-9]+):([0-9]+):([0-9]+)/)
					{
						$endTime = "$1:$2:$3.9999";
						# stop searching when next case is starting
						if( ($line =~ m/>>> Case start:/i || $line =~ m/>>> Case end./i) and !($line =~ m/$caseId/) )
						{
							#print("CASEEND: $line\n");
							last;
						}
					}
				}

			}

			$line2 = "StartTime: $startTime PM, EndTime: $endTime PM";

			#print("l1: $line1\nl2: $line2\nl3: $line3\n\n");

			my $refCaseDesc = GetCaseDesc($caseId);

			$caseLogFile = GetFileNameForCaseLog( $line1, $line2, $line3 );

			WriteCaseLog($caseLogFile, $refLogLines, $refCaseDesc, $line1, $line2, $line3);

			my $refCase = GetCase($caseId, \@cases);

			UpdateCase($refCase, $caseLogFile, "", $result, $status, $info, $reason, 0);
		}
	}
}

sub UpdateCase
{
	my ($refCase, $caseLogFile, $caseScripterLogFile, $result, $status, $info, $reason, $caseRunTimeSeconds) = @_;

	if($optionShowMessages) { print(" - Case update: $result, $status, $reason, $caseRunTimeSeconds\n\n"); };

	die("Result not defined. Cannot update.\n") if(!defined($result)  );
	die("Status not defined. Cannot update.\n") if(!defined($status) );
	die("Info not defined. Cannot update.\n") if( !defined($info) );
	die("Reason not defined. Cannot update.\n") if( !defined($reason) );

	$caseRunTimeSeconds = 0 if($caseRunTimeSeconds < 0);

	# we have actual result, no need for this anymore
	@$refCase[$CASE_CHECK_RESULT_LOG_FILE] = 0;

	if(!$optionFinalDoc)
	{
		@$refCase[$CASE_RUN_TIMES]++;

		@$refCase[$CASE_RUN_TIME_SECONDS] = $caseRunTimeSeconds;

		if($status eq "CRASHED") {
			@$refCase[$CASE_CRASHED]++;
		}
		elsif($status eq "FAILED") {
			@$refCase[$CASE_FAILED]++;
		}
		elsif($status eq "PASSED") {
			@$refCase[$CASE_PASSED]++;
		}
	}
	else
	{
		if($status eq "PASSED") {
			@$refCase[$CASE_PASSED] = 1;
			@$refCase[$CASE_CRASHED] = 0;
			@$refCase[$CASE_FAILED] = 0;
		}
		elsif($status eq "CRASHED" && @$refCase[$CASE_STATUS] ne "PASSED") {
			@$refCase[$CASE_PASSED] = 0;
			@$refCase[$CASE_CRASHED] = 1;
			@$refCase[$CASE_FAILED] = 0;
		}
		elsif($status eq "FAILED" && @$refCase[$CASE_STATUS] ne "PASSED" && @$refCase[$CASE_STATUS] ne "CRASHED") {
			@$refCase[$CASE_PASSED] = 0;
			@$refCase[$CASE_CRASHED] = 0;
			@$refCase[$CASE_FAILED] = 1;
		}
	}

	my $updateCase = 0;

	if(!$optionGoodIsBetter and !$optionFinalDoc)
	{
		# Only update case status if it's more fatal than the current, CRASHED > FAILED > UNKNOWN > PASSED
		if($status ne "$caseDefaultStatus")
		{
			if (@$refCase[$CASE_STATUS] eq "$caseDefaultStatus") {
				$updateCase = 1;
			}
			elsif (@$refCase[$CASE_STATUS] eq "CRASHED" ) {

			}
			elsif (@$refCase[$CASE_STATUS] eq "FAILED") {
				$updateCase = 1 if($status eq "CRASHED");
			}
			elsif(@$refCase[$CASE_STATUS] eq "PASSED") {
				$updateCase = 1;
			}
		}
	}
	else
	{
		# Only update case status if it's less fatal than the current, PASSED > FAILED > CRASHED > UNKNOWN
		if($status ne "$caseDefaultStatus")
		{
			if (@$refCase[$CASE_STATUS] eq "$caseDefaultStatus") {
				$updateCase = 1;
			}
			elsif(@$refCase[$CASE_STATUS] eq "UNKNOWN") {
				$updateCase = 1;
			}
			elsif($status eq "PASSED")
			{
				$updateCase = 1;
			}
			elsif (@$refCase[$CASE_STATUS] eq "CRASHED" ) {
				$updateCase = 1 if($status eq "FAILED");
			}
			elsif (@$refCase[$CASE_STATUS] eq "FAILED") {

			}
		}
	}

	if($updateCase)
	{
		@$refCase[$CASE_REASON] = $info . $reason;
		@$refCase[$CASE_RESULT] = $result;
		@$refCase[$CASE_STATUS] = $status;
		@$refCase[$CASE_LOG_FILE] = $caseLogFile;
		@$refCase[$CASE_LOG_FILE_SCRIPTER] = $caseScripterLogFile;
	}
	else
	{
	    # -1112 overrides other error codes because the case succeeded but verifying has failed.
	    if(@$refCase[$CASE_RESULT] ne "-1112" and $result eq "-1112")
	    {
	        @$refCase[$CASE_RESULT] = $result;
	    }
	}
	#print "case: " . @{$case}[$CASE_NAME] . "\n" . "run: " . @{$case}[$CASE_RUN_TIMES] . ", crash: " . @{$case}[$CASE_CRASHED] . ", fail " . @{$case}[$CASE_FAILED] . ", passed: " . 	@{$case}[$CASE_PASSED] . "\n";
}

sub CountCaseRunTime
{
	my ($line) = @_;
	my $found = 0;
	RemoveWhiteSpaces(\$line);
	#StartTime: 16:12:10,2440, EndTime: 16:12:34,3880
	#StartTime: 12:02:49.9302 pm, EndTime: 12:03:04.5781 pm
	if($line =~ m/^StartTime: ([0-9]+):([0-9]+):([0-9]+)\,[0-9]*, Endtime: ([0-9]+):([0-9]+):([0-9]+)\,[0-9]*$/i)
	{
		$found = 1;
	}
	elsif($line =~ m/^StartTime: ([0-9]+):([0-9]+):([0-9]+)\.[0-9]*[ A-Z]*, Endtime: ([0-9]+):([0-9]+):([0-9]+)\.[0-9]*[ A-Z]*$/i)
	{
		$found = 1;
	}

    my $caseRunTime = 0;

	if($found)
	{
		my $startSeconds = ($1 * 60 * 60) + $2 * 60 + $3;
		my $endSeconds = ($4 * 60 * 60) + $5 * 60 + $6;

		$caseRunTime = $endSeconds - $startSeconds;
	}
	$caseRunTime = 0 if($caseRunTime < 0);

    $totalExecutionTime += $caseRunTime;
	return $caseRunTime;
}

sub GetFileNameForCaseLog
{
    my ($line1, $line2, $line3, $extra) = @_;

	RemoveWhiteSpaces(\$line1);
	RemoveWhiteSpaces(\$line2);
	RemoveWhiteSpaces(\$line3);

	my $caseId = "";

	if($line1 =~ m/\[[0-9]+\][ ]+Title:\[([a-z0-9]+)$regexpCaseName\]$/i)
	{
		#"' ultraedit
		$caseId = $1;
	}

	my $caseTimeStr = "";

	#StartTime: 16:12:10,2440, EndTime: 16:12:34,3880
	if($line2 =~ m/^StartTime: ([0-9]+):([0-9]+):([0-9]+)\,[0-9]*, Endtime: ([0-9]+):([0-9]+):([0-9]+)\,[0-9]*$/i)
	{
		$found = 1;
	}
	elsif($line2 =~ m/^StartTime: ([0-9]+):([0-9]+):([0-9]+)\.[0-9]*[ A-Z]*, Endtime: ([0-9]+):([0-9]+):([0-9]+)\.[0-9]*[ A-Z]*$/i)
	{
		$found = 1;
	}

	if( $found )
	{
		$caseTimeStr = $1 . $2 . $3 . $4 . $5 . $6;
	}

	my $fileext = ".txt";
	$fileext = ".html" if($optionHtml);

    my $caseLogFile;
    
     if( !defined( $extra ) )
     {
        $caseLogFile = $caseLogOutDir . $caseId . "_" . $caseTimeStr . $fileext;
    }
    else
    {
        $caseLogFile = $caseLogOutDir . $caseId . "_" . $caseTimeStr . $extra . $fileext;
    }

	print(" - Case log file: " . $caseLogFile ."\n") if($optionShowMessages);
	return $caseLogFile;
}

#------------------------------------------------------------------------------------
# WriteCaseLog
#
# Parameters:
# 	$caseLogFile: filename to write
# 	$refLogLines: input where log lines are stored
# 	$caseDesc: optional text description of case which will be written into the log file
# 	$line1: [testscripter_iptvservicemanagementapitestasync][c:\TestFramework\IptvServiceManagementApiTestAsync.cfg][2] Title:[ET08203 Add valid hardcoded service_0 ASYNC]
# 	$line2:	StartTime: 3:06:14.2212 PM, EndTime: 3:06:18.1037 PM
# 	$line3:	Result: 0 [] ==> PASSED
#
# Writes case specific log file into testcase_logs/testcase_logs directory. Reads the lines from @caseLogLines array
#------------------------------------------------------------------------------------
sub WriteCaseLog
{
#[testscripter_iptvservicemanagementapitestasync][c:\TestFramework\IptvServiceManagementApiTestAsync.cfg][2] Title:[ET08203 Add valid hardcoded service_0 ASYNC]
#	StartTime: 3:06:14.2212 PM, EndTime: 3:06:18.1037 PM
#	StartTime: 12:34:41.5407, EndTime: 12:34:41.9687
#	Result: 0 [] ==> PASSED

	my ($caseLogFile, $refLogLines, $refCaseDesc, $line1, $line2, $line3) = @_;

	# Don't generate log files if we only print summary
	if($optionPrintCfgSummaries)
	{
		return;
	}

	#print("1: $line1");	print("2: $line2");	print("3: $line3");

	RemoveWhiteSpaces(\$line1);
	RemoveWhiteSpaces(\$line2);
	RemoveWhiteSpaces(\$line3);

	my $lineBreak = "\n";
	$lineBreak = "<br>\n" if($optionHtml);

	my $caseId = "";

	if($line1 =~ m/\[[0-9]+\][ ]+Title:\[([a-z0-9]+)$regexpCaseName\]$/i)
	{
		#"' ultraedit
		$caseId = $1;
		print("Writing log for: $caseId.\n") if($optionShowMessages);
	}

	# Write header for case

	my @writeArray;

	# split the first line
	push @writeArray, ( "<hr>" ) if($optionHtml);
	push @writeArray, ( substr($line1, 0, index($line1, "Title:")) . $lineBreak );
	push @writeArray, ( substr($line1, index($line1, "Title:")) . $lineBreak );
	my $title = substr($line1, index($line1, "Title:"));

	#($line1 . "\n");
	push @writeArray, ($line2 . $lineBreak);
	push @writeArray, ($line3 . $lineBreak);
	push @writeArray, ("\n");
	push @writeArray, ( "<hr>" ) if($optionHtml);

	# Include the script for the case in the file?

	if($optionCaseIncludedInLog)
	{
		foreach $linexxx (@{$refCaseDesc})
		{
			push @writeArray, ("$linexxx");
			push @writeArray, ($lineBreak) if($optionHtml);
		}
		push @writeArray, ( "<hr>" ) if($optionHtml);
		push @writeArray, ("\n");
	}

	my $passed = 0;
	$passed = 1 if($line3 =~ m/==> PASSED/);

	# Get the log for the case

	my $startLine = 0;
	my $endLine = 0;

	my $logLineCount = scalar(@$refLogLines);

	if($logLineCount > 0 && ($optionLogAllCases || !$passed) )
	{
		if($lastCaseLogLine >= $logLineCount)
		{
			$lastCaseLogLine = 0;
		}

		# Get the start and end time for the case

		my $found = 0;
		#StartTime: 16:12:10,2440, EndTime: 16:12:34,3880
		if($line2 =~ m/^StartTime: ([0-9]+):([0-9]+):([0-9]+)\,[0-9]*, Endtime: ([0-9]+):([0-9]+):([0-9]+)\,[0-9]*$/i)
		{
			$found = 1;
		}
		elsif($line2 =~ m/^StartTime: ([0-9]+):([0-9]+):([0-9]+)\.[0-9]*[ A-Z]*, Endtime: ([0-9]+):([0-9]+):([0-9]+)\.[0-9]*[ A-Z]*$/i)
		{
			$found = 1;
		}
		else
		{
			print(" *ERROR* Could not parse case run time for case $caseId.  Can not write case log note. Returning.\n");
			return;
		}

		my $startSeconds = 0;
		my $endSeconds = 0;

		if($found)
		{
			$startSeconds = ($1 * 60 * 60) + $2 * 60 + $3;
			$endSeconds = ($4 * 60 * 60) + $5 * 60 + $6;

			my $caseRunTime = $endSeconds - $startSeconds;

			if($caseRunTime < 0)
			{
				# It's possible to code solution but it'd slow down the script.
				print(" *ERROR* Case $caseId has probably passed midnight/midday. Giving up writing case specific log.\n");
				return;
			}

			#print " - start:"  . $1 . ":" . $2 . ":" . $3 . " = " . $startSeconds . "\n";
			#print " - end: " . $4 . ":" . $5 . ":" . $6 . " = " . $endSeconds . "\n";
		}

		# Find indexes for start and end lines

		$startLine = -1;
		# If the line at $lastCaseLogLine matches then find backwards the first matching line,
		# otherwise some lines might be missed from the log note.
		if(LogLineTimeMatchesForCase(\@$refLogLines[$lastCaseLogLine], $startSeconds, $startSeconds))
		{
			#print("find back\n");
			for(my $i=$lastCaseLogLine; $i > 0; $i--)
			{
				if(!LogLineTimeMatchesForCase(\@$refLogLines[$i], $startSeconds, $startSeconds))
				{
					$startLine = $i+1;
					last;
				}
			}
		}
		# Otherwise try to find match forward.
		else
		{
			$startLine = FindLogLineMatch($refLogLines, $startSeconds, $endSeconds, $lastCaseLogLine, 1);
		}
		# If that doesn't succeed then lets go at start of the log. SLOW for huge logs.
		if($startLine == -1)
		{
			$startLine = FindLogLineMatch($refLogLines, $startSeconds, $endSeconds, 0, 1);
			$lastCaseLogLine = 0;
		}
		if($startLine == -1)
		{
			print(" *ERROR* startLine not found!\n");
			return;
		}

		print(" - StartLine: $startLine\n") if($optionShowMessages);

		# Find forward the last line which does not match.
		$endLine = FindLogLineMatch($refLogLines, $startSeconds, $endSeconds, $startLine+1, 0);

		if($endLine == -1 || $endLine < $startLine)
		{
		    print(" - End line not found, trying alternative method.\n") if($optionShowMessages);
			# Find first not matching line forward from the case start.
			$endLine = FindLogLineMatch($refLogLines, $startSeconds, $endSeconds, scalar(@$refLogLines)-1, 0);
			if( $endLine == -1 || $endLine < $startLine )
			{
				# Just take the rest of the log
				$endLine = scalar(@$refLogLines)-1;
			}
		}

		print(" - EndLine: $endLine\n") if($optionShowMessages);

		$lastCaseLogLine = $endLine-1;
	}

	# Create log directory

	if ( !(-e "testcase_logs") )
	{
  		mkdir("testcase_logs");
	}

	if ( !(-e "$caseLogOutDir") )
	{
		mkdir($caseLogOutDir, 0755);
	}

	# Write the log file

	my $fileMode = ">>";

	print(" - Case log file: " . $caseLogFile ."\n") if($optionShowMessages);

	if(	open(FILE_HANDLE, $fileMode . $caseLogFile) )
	{
		if($optionHtml)
		{
			print FILE_HANDLE (
			"<html>\n" .
			"<head>\n" .
			"<title>$title</title>\n" .
			"</head>\n" .
			"<body>\n" .
			"<basefont color=\"black\" face=\"arial\" size=\"4\">\n"
			);
		}

		foreach $line(@writeArray)
		{
			print FILE_HANDLE ($line);
		}

		for(my $i=$startLine;$i<$endLine;$i++)
		{
			my $line = @$refLogLines[$i];
			FormatLogLine(\$line) if($optionHtml);

			print FILE_HANDLE ($line);
		}

		if($optionHtml)
		{
		print FILE_HANDLE (
			"</body>\n" .
			"</html>"
			);
		}

        print FILE_HANDLE ( $lineBreak );
		print FILE_HANDLE ( $lineBreak );

		close FILE_HANDLE;

	} else
	{
		print("ERROR: Could not write to file: " . $caseLogFile . "\n");
	}
}

# There's case start entry in the log, write case log from there onwards.
sub WriteCaseLogFromEntry
{
 	my ($caseLogFile, $refLogLines, $caseEntryLogStartLine, $line1, $line2, $line3) = @_;

	# Don't generate log files if we only print summary
	if($optionPrintCfgSummaries)
	{
		return 0;
	}

	RemoveWhiteSpaces(\$line1);
	RemoveWhiteSpaces(\$line2);
	RemoveWhiteSpaces(\$line3);

	my $lineBreak = "\n";
	$lineBreak = "<br>\n" if($optionHtml);

	my $caseId = "";

	if($line1 =~ m/\[[0-9]+\][ ]+Title:\[([a-z0-9]+)$regexpCaseName\]$/i)
	{
		#"' ultraedit
		$caseId = $1;
	}

	# Write header for case

	my @writeArray;

	# split the first line
	push @writeArray, ( "<hr>" ) if($optionHtml);
	push @writeArray, ( substr($line1, 0, index($line1, "Title:")) . $lineBreak );
	push @writeArray, ( substr($line1, index($line1, "Title:")) . $lineBreak );
	my $title = substr($line1, index($line1, "Title:"));

	#($line1 . "\n");
	push @writeArray, ($line2 . $lineBreak);
	push @writeArray, ($line3 . $lineBreak);
	push @writeArray, ("\n");
	push @writeArray, ( "<hr>" ) if($optionHtml);

	my $passed = 0;
	$passed = 1 if($line3 =~ m/==> PASSED/);

	# Get the log for the case

	my $logLineCount = scalar(@$refLogLines);

	if($logLineCount > 0 && ($optionLogAllCases || !$passed) )
	{
		# Get the start and end time for the case

		my $found = 0;
		#StartTime: 16:12:10,2440, EndTime: 16:12:34,3880
		if($line2 =~ m/^StartTime: ([0-9]+):([0-9]+):([0-9]+)\,[0-9]*, Endtime: ([0-9]+):([0-9]+):([0-9]+)\,[0-9]*$/i)
		{
			$found = 1;
		}
		elsif($line2 =~ m/^StartTime: ([0-9]+):([0-9]+):([0-9]+)\.[0-9]*[ A-Z]*, Endtime: ([0-9]+):([0-9]+):([0-9]+)\.[0-9]*[ A-Z]*$/i)
		{
			$found = 1;
		}
		else
		{
			print(" *ERROR* Could not parse case run time for case $caseId.  Can not write case log note. Returning.\n");
			return 0;
		}

		my $startSeconds = 0;
		my $endSeconds = 0;

		if($found)
		{
			$startSeconds = ($1 * 60 * 60) + $2 * 60 + $3;
			$endSeconds = ($4 * 60 * 60) + $5 * 60 + $6;

			my $caseRunTime = $endSeconds - $startSeconds;

			if($caseRunTime < 0)
			{
				# It's possible to code solution but it'd slow down the script.
				#print(" *ERROR* Case has probably passed midnight/midday. Giving up writing case specific log.\n");
				#return;
			}
		}
	}

	# Create log directory

	if ( !(-e "testcase_logs") )
	{
  		mkdir("testcase_logs");
	}

	if ( !(-e "$caseLogOutDir") )
	{
		mkdir($caseLogOutDir, 0755);
	}

	# Write the log file

	my $fileMode = ">>";

	print(" - Case log file: " . $caseLogFile ."\n") if($optionShowMessages);

    my $caseEntryLogEndLine = -1;
    for(my $i=$caseEntryLogStartLine; $i<scalar(@$refLogLines); $i++ )
    {
        if(@$refLogLines[$i] =~ m/<<< Case end/i)
        {
            $caseEntryLogEndLine = $i;
            last;
        }
    }
    if( $caseEntryLogEndLine == -1 )
    {
        print("ERROR: $caseId is missing case end command in the script?\n");
        return 0;
    }

	if(	open(FILE_HANDLE, $fileMode . $caseLogFile) )
	{
		if($optionHtml)
		{
			print FILE_HANDLE (
			"<html>\n" .
			"<head>\n" .
			"<title>$title</title>\n" .
			"</head>\n" .
			"<body>\n" .
			"<basefont color=\"black\" face=\"arial\" size=\"4\">\n"
			);
		}

		for( my $i = $caseEntryLogStartLine; $i < $caseEntryLogEndLine; $i++ )
		{
            my $line = @$refLogLines[$i];
            FormatLogLine(\$line) if($optionHtml);
            print FILE_HANDLE ($line);
		}

		if($optionHtml)
		{
		    print FILE_HANDLE (
			    "</body>\n" .
			    "</html>"
			    );
		}
        print FILE_HANDLE ( $lineBreak );
		print FILE_HANDLE ( $lineBreak );

		close FILE_HANDLE;

	} else
	{
		print("ERROR: Could not write to file: " . $caseLogFile . "\n");
		return 0;
	}
	
	return 1;
}

#------------------------------------------------------------------------------------
# FindLogLineMatchRecurse
#
# Parameters:
# 	$startsSeconds		the min time the log line will match
# 	$endSeconds			the max time the log line will match
# 	$refStartLine		index of line to start searching
# 	$refLogLines		reference to array of the log
# 	$boolOp				1 = first line with match is returned, 0 = first line with no match is returned
# 	$inc				increment in the search loop
#	$recurse			can the function call itself, if yes this will be passed to the new call too
#	$maxLine			the last line to search
#
#------------------------------------------------------------------------------------
sub FindLogLineMatchRecurse
{
	my ($startSeconds, $endSeconds, $refStartLine, $refLogLines, $boolOp, $inc, $recurse, $maxLine) = @_;

    print("IN FindLogLineMatchRecurse\n") if($optionDebug);
	my $spacer = "";
	for(my $i = 0;$i<$recurse; $i++)
	{
		$spacer .= "-";
	}

	$maxLine = scalar(@$refLogLines) if(!defined($maxLine) or $maxLine > scalar(@$refLogLines));
	print("s: $startSeconds, e: $endSeconds, sl: $$refStartLine, b: $boolOp, i: $inc, r: $recurse, ml: $maxLine\n") if($optionDebug);
	print("$spacer ENTER: range: $$refStartLine - $maxLine, $inc\n") if($optionDebug);
	print("$spacer rec: $recurse\n") if($optionDebug);
	print("$spacer prev: $$refStartLine\n") if($optionDebug);
	print("$spacer inc: $inc\n") if($optionDebug);

	# First try to find the start line without recursion.
	for(my $i = $$refStartLine; $i < $maxLine; $i += $inc)
	{
		if(LogLineTimeMatchesForCase(\@$refLogLines[$i], $startSeconds, $endSeconds) == $boolOp)
		{
			# We have exact match.
			if($inc == 1)
			{
				$$refStartLine = $i;
			}
			# Not exatch match. Return start of previous block.
			elsif($i >= $$refStartLine + $inc)
			{
				$$refStartLine = $i - $inc;
			}

			print("MATCH LINE: $i: " . @$refLogLines[$i] . "\n") if($optionDebug);
			print("return line: " . $$refStartLine . "\n") if($optionDebug);
			print("EXIT FindLogLineMatchRecurse. return 1\n") if($optionDebug);
			return 1;
		}
	}

	if($recurse && $inc > 500)
	{
		# Split the current search block to smaller blocks and do search to them
		for(my $i = $$refStartLine; $i < $maxLine; $i += $inc)
		{
			print("$spacer $i\n") if($inc != 1 && $optionDebug);
			print("...RECURSING!\n") if($optionDebug);

			# Start search from the start of current block.
			my $prevPos = $i;

			# New last line to search
			my $end = $i + $inc;
			$end = scalar(@$refLogLines)-1 if($end > scalar(@$refLogLines)-1);

			# New increment, twice smaller than now
			my $newInc = int($inc / 2 + 0.5);
			$newInc = 200 if($newInc < 200);

			if(FindLogLineMatchRecurse($startSeconds, $endSeconds, \$prevPos, $refLogLines, $boolOp, $newInc, $recurse-1, $end) == 1)
			{
				$$refStartLine = $prevPos;
				print("EXIT FindLogLineMatchRecurse. return 1\n") if($optionDebug);
				return 1;
			}
		}
	}

	print("EXIT FindLogLineMatchRecurse. return 0\n") if($optionDebug);
	return 0;
}

#------------------------------------------------------------------------------------
# FindLogLineMatch
#
# Searches for log line with time between the startSeconds and endSeconds.
#
# Parameters:
# 	$refLogLines		reference to array of the log
# 	$startsSeconds		the min time the log line will match
# 	$endSeconds			the max time the log line will match
# 	$startLine			index of line to start searching
# 	$boolOp				1 = first line with match is returned, 0 = first line with no match is returned
#------------------------------------------------------------------------------------
sub FindLogLineMatch
{
	my ($refLogLines, $startSeconds, $endSeconds, $startLine, $boolOp) = @_;
    print("IN FindLogLineMatch\n") if($optionDebug);
	my $prevPos = $startLine;

	#print("\n\nSTART: $startLine, boolop: $boolOp \n");

	my $match = 0;
	$match = FindLogLineMatchRecurse($startSeconds, $endSeconds, \$prevPos, $refLogLines, $boolOp, 6000, 5);
	$prevPos = 0 if(!$match);
	# Refine the search to be exact line
	$match = FindLogLineMatchRecurse($startSeconds, $endSeconds, \$prevPos, $refLogLines, $boolOp, 1, 0);

    print("EXIT FindLogLineMatch\n") if($optionDebug);
	# Not found.
	return -1 if(!$match);

	return $prevPos;
}

#------------------------------------------------------------------------------------
# JustFormatLogFile
#
# Parameters:
#	$fileName
#------------------------------------------------------------------------------------
sub JustFormatLogFile
{
	my ($fileName) = @_;

	if( !open(FILE_HANDLE, $fileName) )
	{
		die("ERROR! Could not open file '" . $fileName . "'\n");
	}
	my @array = <FILE_HANDLE>;
	close(FILE_HANDLE);

	$fileName = substr($fileName, 0, index($fileName, ".txt")) . ".html";

	if(	open(FILE_HANDLE, ">" . $fileName) )
	{

		print FILE_HANDLE (
		"<html>\n" .
		"<head>\n" .
		"<title>$fileName</title>\n" .
		"</head>\n" .
		"<body>\n" .
		"<basefont color=\"black\" face=\"arial\" size=\"4\">\n"
		);


		my $i;
		for($i = 0;$i<scalar(@array); $i++)
		{
			my $line = $array[$i];
			$line =~ s/\t/ /; #remove tabs
			FormatLogLine(\$line);

			print FILE_HANDLE ($line);
		}

		print FILE_HANDLE (
		"</body>\n" .
		"</html>"
		);

		close FILE_HANDLE;
	} else
	{
		print("ERROR: Could not write to file: " . $fileName . "\n");
	}

}

#------------------------------------------------------------------------------------
# LogLineTimeMatchesForCase
#
# Parameters:
#	$refLine
#	$startSeconds
#	$endSeconds
#------------------------------------------------------------------------------------
sub LogLineTimeMatchesForCase
{
	my ($refLine, $startSeconds, $endSeconds) = @_;

	return 0 if(!defined($$refLine));

	$$refLine =~ s/\t/ /; #remove tabs

	#print($$refLine . "\n");
	#print(" - $startSeconds, $endSeconds\n");

	if(${$refLine} =~ m/[0-9\/]+ ([0-9]+):([0-9]+):([0-9]+)/i)
	{
#			print("YES " . $1 . "\n");

		my $currSeconds = $1 * 60 * 60 + $2 * 60 + $3;
		#print(" - curr: $currSeconds\n");

		#print("curr: $currSeconds, start: $startSeconds, end: $endSeconds\n");

		if($currSeconds >= $startSeconds and $currSeconds <= $endSeconds)
		{
			#print("MATCH curr: " . $1 . ":" . $2 . ":" . $3 . " = " . $currSeconds . "\n");
			return 1;
		}
	}
	#print("NO MATCH\n");
	return 0;
}

#------------------------------------------------------------------------------------
# FormatLogLine
# Parameters:
# 	$line
#------------------------------------------------------------------------------------
sub FormatLogLine
{
	my ($line) = @_;

#Color

# sisään
#27/06/2006	9:37:52	>>>*									royalblue #2B60DE
# pois
#27/06/2006	9:37:52	<<<*									lightblue #0000FF
#27/06/2006	9:23:57	* exit
# destructor
#27/06/2006	9:23:58	~*										#FF0000
#27/06/2006	9:23:58	>>>~*

#27/06/2006	9:37:52	CIptv*Test *							GREY #808080
#27/06/2006	9:37:52	*error/fail								RED #FF0000
#27/06/2006	9:23:41	CreateServerProcess() 					GREEN #00FF00

#!!	TTestObject::~TTestObject								#800080

my $color = "#000000";


if(${$line} =~ m/([0-9\/]+ [0-9]+:[0-9]+:[0-9]+)/i)
{
	$date = $1;
	${$line} = substr(${$line}, length($date));

	$color = "#808080" if(${$line} =~ m/CIptvTest[a-z0-9]+Test/i);

	$color = "#2B60DE" if(${$line} =~ m/^[\t ]*>>>/i);
	$color = "#2B60DE" if(${$line} =~ m/\(\)$/i);
	$color = "#2B60DE" if(${$line} =~ m/enter$/i);

	$color = "#0000FF" if(${$line} =~ m/^[\t ]*<<<*/i);
	$color = "#0000FF" if(${$line} =~ m/ exit$/i);

	$color = "#800080" if(${$line} =~ m/^[\t ]*~/i);
	$color = "#800080" if(${$line} =~ m/^[\t ]*>>>~/i);
	$color = "#800080" if(${$line} =~ m/::~/i);

	$color = "#FF0000" if(${$line} =~ m/error|fail/i);
	
	$color = "#00AA00" if(${$line} =~ m/passed/i);
	$color = "#FF0000" if(${$line} =~ m/\*\*\*Testcase[a-z ]+\*\*\*/i);
	$color = "#00AA00" if(${$line} =~ m/\*\*\*Testcase PASSED+\*\*\*/i);
	$color = "#0000FF" if(${$line} =~ m/Executing line/i);
	
	my $formatStart = "", $formatEnd = "";

	if(${$line} =~ m/Client created semaphore, init/i) { $formatStart = "<b>"; $formatEnd = "</b>"; }
	if(${$line} =~ m/CIptvEngineServer:: ->Starting server shutdown/i) { $formatStart = "<b>"; $formatEnd = "</b>"; }

	SpecialChars($line);

	$date = "<font color=\"black\" face=\"arial\" size=\"2\">" . $date . "</font>";
	${$line} = $date . "$formatStart<font color=\"$color\" face=\"arial\" size=\"2\">" . ${$line} . "</font>$formatEnd<br>";
}


#$line = "<font color=\"$color\" face=\"arial\" size=\"2\"> . $line

#$color = "#2B60DE" if($line =~ m/([0-9\/]+ [0-9]+:[0-9]+:[0-9]+) >>>/i)


}

sub PrintCfgSummaries
{
	my $caseCfgFileName = "";
	my %cfgCaseCount;
	my %cfgCaseTotalTime;

	foreach $case(@cases)
	{
		$caseCfgFileName = @{$case}[$CASE_CFG_FILE];

		if(!defined($cfgCaseCount{$caseCfgFileName}))
		{
			$cfgCaseCount{$caseCfgFileName} = 0;
			$cfgCaseTotalTime{$caseCfgFileName} = 0;
		}

		if(defined(@{$case}[$CASE_RUN_TIME_SECONDS]))
		{
			$cfgCaseTotalTime{$caseCfgFileName} +=  @{$case}[$CASE_RUN_TIME_SECONDS];
		}


		$cfgCaseCount{$caseCfgFileName}++ if(@{$case}[$CASE_STATUS] ne "$caseDefaultStatus") ;
	}

	my $totalTime = 0;
	printf("\n%-50s %10s %10s\n", "CFG", "Case count", "Case run time");
	foreach $caseCfgFileName (sort keys(%cfgCaseCount))
	{
		if($cfgCaseCount{$caseCfgFileName} > 0)
		{
			my $mins = ($cfgCaseTotalTime{$caseCfgFileName}/60);
			$totalTime += $mins;
			printf("%-50s %10d %10.1f\n", $caseCfgFileName, $cfgCaseCount{$caseCfgFileName}, $mins);
		}
	}
	printf("Total time: %.2f hours\n\n", $totalTime/60 );

	print("No cases run for:\n");
	foreach $caseCfgFileName (sort keys(%cfgCaseCount))
	{
		if($cfgCaseCount{$caseCfgFileName} == 0)
		{
			print("$caseCfgFileName\n");
		}
	}
}

#------------------------------------------------------------------------------------
# WriteOfficeXml
#
# Parameters:
#	$outputFile
#	$briefSummary
#
# Writes the cases into a word formatted xml file.
#------------------------------------------------------------------------------------
sub WriteOfficeXml
{
	my ($outputFile, $briefSummary) = @_;

	if(	!open(FILE_HANDLE, ">" . $outputFile) )
	{
		print("ERROR! Could not open file '" . $outputFile . "'\n");
		return;
	}

	my $writeData = $xmlHeader;
	my $replacement;

	if($briefSummary == 0) {
		$writeData .= $xmlHeaderTableColumns;
	}
	else {
		$writeData .= $xmlHeaderTableColumnsBrief;
	}

	$excelRowCount = scalar(@cases) * 9 + 100;
	$writeData =~ s/$CaseCountMul8/$excelRowCount/;

	print FILE_HANDLE ( $writeData );

	if($briefSummary) {
		$writeData = $xmlSummaryData;

		$writeData =~ s/$xmlDataSummaryCaseCount/$summaryCaseCount/;
		$writeData =~ s/$xmlDataSummaryPassed/$summaryPassedCases/;
		$writeData =~ s/$xmlDataSummaryFailed/$summaryFailedCases/;
		$writeData =~ s/$xmlDataSummaryCrashed/$summaryCrashedCases/;
		$writeData =~ s/$xmlDataSummaryTimeout/$summaryTimeoutCases/;
		$writeData =~ s/$xmlDataSummaryRunRate/$summaryRunRate/;
		$writeData =~ s/$xmlDataSummaryPassRateTotal/$summaryPassRateTotal/;
		$writeData =~ s/$xmlDataSummaryPassRateRun/$summaryPassRateRun/;

		print FILE_HANDLE ( $writeData );
	}

	my $caseCfgFileName = "";

	my %cfgCaseCount;

	# Sort the cases by the config files, cfg's which have no run cases come last

	if(!$optionSortCases)
	{
		#print("HASH CREATE\n");
		#create hash of cfg case counts
		foreach $case(@cases)
		{
			$caseCfgFileName = @{$case}[$CASE_CFG_FILE];

			if(!defined($cfgCaseCount{$caseCfgFileName}))
			{
				$cfgCaseCount{$caseCfgFileName} = 0;
			}

			$cfgCaseCount{$caseCfgFileName}++ if(@{$case}[$CASE_STATUS] ne "$caseDefaultStatus") ;
		}

		#print("THRU CASES\n");

		foreach $caseCfgFileName (keys(%cfgCaseCount))
		{
			# if cfg has zero cases run then it's cases are put back of the array
			if($cfgCaseCount{$caseCfgFileName} == 0)
			{
				#print("ZERO CASES RUN: $caseCfgFileName\n");
				my @moveCases;

				my $i;
				for($i=0; $i< scalar(@cases); $i++)
				{
					if($cases[$i][$CASE_CFG_FILE] eq $caseCfgFileName)
					{
						push @moveCases, splice(@cases, $i, 1);
						$i--;
					}
				}

				push @cases, @moveCases;
			}
		}
	}

	# Write the xml file

	$caseCfgFileName = "";

	foreach $case(@cases)
	{
	    if($optionShowMessages || $optionDebug) 
		{
			print(" - Case Xml : " . @{$case}[$CASE_NAME]  . ", status: " . @{$case}[$CASE_STATUS] . "\n") if( $optionDebug || @{$case}[$CASE_STATUS] ne "Not planned" );
		}
		
		if($briefSummary == 0)
		{
			$writeData = $xmlData;
			$writeData .= $xmlData2;
			$writeData .= $xmlDataEmptyRow;
		}
		else
		{
			$writeData = "";

			# Write cfg file to the brief xml if it has changed for the case
			if($optionSortCases == 0 && $caseCfgFileName ne @{$case}[$CASE_CFG_FILE])
			{
				$caseCfgFileName = @{$case}[$CASE_CFG_FILE];

				$writeData .= $xmlDataEmptyRow;
				$writeData .= $xmlCfgFileBrief;
				$writeData .= $xmlDataBriefHeader;

				$replacement = @{$case}[$CASE_CFG_FILE];
				XmlReadyText(\$replacement);
				$writeData =~ s/$xmlDataCfgFile/$replacement/;
			}
			
			# Write log file links to xml.

			my $caseHasLog = ( defined(@{$case}[$CASE_LOG_FILE]) and @{$case}[$CASE_LOG_FILE] ne "" );
			my $caseHasScripterLog = ( defined(@{$case}[$CASE_LOG_FILE_SCRIPTER]) and @{$case}[$CASE_LOG_FILE_SCRIPTER] ne "" );
			my $caseLogLink1 = "";
			my $caseLogLink2 = "";
			
			if( $caseHasLog && $caseHasScripterLog )
			{
			    print("   - Case has both log files\n") if ($optionDebug );
			    $writeData .= $xmlDataBrief2Links;
			    $caseLogLink1 = @{$case}[$CASE_LOG_FILE];
			    $caseLogLink2 = @{$case}[$CASE_LOG_FILE_SCRIPTER];
			}
			elsif( $caseHasLog )
			{
			    print("   - Case has log file\n") if ($optionDebug );
			    $writeData .= $xmlDataBrief1Link;
			    $caseLogLink1 = @{$case}[$CASE_LOG_FILE];
			}
			elsif( $caseHasScripterLog )
			{
			    print("   - Case has scripter log file\n") if ($optionDebug );
			    $writeData .= $xmlDataBrief1Link;
			    $caseLogLink1 = @{$case}[$CASE_LOG_FILE_SCRIPTER];
		    }
			else
			{
			    print("   - Case has no log files\n") if ($optionDebug );
			    $writeData .= $xmlDataBriefNoLinks;
			}
			
			if( $caseLogLink1 ne "" )
			{
                print("   - Log file 1: $caseLogLink1\n") if ($optionDebug );
                $replacement = $caseLogLink1;
				XmlReadyText(\$replacement);
				
				#print("wordxml log file 1: $replacement\n";

				#print("repl: " . $replacement . "\n");
				$replacement = substr($replacement, index($replacement, "\\") + 1);
				#$replacement = ".\\testcase_logs\\..\\" . $replacement;
				#print("repl: " . $replacement . "\n");

				$writeData =~ s/$xmlDataCaseLink1/$replacement/;
			}

			if( $caseLogLink2 ne "" )
			{
			    print("   - Log file 2: $caseLogLink2\n") if ($optionDebug );
                $replacement = $caseLogLink2;
				XmlReadyText(\$replacement);
				
				#print("wordxml log file 2: $replacement\n";

				#print("repl: " . $replacement . "\n");
				$replacement = substr($replacement, index($replacement, "\\") + 1);
				#$replacement = ".\\testcase_logs\\..\\" . $replacement;
				#print("repl: " . $replacement . "\n");

				$writeData =~ s/$xmlDataCaseLink2/$replacement/;
			}
			
			# Write case fail reason to xml.
			
			$replacement = @{$case}[$CASE_REASON];
			XmlReadyText(\$replacement);
			$writeData =~ s/$xmlDataCaseReason/$replacement/;

            # Write case run time or result to xml.

			if(!$optionCaseRunTimes)
			{
				$replacement = @{$case}[$CASE_RESULT];
			}
			else
			{
				$replacement = @{$case}[$CASE_RUN_TIME_SECONDS];
			}

			# Write result to xml.
			
			XmlReadyText(\$replacement);
			$writeData =~ s/$xmlDataCaseResult/$replacement/;
		}

		#$writeData = $xmlData;
		#if($option_brief_summary == 0) { $writeData .= $xmlData2; }
		#$writeData .= $xmlDataEmptyRow;

		$replacement = @{$case}[$CASE_NAME];
		XmlReadyText(\$replacement);
		$writeData =~ s/$xmlDataCaseName/$replacement/;

		$replacement = @{$case}[$CASE_RUN_TIMES];
		XmlReadyText(\$replacement);
		$writeData =~ s/$xmlDataCaseRunTimes/$replacement/;

		$replacement = @{$case}[$CASE_FAILED];
		XmlReadyText(\$replacement);
		$writeData =~ s/$xmlDataCaseFailed/$replacement/;

		$replacement = @{$case}[$CASE_CRASHED];
		XmlReadyText(\$replacement);
		$writeData =~ s/$xmlDataCaseCrashed/$replacement/;

		$replacement = @{$case}[$CASE_PASSED];
		XmlReadyText(\$replacement);
		$writeData =~ s/$xmlDataCasePassed/$replacement/;

		$replacement = @{$case}[$CASE_STATUS];
		XmlReadyText(\$replacement);
		$writeData =~ s/$xmlDataCaseStatus/$replacement/;

		$replacement = @{$case}[$CASE_PURPOSE];
		XmlReadyText(\$replacement);
		$writeData =~ s/$xmlDataCasePurpose/$replacement/;

		$replacement = @{$case}[$CASE_MEANS];
		XmlReadyText(\$replacement);
		$writeData =~ s/$xmlDataCaseMeans/$replacement/;

		$replacement = @{$case}[$CASE_REQUIRED_SETTINGS];
		XmlReadyText(\$replacement);
		$writeData =~ s/$xmlDataCaseRequiredSettings/$replacement/;

		$replacement = @{$case}[$CASE_RELATED_REQUIREMENTS];
		XmlReadyText(\$replacement);
		$writeData =~ s/$xmlDataCaseRelatedRequirements/$replacement/;

		$replacement = @{$case}[$CASE_VERIFICATION];
		XmlReadyText(\$replacement);
		$writeData =~ s/$xmlDataCaseVerification/$replacement/;

		$replacement = @{$case}[$CASE_NOTE];
		XmlReadyText(\$replacement);
		$writeData =~ s/$xmlDataCaseNote/$replacement/;

		if(@{$case}[$CASE_STATUS] eq "UNKNOWN") {
			$replacement = $STYLE_ID_STATUS_UNKNOWN;
		}
		elsif(@{$case}[$CASE_STATUS] eq "CRASHED") {
			$replacement = $STYLE_ID_STATUS_CRASHED;
		}
		elsif(@{$case}[$CASE_STATUS] eq "FAILED") {
			$replacement = $STYLE_ID_STATUS_FAILED;
		}
		elsif(@{$case}[$CASE_STATUS] eq "PASSED") {
			$replacement = $STYLE_ID_STATUS_PASSED;
		}
		else {
			$replacement = $STYLE_ID_STATUS_NA;
		}

		$writeData =~ s/$STYLE_ID_STATUS_TAG/$replacement/;

		print FILE_HANDLE ( $writeData );
	}

	print FILE_HANDLE ( $xmlFooter );

	close(FILE_HANDLE);

	print("Report " . $outputFile . " written.\n");
}

#------------------------------------------------------------------------------------
# WriteOfficeXmlAlt
#
# Parameters:
#	$outputFile
#
# Writes the cases into a word formatted xml file.
#------------------------------------------------------------------------------------
sub WriteOfficeXmlAlt
{
	my ($outputFile, $refRuns) = @_;

	CalculateStats();

	if(	!open(FILE_HANDLE, ">" . $outputFile) )
	{
		print("ERROR! Could not open file '" . $outputFile . "'\n");
		return;
	}

	my $writeData = $xmlHeader;
	my $replacement;

    $writeData .= $xmlHeaderTableColumnsAlt;

    my $xRefRunInfo = @$refRuns[0];
    my $xRefCases = @$xRefRunInfo[2];
    my $caseCount = scalar( @$xRefCases ) + 1000;

	$excelRowCount = $caseCount * 9 + 100;
	$writeData =~ s/$CaseCountMul8/$excelRowCount/;

	print FILE_HANDLE ( $writeData );

	my $caseCfgFileName = "";

	my %cfgCaseCount;

	# Sort the cases by the config files, cfg's which have no run cases come last

	if(!$optionSortCases)
	{
		#print("HASH CREATE\n");
		#create hash of cfg case counts
		foreach $case(@cases)
		{
			$caseCfgFileName = @{$case}[$CASE_CFG_FILE];

			if(!defined($cfgCaseCount{$caseCfgFileName}))
			{
				$cfgCaseCount{$caseCfgFileName} = 0;
			}

			$cfgCaseCount{$caseCfgFileName}++ if(@{$case}[$CASE_STATUS] ne "$caseDefaultStatus") ;
		}

		#print("THRU CASES\n");

		foreach $caseCfgFileName (keys(%cfgCaseCount))
		{
			# if cfg has zero cases run then it's cases are put back of the array
			if($cfgCaseCount{$caseCfgFileName} == 0)
			{
				#print("ZERO CASES RUN: $caseCfgFileName\n");
				my @moveCases;

				my $i;
				for($i=0; $i< scalar(@cases); $i++)
				{
					if($cases[$i][$CASE_CFG_FILE] eq $caseCfgFileName)
					{
						push @moveCases, splice(@cases, $i, 1);
						$i--;
					}
				}

				push @cases, @moveCases;
			}
		}
	}

    my @sortedRuns;

    #Monday 25th August 2008
    while( 1 )
    {
        my $maxTotal = 0;
        my $refWinner;
        for( my $i=0; $i<scalar(@$refRuns); $i++ )
        {
            my $refRunInfo = @$refRuns[$i];
            my $date = @$refRunInfo[1];
            my @parts = split(" ", $date);
            my $total = 0 + $parts[1];

            if( $parts[2] eq "Jan" )
            {
                $total += 1 * 30;
            }
            elsif( $parts[2] eq "Feb" )
            {
                $total += 2 * 30;
            }
            elsif( $parts[2] eq "Mar" )
            {
                $total += 3 * 30;
            }
            elsif( $parts[2] eq "Apr" )
            {
                $total += 4 * 30;
            }
            elsif( $parts[2] eq "May" )
            {
                $total += 5 * 30;
            }
            elsif( $parts[2] eq "Jun" )
            {
                $total += 6 * 30;
            }
            elsif( $parts[2] eq "Jul" )
            {
                $total += 7 * 30;
            }
            elsif( $parts[2] eq "Aug" )
            {
                $total += 8 * 30;
            }
            elsif( $parts[2] eq "Sep" )
            {
                $total += 9 * 30;
            }
            elsif( $parts[2] eq "Oct" )
            {
                $total += 10 * 30;
            }
            elsif( $parts[2] eq "Nov" )
            {
                $total += 11 * 30;
            }
            elsif( $parts[2] eq "Dec" )
            {
                $total += 12 * 30;
            }

            if( $maxTotal < $total )
            {
                my $foundAlready = 0;
                foreach my $xrun ( @sortedRuns )
                {
                    if( $xrun == @$refRuns[$i] )
                    {
                        $foundAlready = 1;
                    }

                }

                if( !$foundAlready )
                {
                    $maxTotal = $total;
                    $winner = @$refRuns[$i];
                }
            }
        }
        push @sortedRuns, $winner;
        if( scalar(@sortedRuns) == scalar(@$refRuns) )
        {
            last;
        }
    }

    foreach $run ( @sortedRuns )
    {
        #print("sorted: " . @$run[1] . "\n");
    }
    foreach $run ( @$refRuns )
    {
        #print("orig: " . @$run[1] . "\n");
    }

    my $refMainRunInfo = $sortedRuns[0];
    my $refMainCases = @$refMainRunInfo[2];

	$caseCfgFileName = "";
    $replacement = "";

    # This prints only cases which are in first run. Build list of cases in all runs and use that.
    foreach $mainCase ( @$refMainCases )
    {
        $writeData = "";

        # Status of the current case in different runs
        my @statuses;
        my @results;
        for( my $i = 0; $i<100; $i++ )
        {
            $statuses[$i] = "UNKNOWN";
            $results[$i] = "";
        }

        for( my $i = 0; $i<scalar( @sortedRuns ); $i++ )
        {
            my $refRunInfo = $sortedRuns[$i];

            my $refCases = @$refRunInfo[2];

            foreach $case ( @$refCases )
            {
                if( @$case[$CASE_ID] eq @$mainCase[$CASE_ID] )
                {
                    $statuses[$i] = @$case[$CASE_STATUS];
                    $results[$i] = @$case[$CASE_RESULT];
                }
            }
        }

		# If cfg changes, write xml header for it
		if($caseCfgFileName ne @$mainCase[$CASE_CFG_FILE])
		{
			$caseCfgFileName = @$mainCase[$CASE_CFG_FILE];

			$writeData .= $xmlDataEmptyRow;
			$writeData .= $xmlCfgFileBrief;
			$writeData .= $xmlCfgFileAltHeader;

			$replacement = @$mainCase[$CASE_CFG_FILE];
			XmlReadyText(\$replacement);
			$writeData =~ s/$xmlDataCfgFile/$replacement/;


            for( $i = 0; $i<$ALT_RESULTCOUNT; $i++ )
            {
                $replacement = "";
                if( defined( $sortedRuns[$i] ) )
                {
                    $refRunInfo = $sortedRuns[$i];
                    $replacement = @$refRunInfo[1];
                }
                my $field = $xmlDataAltDateX . ($i+1);
                $writeData =~ s/$field/$replacement/;
            }
		}

        # Write xml for X cases

        $writeData .= $xmlCfgFileAltData;

	    $replacement = @$mainCase[$CASE_NAME];
	    XmlReadyText(\$replacement);
	    $writeData =~ s/$xmlDataCaseName/$replacement/;

        # Replace the X fields for runs
        for( my $i = 0; $i<$ALT_RESULTCOUNT; $i++ )
        {
            $replacement = $statuses[$i];
            $replacement = $results[$i];
            my $field = $xmlDataAltResultX . ($i+1);
            $writeData =~ s/$field/$replacement/;

    		$replacement = $STYLE_ID_STATUS_NA_CENTERED;
    		if($statuses[$i] eq "CRASHED") {
    			$replacement = $STYLE_ID_STATUS_CRASHED_CENTERED;
    		}
    		elsif($statuses[$i] eq "FAILED") {
    			$replacement = $STYLE_ID_STATUS_FAILED_CENTERED;
    		}
    		elsif($statuses[$i] eq "PASSED") {
    			$replacement = $STYLE_ID_STATUS_PASSED_CENTERED;
    		}
    		else {
    			$replacement = $STYLE_ID_STATUS_NA_CENTERED;
    		}

    		$writeData =~ s/$STYLE_ID_STATUS_TAG/$replacement/;
        }
        print FILE_HANDLE ( $writeData );
    }

	print FILE_HANDLE ( $xmlFooter );
	close(FILE_HANDLE);
	print("Alternative report " . $outputFile . " written.\n");
	return;
}

#------------------------------------------------------------------------------------
# WriteTDToolResultFile
#
# Parameters:
#	$outputFile
#
# Writes the cases into TDTool formatted file which can be exported into Quality Center
#------------------------------------------------------------------------------------
sub WriteTDToolResultFile
{
	my ($outputFile) = @_;

	if(	!open(FILE_HANDLE, ">" . $outputFile) )
	{
		print("ERROR! Could not open file '" . $outputFile . "'\n");
		return;
	}

	my $writeData;
	my $replacement;

	my %cfgCaseCount;

	# sort the cases by the config files, cfg's which have no run cases come last
	if(!$optionSortCases)
	{
		foreach $case(@cases)
		{
			$caseCfgFileName = @{$case}[$CASE_CFG_FILE];

			if(!defined($cfgCaseCount{$caseCfgFileName}))
			{
				$cfgCaseCount{$caseCfgFileName} = 0;
			}

			$cfgCaseCount{$caseCfgFileName}++ if(@{$case}[$CASE_STATUS] ne "$caseDefaultStatus") ;
		}

		#print("THRU CASES\n");

		foreach $caseCfgFileName (keys(%cfgCaseCount))
		{
			# if cfg has zero cases run then it's cases are put back of the array
			if($cfgCaseCount{$caseCfgFileName} == 0)
			{
				#print("ZERO CASES RUN: $caseCfgFileName\n");
				my @moveCases;

				my $i;
				for($i=0; $i< scalar(@cases); $i++)
				{
					if($cases[$i][$CASE_CFG_FILE] eq $caseCfgFileName)
					{
						push @moveCases, splice(@cases, $i, 1);
						$i--;
					}
				}

				push @cases, @moveCases;
			}
		}
	}

#test_set_name_here
#[1]APES PTSW_WBA_TS -1.1. - Server Version - (01) - COMM_SERVER_VERSION_GET_REQ
#Passed&Actual result:  Info: 0

	print FILE_HANDLE ( "IPTV_Engine test set\n" );

	foreach $case(@cases)
	{
		$writeData = "[1]";

		my $caseName = @{$case}[$CASE_NAME];
		$writeData .= $caseName;

		$writeData .= "\n";

		my $result;

		if(@{$case}[$CASE_STATUS] eq "UNKNOWN") {
			$result = "N/A";
		}
		elsif(@{$case}[$CASE_STATUS] eq "CRASHED") {
			$result = "Failed";
		}
		elsif(@{$case}[$CASE_STATUS] eq "FAILED") {
			$result = "Failed";
		}
		elsif(@{$case}[$CASE_STATUS] eq "PASSED") {
			$result = "Passed";
		}
		else {
			$result = "No Run";
		}

		$writeData .= $result;



		my $comments = "&Info";

		#$comments = "CFG file: @{$case}[$CASE_CFG_FILE];

		#$comments .= "Actual result = " . @{$case}[$CASE_RESULT] . ", Info = " . @{$case}[$CASE_REASON];

		$writeData .= $comments;

		$writeData .= "\n";

		# Replace bad characters for QC
		$writeData =~ s/\\/-/g;
		$writeData =~ s/\//-/g;
		$writeData =~ s/:/-/g;
		$writeData =~ s/\"/-/g;
		$writeData =~ s/\?/-/g;
		$writeData =~ s/\'/-/g;
		$writeData =~ s/\|/-/g;
		$writeData =~ s/\*/-/g;
		$writeData =~ s/\%/-/g;
		$writeData =~ s/ä/a/g;
		$writeData =~ s/ö/o/g;
		$writeData =~ s/\å/a/g;
		$writeData =~ s/</(/g;
		$writeData =~ s/>/)/g;

		if($result eq "Passed" or $result eq "Failed")
		{
			print FILE_HANDLE ( $writeData );
		}
	}

	close(FILE_HANDLE);

	print("Report " . $outputFile . " written.\n");
}


#------------------------------------------------------------------------------------
# FindCfgFiles
# Parameters:
#	$godir, $refFiles
#
# Finds cfg files from the the specified directory and it's sub directories.
#------------------------------------------------------------------------------------
sub FindCfgFiles
{
	my ($godir, $refFiles) = @_;
	
    my $startDir = cwd;

	chdir($godir) or die("Could not change dir to $godir");
	
	opendir(DIR, ".");
	my @files = sort(readdir(DIR));
	closedir(DIR);
	
	foreach $file(@files)
	{
		if($file eq "." or $file eq "..") {next};

		if (-d $file)
		{
		 	FindCfgFiles( $file, $refFiles );
		} else {
			if($file =~ m/\.cfg$/i)
			{
				next if($file =~ m/livetv/i and $optionNoLiveTvTests);

				next if(
						($file =~ m/IptvSecurityServicesTest/i or
						 $file =~ m/IptvRssSecurityTest/i or
						 $file =~ m/IptvLiveTvSep/i or
						 $file =~ m/IptvRssDownloadSecurityTest/i)

						 and $optionNoSecurityTests
						);

				next if($file =~ m/example.cfg/i);

				push @$refFiles, ( cwd . "/" . $file );
			}
		}
	}

	chdir("$startDir") or die("Could not change dir to $startDir");
}

#------------------------------------------------------------------------------------
# ParseCfg
# Parameters:
#	$file
#------------------------------------------------------------------------------------
sub ParseCfg
{
	my ($file) = @_;

	my $fileCaseCount = 0;

	if( !open(FILE_HANDLE, $file) )
	{
		print("ERROR! Could not open file '" . $file . "'\n");
		return 0;
	}
	my @array = <FILE_HANDLE>;
	close(FILE_HANDLE);

	my $lineCount = scalar(@array);
	my $i;
	my $cfgFileWritten = 0;
	my $caseDocumentationStart = -1;
	my $line;

	my @caseDesc; # lines for case desc and case itself

	for($i=0; $i<$lineCount; $i++ ) {
		$line = $array[$i];

		RemoveWhiteSpaces(\$line);

		#print("           $line\n");

		if($line =~ m/^\#\[IptvETDescription\]/)
		{
			$caseDocumentationStart = $i;
		}

		if($line =~ m/\[Test\]/)
		{
			if($caseDocumentationStart >= 0)
			{
				ReadCaseAndDescText(\@array, \@caseDesc, $caseDocumentationStart-1)
			}
			else
			{
				ReadCaseAndDescText(\@array, \@caseDesc, $i);
			}

			#print("readcase desc: " . scalar(@caseDesc) . "\n");
		}
		else
		{
		    #print("NOT READ readcase desc: " . scalar(@caseDesc) . "\n");
		}

	    #test case starts here
	    if($line =~ m/^title /)
	    {
	    	#print("COUNT: " . scalar(@caseDesc) . "\n\n");

			if($caseDocumentationStart >= 0)
			{
				#print(">>> Case start: " . $line . "\n");
				#$i +=
				ReadCase(\@array, $caseDocumentationStart, $file);
				$caseDocumentationStart = -1;
			}

	    	my $caseName = substr($line, length("title "));
	    	my $caseId = GetCaseIdFromName($caseName);

	    	RemoveWhiteSpaces(\$caseName);
	    	#SpecialChars(\$caseName);

	    	my $documentationExists = GetCase($caseId, \@cases);

			$caseDesc[0] = $caseName;
			push @caseDescs, [ @caseDesc ];
			@caseDesc = (); #new case starts

	    	# create empty array for case
	    	if(!$documentationExists)
	    	{
	    		if($cfgFileWritten == 0)
	    		{
	    			$cfgFileWritten = 1;
	    			push @notDocumentedCases, ("\n\n" . $file .
"\n************************************************************************************************\n"
						);

	    		}
	    		push @notDocumentedCases, ($caseName . "\n");

				#create dummy case
				my @case;
				$case[$CASE_NAME] = $caseName;

				$case[$CASE_ID] = $caseId;

				$case[$CASE_RUN_TIMES] = 0;
				$case[$CASE_CRASHED] = 0;
				$case[$CASE_FAILED] = 0;
				$case[$CASE_PASSED] = 0;
				$case[$CASE_STATUS] = "$caseDefaultStatus";
				$case[$CASE_PURPOSE] = "N/A";
				$case[$CASE_MEANS] = "N/A";
				$case[$CASE_REQUIRED_SETTINGS] = "N/A";
				$case[$CASE_RELATED_REQUIREMENTS] = "N/A";
				$case[$CASE_VERIFICATION] = "N/A";
				$case[$CASE_NOTE] = "N/A";
				$case[$CASE_REASON] = "";
				$case[$CASE_RESULT] = "";
				$case[$CASE_LOG_FILE] = "";
				$case[$CASE_LOG_FILE_SCRIPTER] = "";
				$case[$CASE_CHECK_RESULT_LOG_FILE] = 0;
				$case[$CASE_CFG_FILE] = lc( GetPathFileName($file) );
				$case[$CASE_RUN_TIME_SECONDS] = 0;

                if( IsCaseInCaseList( $case[$CASE_ID] ) )
    			{
        			push @cases, [ @case ];
    		    }
	    	}

	    	$fileCaseCount++;
	    	if($optionShowMessages) { print(" - Case: " . $caseName . "\n"); };
	    }
	}

	return $fileCaseCount;
}


#------------------------------------------------------------------------------------
# ReadCaseAndDescText
#
# Parameters:
#	$lines
#	$caseInfo
#	$startIndex
#------------------------------------------------------------------------------------
sub ReadCaseAndDescText
{
	my ($lines, $caseInfo, $startIndex) = @_;
	my $lineCount = @{$lines};

	my $readLines = 0;
	my $i = 0;

	@{$caseInfo}[0] = "N/A";

	for($i=$startIndex; $i<$lineCount; $i++)
	{
		my $line = @{$lines}[$i];

		@{$caseInfo}[ scalar(@{$caseInfo}) ] = $line;

		#print($line . "\n");

		if($line =~ m/\[Endtest\]/i)
		{
#				push @cases, [ @case ];

			#foreach $xxx (@{$caseInfo})	{		print("XXX: " . $xxx . "");	}

			return $readLines;
		}

		$readLines++;
	}

	return $readLines;
}

#------------------------------------------------------------------------------------
# ReadCase
#
# Parameters:
#	$lines
#	$startIndex
#	$file
#------------------------------------------------------------------------------------
sub ReadCase
{
	my ($lines, $startIndex, $file) = @_;
	my $lineCount = @{$lines};

	my $readLines = 0;
	my $i = 0;

	my $caseName = "";
	my $casePurpose = "";
	my $caseMeans = "";
	my $caseRequiredSettings = "";
	my $caseRelatedRequirements = "";
	my $caseVerification = "";
	my $caseNote = "";

	#this is where text is appended if it's on a line which has no description tag
	# -> multiline descriptions can be specified
	my $refAppend = 0;

	for($i=$startIndex; $i<$lineCount; $i++)
	{
		my $line = @{$lines}[$i];

		#print($line . "\n");

		RemoveWhiteSpaces(\$line);
		#$line =~ s/\s+$//; #whitespaces in the end
		#$line =~ s/^\s+//; #whitespaces at the start

		if($line =~ m/^\#\[EndIptvETDescription\]/)
		{
			#print(" ***** End case\n");

			my @case;

			$case[$CASE_NAME] = $caseName;
			$case[$CASE_ID] = GetCaseIdFromName($caseName);

			$case[$CASE_RUN_TIMES] = 0;
			$case[$CASE_CRASHED] = 0;
			$case[$CASE_FAILED] = 0;
			$case[$CASE_PASSED] = 0;
			$case[$CASE_STATUS] = "$caseDefaultStatus";
			$case[$CASE_PURPOSE] = $casePurpose;
			$case[$CASE_MEANS] = $caseMeans;
			$case[$CASE_REQUIRED_SETTINGS] = $caseRequiredSettings;
			$case[$CASE_RELATED_REQUIREMENTS] = $caseRelatedRequirements;
			$case[$CASE_VERIFICATION] = $caseVerification;
			$case[$CASE_NOTE] = $caseNote;
			$case[$CASE_REASON] = "";
			$case[$CASE_RESULT] = "";
			$case[$CASE_LOG_FILE] = "";
			$case[$CASE_LOG_FILE_SCRIPTER] = "";
			$case[$CASE_CHECK_RESULT_LOG_FILE] = 0;
			$case[$CASE_CFG_FILE] = $file;
			$case[$CASE_RUN_TIME_SECONDS] = 0;

            if( IsCaseInCaseList( $case[$CASE_ID] ) )
			{
    			push @cases, [ @case ];
			}

			return $readLines;
		}

		elsif($line =~ m/^\# Testname:/)
		{
			$caseName = substr($line, length("# Testname:"));
			RemoveWhiteSpaces(\$caseName);
			#SpecialChars(\$caseName);
			$refAppend = \$caseName;
		}

		elsif($line =~ m/^\# Purpose:/)
		{
			$casePurpose = substr($line, length("# Purpose:"));
			RemoveWhiteSpaces(\$casePurpose);
			#SpecialChars(\$casePurpose);
			$refAppend = \$casePurpose;
		}

		elsif($line =~ m/^\# Means:/)
		{
			$caseMeans = substr($line, length("# Means:"));
			RemoveWhiteSpaces(\$caseMeans);
			#SpecialChars(\$caseMeans);
			$refAppend = \$caseMeans;
		}

		elsif($line =~ m/^\# Required environment settings:/)
		{
			$caseRequiredSettings = substr($line, length("# Required environment settings:"));
			RemoveWhiteSpaces(\$caseRequiredSettings);
			#SpecialChars(\$caseRequiredSettings);
			$refAppend = \$caseRequiredSettings;
		}

		elsif($line =~ m/^\# Related requirements:/)
		{
			$caseRelatedRequirements = substr($line, length("# Related requirements:"));
			RemoveWhiteSpaces(\$caseRelatedRequirements);
			$refAppend = \$caseRelatedRequirements;
		}

		elsif($line =~ m/^\# Verification:/)
		{
			$caseVerification = substr($line, length("# Verification:"));
			RemoveWhiteSpaces(\$caseVerification);
			$refAppend = \$caseVerification;
		}

		elsif($line =~ m/^\# Note:/)
		{
			$caseNote = substr($line, length("# Note:"));
			RemoveWhiteSpaces(\$caseNote);
			$refAppend = \$caseNote;
		}

		elsif($line =~ m/^\#/)
		{
			my $text = substr($line, length("#"));
			RemoveWhiteSpaces(\$text);
			#print(" ***** JOTTAI MUuTA: " . $text. "\n");
			${$refAppend} .= " " . $text;

			RemoveWhiteSpaces($refAppend);

		}

		$readLines++;
	}

	return $readLines;
}

#------------------------------------------------------------------------------------
# GetCaseIdFromName
#
# Parameters:
#	$caseName
#------------------------------------------------------------------------------------
sub GetCaseIdFromName
{
	my ($caseName) = @_;

	return "NOID" if(!defined($caseName) || $caseName eq "");

	RemoveWhiteSpaces(\$caseName);
	#SpecialChars(\$caseName);

	if($caseName =~ m/(ET[0-9]+)[ ]+/)
	{
		return $1;
	}

	return $caseName;
}

#------------------------------------------------------------------------------------
# GetCaseField
#
# Parameters:
#	$caseName
#	$caseField
#------------------------------------------------------------------------------------
sub GetCaseField
{
	my ($caseNameOrId, $caseField) = @_;

	my $ret = "";

	foreach my $case(@cases)
	{
		if(@{$case}[$CASE_NAME] eq $caseNameOrId or @{$case}[$CASE_ID] eq $caseNameOrId)
		{
			if( defined(@{$case}[$caseField]) )
			{
				$ret = @{$case}[$caseField];
			}
		}
	}

	return $ret;
}

#------------------------------------------------------------------------------------
# GetCaseByNameOnly
#
# Parameters:
#	$caseName
#
# Removes the case IDs from case names and tries to find case from @cases array
#------------------------------------------------------------------------------------
sub GetCaseByNameOnly
{
	my ($caseName) = @_;

	my $startPos = index($caseName, " ");
	$caseName  = substr($caseName, $startPos) if($startPos != -1);

	RemoveWhiteSpaces(\$caseName);

	for(my $i = 0; $i<scalar(@cases); $i++)
	{
		my $name = $cases[$i][$CASE_NAME];
		$startPos = index($name, " ");
		return if($startPos == -1);
		$name  = substr($name, $startPos);
		RemoveWhiteSpaces(\$name);

		return $cases[$i] if($name eq $caseName);
	}
	return;
}

#------------------------------------------------------------------------------------
# GetCase
#
# Parameters:
#	$caseNameOrID
#
# Returns reference to case
#------------------------------------------------------------------------------------
sub GetCase
{
	my ($caseNameOrID, $refCases) = @_;

	for(my $i = 0; $i<scalar(@$refCases); $i++)
	{
        $case = @$refCases[$i];
		if(@$case[$CASE_NAME] eq $caseNameOrID or @$case[$CASE_ID] eq $caseNameOrID)
		{
			return $case;
		}
	}
	return;
}

#------------------------------------------------------------------------------------
# GetCaseDesc
#
# Parameters:
#	$caseNameOrID
#
# Returns reference to casedesc
#------------------------------------------------------------------------------------
sub GetCaseDesc
{
	my ($caseNameOrID) = @_;

	for(my $i=0; $i<scalar(@caseDescs); $i++)
	{
		if($caseDescs[$i][0] eq $caseNameOrID || $caseDescs[$i][0] eq $caseNameOrID)
		{
			return $caseDescs[$i];
		}
	}
	return;
}

#------------------------------------------------------------------------------------
# RemoveWhiteSpaces
#
# Parameters:
# 	$text
#------------------------------------------------------------------------------------
sub RemoveWhiteSpaces()
{
	my ($text) = @_;
	${$text} =~ s/\s+$//; #whitespaces in the end
	${$text} =~ s/^\s+//; #whitespaces at the start
}

#------------------------------------------------------------------------------------
# XmlReadyText
#
# Parameters:
# 	$text
#------------------------------------------------------------------------------------
sub XmlReadyText
{
	my ($text) = @_;

	$txtlt = "&lt;";
	$txtgt = "&gt;";
	${$text} =~ s/</$txtlt/g;
	${$text} =~ s/>/$txtgt/g;

	${$text} =~ s/Ä/&Auml/g;
	${$text} =~ s/ä/&auml/g;
	${$text} =~ s/Ö/&Ouml/g;
	${$text} =~ s/ö/&ouml/g;

	#ä &auml;

#	Ö &Ouml;

#	ö &ouml;

}

#------------------------------------------------------------------------------------
# SpecialChars
#
# Parameters:
# 	$text
#------------------------------------------------------------------------------------
sub SpecialChars
{
	my ($text) = @_;


	ReplaceChar($text, "etmerkki#39;", "'" );
	ReplaceChar($text, "etmerkkiamp;", "&" );
	ReplaceChar($text, "etmerkkiacute;", "´" );

	ReplaceChar($text, "etmerkkilsquo;", "‘" );
	ReplaceChar($text, "etmerkkirsquo;", "’" );
	ReplaceChar($text, "etmerkkisbquo;", "‚" );
	ReplaceChar($text, "etmerkkildquo;", "“" );
	ReplaceChar($text, "etmerkkirdquo;", "”" );
	ReplaceChar($text, "etmerkkibdquo;", "„" );
	ReplaceChar($text, "etmerkki#34;", "\"" );

	ReplaceChar($text, "etmerkki#40;", "(" );
	ReplaceChar($text, "etmerkki#41;", ")" );

	ReplaceChar($text, "etmerkkifrasl;", "/" );
	ReplaceChar($text, "etmerkkilt;", "<" );
	ReplaceChar($text, "etmerkkigt;", ">" );
	ReplaceChar($text, "etmerkki#166;" , "¦" );

	ReplaceChar($text, "etmerkkipara;", "¶" );
	ReplaceChar($text, "etmerkkimiddot;", "·" );
	ReplaceChar($text, "etmerkkifrac14;", "¼" );
	ReplaceChar($text, "etmerkkifrac12;", "½" );
	ReplaceChar($text, "etmerkkifrac34;" , "¾" );


	${$text} =~ s/etmerkki/&/g;

	#	print("TEXT: " . ${$text} . "\n");
}

#------------------------------------------------------------------------------------
# ReplaceChar
#
# Parameters:
# 	$text
#	$replacement
#	$char
#------------------------------------------------------------------------------------
sub ReplaceChar
{
	my ($text, $replacement, $char) = @_;

#	print("txt: " . ${$text} . "char: " . $char . ", repl: " . $replacement . "\n");

	while(index(${$text}, $char)  != -1)
	{
		my $pos = index(${$text}, $char);
		if($pos < 0) { $pos = 0 };

		$str1 = substr(${$text}, 0, $pos);
		$str2 = substr(${$text}, $pos+1);

#		print "STR: '" .  $str1 . "' - '" . $str2 . "'\n";

#		print "XXX: " . $str1 . $replacement .  $str2 . "\n";

		${$text} = $str1 . $replacement . $str2;;
	}
}

#------------------------------------------------------------------------------------
# PrintCases
#------------------------------------------------------------------------------------
sub PrintCases
{

	my ($fileName) = @_;

	my @buff;

	push @buff, ("Name, Status, LogFile\n");

	my $i;

	push @buff, ("----------------------------------------\nCASES\n--------------------------------------\n");
	foreach $case(@cases)
	{

		#	my $case = $cases[$i];
		if(0 or @{$case}[$CASE_STATUS] ne "$caseDefaultStatus")
			{

			push @buff, (@{$case}[$CASE_NAME] . " ");
			#@{$case}[$CASE_RUN_TIMES]
			#@{$case}[$CASE_CRASHED]
			#@{$case}[$CASE_FAILED]
			#@{$case}[$CASE_PASSED]
			push @buff, (@{$case}[$CASE_STATUS] . " ");
			#@{$case}[$CASE_PURPOSE]
			#@{$case}[$CASE_MEANS]
			#@{$case}[$CASE_REQUIRED_SETTINGS]
			#@{$case}[$CASE_RELATED_REQUIREMENTS]
			#@{$case}[$CASE_VERIFICATION]
			#@{$case}[$CASE_NOTE]
			#@{$case}[$CASE_REASON]
			#@{$case}[$CASE_RESULT]
			push @buff, ("file: " . @{$case}[$CASE_LOG_FILE]  . " ");

			push @buff, ("check log: " . @{$case}[$CASE_CHECK_RESULT_LOG_FILE]  . " ");

			push @buff, ("\n");

			}
	}

	open(XXX, ">" . $fileName);
	print XXX ( @buff );
	close(XXX);

}

#------------------------------------------------------------------------------------
# FindFiles
# Parameters:
#	$goDir, where to start finding
#	$fileSearch, filename search
#	$searchType, 0 = fullname search, 1 = filetype search
#	$refIncfiles, reference to array which will hold found files
#------------------------------------------------------------------------------------
sub FindFiles
{
	my ($godir, $fileSearch, $searchType, $refIncfiles) = @_;

	my $startDir = cwd;

	chdir($godir) or die("Could not change dir to $godir");

	#print("Now in: " . cwd . "\n");

	opendir(DIR, ".");
	my @filelist = sort(readdir(DIR));
	closedir(DIR);

	foreach my $file(@filelist)
	{
		if($file eq "." or $file eq "..") {next};

		if (-d $file)
		{
		 	FindFiles( $file, $fileSearch, $searchType, $refIncfiles);
		} else
		{
			if( ($file =~ m/$fileSearch/i and $searchType == 0 ) or ($file =~ m/$fileSearch$/i and $searchType == 1 ) )
			{
                $file = cwd . "/" . $file;
				push @$refIncfiles, $file;
				#print("$file\n");
			}
		}
	}

	chdir ($startDir) or die("Could not change dir to $startDir");
}


#------------------------------------------------------------------------------------
# GetAllFiles
# Parameters:
#	$goDir, where to start finding
#	$refIncfiles, reference to array which will hold found files
#   $subDirLevel, how deep in the directories we go to search files. < 0 is no limit.
#------------------------------------------------------------------------------------
sub GetAllFiles
{
	my ($godir, $refIncfiles, $subDirLevel) = @_;

	my $startDir = cwd;

	chdir($godir) or die("Could not change dir to $godir");

	#print("Now in: " . cwd . "\n");

	opendir(DIR, ".");
	my @filelist = sort(readdir(DIR));
	closedir(DIR);

	foreach my $file(@filelist)
	{
		if($file eq "." or $file eq "..") {next};
		
		if (! (-d $file) )
		{
		 	my $path = $startDir . "/" . $file;
		 	push @$refIncfiles, $path;		 	
		} elsif( $subDirLevel > 0 || $subDirLevel < 0 )
		{
			my $backupDir = cwd;
			chdir( $file ) or die("Could not change dir to $file");
			GetAllFiles( $godir, $refIncfiles, $subDirLevel-1 );
			chdir( $backupDir ) or die("Could not change dir to $backupDir");
		}
	}

	chdir ($startDir) or die("Could not change dir to $startDir");
}

#------------------------------------------------------------------------------------
# FindDirs
# Parameters:
#	$goDir, where to start finding
#	$fileSearch, filename search
#	$refIncfiles, reference to array which will hold found files
#------------------------------------------------------------------------------------
sub FindDirs
{
	my ($godir, $fileSearch, $refIncfiles) = @_;

	my $startDir = cwd;

	chdir($godir) or die("Could not change dir to $godir");

	#print("Now in: " . cwd . "\n");

	opendir(DIR, ".");
	my @filelist = sort(readdir(DIR));
	closedir(DIR);

	foreach my $file(@filelist)
	{
		if($file eq "." or $file eq "..") {next};

		if (-d $file)
		{
		    if( $file =~ m/$fileSearch/i )
		    {
		        push @$refIncfiles, (cwd . "/" . $file);
		    }
		 	FindDirs( $file, $fileSearch, $refIncfiles );
		}
	}

	chdir ($startDir) or die("Could not change dir to $startDir");
}

#------------------------------------------------------------------------------------
# GetPathFileName
#
# Parameters:
# 	$str
#------------------------------------------------------------------------------------
sub GetPathFileName
{
    my ($str) = @_;

    my $startPos = rindex($str, "\\");
    if($startPos == -1)
    {
        $startPos = rindex($str, "/");
        return $str if($startPos == -1);
    }

    my $filename = substr($str, $startPos+1);

    return $filename;
}

#------------------------------------------------------------------------------------
# GetPathDir
#
# Parameters:
# 	$str
#------------------------------------------------------------------------------------
sub GetPathDir
{
    my ($str) = @_;

    my $startPos = rindex($str, "\\");
    if($startPos == -1)
    {
        $startPos = rindex($str, "/");
        return $str if($startPos == -1);
    }

    my $filename = substr($str, 0, $startPos);

    return $filename;
}

sub InitXmlData
{

$xmlHeader =
"<?xml version='1.0'?>" .
"<?mso-application progid='Excel.Sheet'?>" .
"<Workbook xmlns='urn:schemas-microsoft-com:office:spreadsheet'" .
" xmlns:o='urn:schemas-microsoft-com:office:office'" .
" xmlns:x='urn:schemas-microsoft-com:office:excel'" .
" xmlns:ss='urn:schemas-microsoft-com:office:spreadsheet'" .
" xmlns:html='http://www.w3.org/TR/REC-html40'>" .
" <DocumentProperties xmlns='urn:schemas-microsoft-com:office:office'>" .
"  <Author>Senbom Petri</Author>" .
"  <LastAuthor>Senbom Petri</LastAuthor>" .
"  <Created>2006-06-09T11:08:05Z</Created>" .
"  <Company>Nokia Oyj</Company>" .
"  <Version>11.6568</Version>" .
" </DocumentProperties>" .
" <ExcelWorkbook xmlns='urn:schemas-microsoft-com:office:excel'>" .
"  <WindowHeight>12210</WindowHeight>" .
"  <WindowWidth>18780</WindowWidth>" .
"  <WindowTopX>360</WindowTopX>" .
"  <WindowTopY>255</WindowTopY>" .
"  <ProtectStructure>False</ProtectStructure>" .
"  <ProtectWindows>False</ProtectWindows>" .
" </ExcelWorkbook>" .
" <Styles>" .
"  <Style ss:ID='Default' ss:Name='Normal'>" .
"   <Alignment ss:Vertical='Bottom'/>" .
"   <Borders/>" .
"   <Font/>" .
"   <Interior/>" .
"   <NumberFormat/>" .
"   <Protection/>" .
"  </Style>" .
"  <Style ss:ID='m155260432'>" .
"   <Alignment ss:Vertical='Top' ss:WrapText='1'/>" .
"   <Borders>" .
"    <Border ss:Position='Bottom' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Left' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Right' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Top' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"   </Borders>" .
"   <Interior ss:Color='#FFFFFF' ss:Pattern='Solid'/>" .
"  </Style>" .
"  <Style ss:ID='m155260442'>" .
"   <Alignment ss:Vertical='Top' ss:WrapText='1'/>" .
"   <Borders>" .
"    <Border ss:Position='Bottom' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Left' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Right' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Top' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"   </Borders>" .
"   <Interior ss:Color='#FFFFFF' ss:Pattern='Solid'/>" .
"  </Style>" .
"  <Style ss:ID='m155266416'>" .
"   <Alignment ss:Vertical='Bottom'/>" .
"   <Borders>" .
"    <Border ss:Position='Bottom' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Left' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Right' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Top' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"   </Borders>" .
"   <Font x:Family='Swiss' ss:Bold='1'/>" .
"   <Interior ss:Color='#FFFFFF' ss:Pattern='Solid'/>" .
"  </Style>" .
"  <Style ss:ID='m155266426'>" .
"   <Alignment ss:Vertical='Top' ss:WrapText='1'/>" .
"   <Borders>" .
"    <Border ss:Position='Bottom' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Left' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Right' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Top' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"   </Borders>" .
"   <Interior ss:Color='#FFFFFF' ss:Pattern='Solid'/>" .
"  </Style>" .
"  <Style ss:ID='m155266436'>" .
"   <Alignment ss:Vertical='Top' ss:WrapText='1'/>" .
"   <Borders>" .
"    <Border ss:Position='Bottom' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Left' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Right' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Top' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"   </Borders>" .
"   <Interior ss:Color='#FFFFFF' ss:Pattern='Solid'/>" .
"  </Style>" .
"  <Style ss:ID='m155266446'>" .
"   <Alignment ss:Vertical='Top' ss:WrapText='1'/>" .
"   <Borders>" .
"    <Border ss:Position='Bottom' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Left' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Right' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Top' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"   </Borders>" .
"   <Interior ss:Color='#FFFFFF' ss:Pattern='Solid'/>" .
"  </Style>" .
"  <Style ss:ID='s21'>" .
"   <Alignment ss:Horizontal='Right' ss:Vertical='Bottom'/>" .
"   <Borders>" .
"    <Border ss:Position='Bottom' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Right' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Top' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"   </Borders>" .
"   <Interior ss:Color='#99CCFF' ss:Pattern='Solid'/>" .
"  </Style>" .
"  <Style ss:ID='s25'>" .
"   <Alignment ss:Horizontal='Right' ss:Vertical='Bottom'/>" .
"   <Borders>" .
"    <Border ss:Position='Right' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"   </Borders>" .
"   <Interior ss:Color='#99CCFF' ss:Pattern='Solid'/>" .
"  </Style>" .
"  <Style ss:ID='s26'>" .
"   <Borders>" .
"    <Border ss:Position='Left' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Top' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"   </Borders>" .
"   <Interior ss:Color='#FFFFFF' ss:Pattern='Solid'/>" .
"  </Style>" .
"  <Style ss:ID='s27'>" .
"   <Alignment ss:Horizontal='Center' ss:Vertical='Bottom'/>" .
"   <Borders>" .
"    <Border ss:Position='Top' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"   </Borders>" .
"   <Interior ss:Color='#99CCFF' ss:Pattern='Solid'/>" .
"  </Style>" .
"  <Style ss:ID='s28'>" .
"   <Borders>" .
"    <Border ss:Position='Top' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"   </Borders>" .
"   <Interior ss:Color='#FFFFFF' ss:Pattern='Solid'/>" .
"  </Style>" .
"  <Style ss:ID='s29'>" .
"   <Borders>" .
"    <Border ss:Position='Right' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Top' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"   </Borders>" .
"   <Interior ss:Color='#FFFFFF' ss:Pattern='Solid'/>" .
"  </Style>" .
"  <Style ss:ID='s30'>" .
"   <Alignment ss:Horizontal='Right' ss:Vertical='Top'/>" .
"   <Borders>" .
"    <Border ss:Position='Right' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"   </Borders>" .
"   <Interior ss:Color='#99CCFF' ss:Pattern='Solid'/>" .
"  </Style>" .
"  <Style ss:ID='s34'>" .
"   <Alignment ss:Horizontal='Right' ss:Vertical='Top'/>" .
"   <Borders>" .
"    <Border ss:Position='Bottom' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Right' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"   </Borders>" .
"   <Interior ss:Color='#99CCFF' ss:Pattern='Solid'/>" .
"  </Style>" .
"  <Style ss:ID='s35'>" .
"   <Interior ss:Color='#FFFFFF' ss:Pattern='Solid'/>" .
"  </Style>" .

#failed

"  <Style ss:ID='s36'>" .
"   <Alignment ss:Vertical='Top' ss:WrapText='1'/>" .
"   <Borders>" .
"    <Border ss:Position='Bottom' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Left' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Right' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Top' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"   </Borders>" .
"   <Interior ss:Color='#FFFF00' ss:Pattern='Solid'/>" .
"  </Style>" .

#passed style

"  <Style ss:ID='s37'>" .
"   <Alignment ss:Vertical='Top' ss:WrapText='1'/>" .
"   <Borders>" .
"    <Border ss:Position='Bottom' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Left' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Right' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Top' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"   </Borders>" .
"   <Interior ss:Color='#CCFFCC' ss:Pattern='Solid'/>" .
"  </Style>" .

#crashed style

"  <Style ss:ID='s38'>" .
"   <Alignment ss:Vertical='Top' ss:WrapText='1'/>" .
"   <Borders>" .
"    <Border ss:Position='Bottom' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Left' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Right' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Top' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"   </Borders>" .
"   <Interior ss:Color='#FF6600' ss:Pattern='Solid'/>" .
"  </Style>" .

# UNKNOWN style

"  <Style ss:ID='s401'>" .
"   <Alignment ss:Vertical='Top' ss:WrapText='1'/>" .
"   <Borders>" .
"    <Border ss:Position='Bottom' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Left' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Right' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Top' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"   </Borders>" .
"   <Interior ss:Color='#FF6600' ss:Pattern='Solid'/>" .
"  </Style>" .


#NA style
"  <Style ss:ID='s39'>" .
"   <Alignment ss:Vertical='Top' ss:WrapText='1'/>" .
"   <Borders>" .
"    <Border ss:Position='Bottom' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Left' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Right' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Top' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"   </Borders>" .
"  </Style>" .


#failed centered

"  <Style ss:ID='s36centered'>" .
"   <Alignment ss:Horizontal=\"Center\" ss:Vertical='Top' ss:WrapText='1'/>" .
"   <Borders>" .
"    <Border ss:Position='Bottom' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Left' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Right' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Top' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"   </Borders>" .
"   <Interior ss:Color='#FFFF00' ss:Pattern='Solid'/>" .
"  </Style>" .

#passed style centered

"  <Style ss:ID='s37centered'>" .
"   <Alignment ss:Horizontal=\"Center\" ss:Vertical='Top' ss:WrapText='1'/>" .
"   <Borders>" .
"    <Border ss:Position='Bottom' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Left' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Right' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Top' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"   </Borders>" .
"   <Interior ss:Color='#CCFFCC' ss:Pattern='Solid'/>" .
"  </Style>" .

#crashed style centered

"  <Style ss:ID='s38centered'>" .
"   <Alignment ss:Horizontal=\"Center\" ss:Vertical='Top' ss:WrapText='1'/>" .
"   <Borders>" .
"    <Border ss:Position='Bottom' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Left' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Right' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Top' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"   </Borders>" .
"   <Interior ss:Color='#FF6600' ss:Pattern='Solid'/>" .
"  </Style>" .

# UNKNOWN style centered

"  <Style ss:ID='s401centered'>" .
"   <Alignment ss:Horizontal=\"Center\" ss:Vertical='Top' ss:WrapText='1'/>" .
"   <Borders>" .
"    <Border ss:Position='Bottom' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Left' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Right' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Top' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"   </Borders>" .
"   <Interior ss:Color='#FF6600' ss:Pattern='Solid'/>" .
"  </Style>" .


#NA style centered
"  <Style ss:ID='s39centered'>" .
"   <Alignment ss:Horizontal=\"Center\" ss:Vertical='Top' ss:WrapText='1'/>" .
"   <Borders>" .
"    <Border ss:Position='Bottom' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Left' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Right' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Top' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"   </Borders>" .
"  </Style>" .

#summary style
"  <Style ss:ID='summary'>" .
"   <Alignment ss:Vertical='Top' ss:WrapText='1'/>" .
"   <Borders>" .
"    <Border ss:Position='Bottom' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Left' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Right' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Top' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"   </Borders>" .
"   <Interior ss:Color='#FFFFFF' ss:Pattern='Solid'/>" .
"  </Style>" .

#summary real number style
"  <Style ss:ID='summaryreal'>" .
"   <NumberFormat ss:Format='Fixed'/> ".
"   <Alignment ss:Vertical='Top' ss:WrapText='1'/>" .
"   <Borders>" .
"    <Border ss:Position='Bottom' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Left' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Right' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Top' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"   </Borders>" .
"   <Interior ss:Color='#FFFFFF' ss:Pattern='Solid'/>" .
"  </Style>" .

#summary header
"  <Style ss:ID='summary_header'>" .
"   <Alignment ss:Horizontal='Left' ss:Vertical='Bottom'/>" .
"   <Borders>" .
"    <Border ss:Position='Bottom' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Right' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Top' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"   </Borders>" .
"   <Font x:Family='Swiss' ss:Bold='1'/>" .
"  </Style>" .

#brief header
"  <Style ss:ID='brief_header'>" .
"   <Alignment ss:Horizontal='Center' ss:Vertical='Bottom'/>" .
"   <Borders>" .
"    <Border ss:Position='Bottom' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Right' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Top' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"   </Borders>" .
"   <Interior ss:Color='#99CCFF' ss:Pattern='Solid'/>" .
"  </Style>" .

"  <Style ss:ID='brief_heading_cfgfilename'>" .
"   <Alignment ss:Vertical='Bottom'/>" .
"   <Borders>" .
"    <Border ss:Position='Bottom' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Left' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Right' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"    <Border ss:Position='Top' ss:LineStyle='Continuous' ss:Weight='1'/>" .
"   </Borders>" .
"   <Font x:Family='Swiss' ss:Bold='1'/>" .
"   <Interior ss:Color='#CCFFCC' ss:Pattern='Solid'/>" .
"  </Style>" .

#link
"  <Style ss:ID='urlparent' ss:Name='Hyperlink'>" .
"   <Font ss:Color='#0000FF' ss:Underline='Single'/>" .
"  </Style>" .

"  <Style ss:ID='url' ss:Parent='urlparent'>" .
"   <Interior ss:Color='#FFFFFF' ss:Pattern='Solid'/>" .
"  </Style>" .

" </Styles>" .
" <Worksheet ss:Name='Sheet1'>";

$xmlHeaderTableColumns =
"  <Table ss:ExpandedColumnCount='18' ss:ExpandedRowCount='CASE_COUNT_MUL8' x:FullColumns='1'" .
"   x:FullRows='1'>" .
"   <Column ss:AutoFitWidth='0' ss:Width='138.75'/>" .
"   <Column ss:Index='3' ss:AutoFitWidth='0' ss:Width='39'/>" .
"   <Column ss:Index='5' ss:AutoFitWidth='0' ss:Width='39'/>" .
"   <Column ss:Index='7' ss:AutoFitWidth='0' ss:Width='39'/>" .
"   <Column ss:Index='16' ss:AutoFitWidth='0' ss:Width='26.25'/>" .
"   <Column ss:AutoFitWidth='0' ss:Width='15'/>" .
"   <Column ss:AutoFitWidth='0' ss:Width='525.75'/>\n\n";

$xmlHeaderTableColumnsBrief =
"  <Table ss:ExpandedColumnCount='25' ss:ExpandedRowCount='CASE_COUNT_MUL8' x:FullColumns='1'" .
"   x:FullRows='1'>" .
"   <Column ss:AutoFitWidth='0' ss:Width='138.75'/>" .
"   <Column ss:Index='2' ss:AutoFitWidth='0' ss:Width='39'/>" .
"   <Column ss:Index='3' ss:AutoFitWidth='0' ss:Width='39'/>" .
"   <Column ss:Index='4' ss:AutoFitWidth='0' ss:Width='39'/>" .
"   <Column ss:Index='5' ss:AutoFitWidth='0' ss:Width='39'/>" .
"   <Column ss:Index='6' ss:AutoFitWidth='0' ss:Width='39'/>" .
"   <Column ss:Index='7' ss:AutoFitWidth='0' ss:Width='65'/>" . #status
"   <Column ss:Index='8' ss:AutoFitWidth='0' ss:Width='39'/>" .
"   <Column ss:Index='9' ss:AutoFitWidth='0' ss:Width='39'/>" .
"   <Column ss:Index='12' ss:AutoFitWidth='0' ss:Width='260'/>" . # info
"   <Column ss:Index='13' ss:AutoFitWidth='0' ss:Width='26.25'/>" . # link1
"   <Column ss:Index='14' ss:AutoFitWidth='0' ss:Width='26.25'/>" . # link2
"   <Column ss:Index='16' ss:AutoFitWidth='0' ss:Width='26.25'/>" .
"   <Column ss:AutoFitWidth='0' ss:Width='15'/>" .
"   <Column ss:AutoFitWidth='0' ss:Width='525.75'/>\n\n";

$xmlHeaderTableColumnsAlt =
"  <Table ss:ExpandedColumnCount='25' ss:ExpandedRowCount='CASE_COUNT_MUL8' x:FullColumns='1'" .
"   x:FullRows='1'>" .
"   <Column ss:AutoFitWidth=\"0\" ss:Width=\"138.75\"/>" .
"   <Column ss:AutoFitWidth=\"0\" ss:Width=\"30\" ss:Span=\"4\"/>" .
"   <Column ss:Index=\"7\" ss:AutoFitWidth=\"0\" ss:Width=\"60.00\" ss:Span=\"9\"/>" .
"   <Column ss:Index=\"17\" ss:AutoFitWidth=\"0\" ss:Width=\"15\"/>" .
"   <Column ss:AutoFitWidth=\"0\" ss:Width=\"525.75\"/>";

$xmlFooter =

"  </Table>" .
"  <WorksheetOptions xmlns='urn:schemas-microsoft-com:office:excel'>" .

#splitted panes
#"  <Selected/>" .
#"   <SplitHorizontal>3060</SplitHorizontal>" .
#"   <TopRowBottomPane>11</TopRowBottomPane>" .
#"   <ActivePane>2</ActivePane>" .
#"   <Panes>" .
#"    <Pane>" .
#"     <Number>3</Number>" .
#"    </Pane>" .
#"    <Pane>" .
#"     <Number>2</Number>" .
#"     <RangeSelection>R12C1:R12C8</RangeSelection>" .
#"    </Pane>" .
#"   </Panes>" .

#not splitted
"   <Selected/>" .
"   <Panes>" .
"    <Pane>" .
"     <Number>3</Number>" .
"     <ActiveRow>7</ActiveRow>" .
"     <ActiveCol>2</ActiveCol>" .
"    </Pane>" .
"   </Panes>" .

"   <ProtectObjects>False</ProtectObjects>" .
"   <ProtectScenarios>False</ProtectScenarios>" .
"  </WorksheetOptions>" .
" </Worksheet>" .
" <Worksheet ss:Name='Sheet2'>" .
"  <WorksheetOptions xmlns='urn:schemas-microsoft-com:office:excel'>" .
"   <ProtectObjects>False</ProtectObjects>" .
"   <ProtectScenarios>False</ProtectScenarios>" .
"  </WorksheetOptions>" .
" </Worksheet>" .
" <Worksheet ss:Name='Sheet3'>" .
"  <WorksheetOptions xmlns='urn:schemas-microsoft-com:office:excel'>" .
"   <ProtectObjects>False</ProtectObjects>" .
"   <ProtectScenarios>False</ProtectScenarios>" .
"  </WorksheetOptions>" .
" </Worksheet>" .
"</Workbook>\n\n";

$xmlDataEmptyRow =
"   <Row>" .
"    <Cell ss:StyleID='s35'><Data ss:Type='String'></Data></Cell>" .
"    <Cell ss:StyleID='s35'/>" .
"    <Cell ss:StyleID='s35'/>" .
"    <Cell ss:StyleID='s35'/>" .
"    <Cell ss:StyleID='s35'/>" .
"    <Cell ss:StyleID='s35'/>" .
"    <Cell ss:StyleID='s35'/>" .
"    <Cell ss:StyleID='s35'/>" .
"    <Cell ss:StyleID='s35'/>" .
"    <Cell ss:StyleID='s35'/>" .
"    <Cell ss:StyleID='s35'/>" .
"    <Cell ss:StyleID='s35'/>" .
"    <Cell ss:StyleID='s35'/>" .
"    <Cell ss:StyleID='s35'/>" .
"    <Cell ss:StyleID='s35'/>" .
"    <Cell ss:StyleID='s35'/>" .
"    <Cell ss:StyleID='s35'/>" .
"    <Cell ss:StyleID='s35'/>" .
"   </Row>\n\n";

$xmlSummaryData =

$xmlDataEmptyRow .

"   <Row>" .
"    <Cell ss:StyleID='s35' ss:MergeAcross='20'>" . "<Data ss:Type='String'>INSERT TEST SOFTWARE HERE</Data></Cell>" .
"   </Row>\n\n" .

"   <Row>" .
"    <Cell ss:StyleID='s35' ss:MergeAcross='20'>" . "<Data ss:Type='String'>INSERT TEST DEVICE HERE</Data></Cell>" .
"   </Row>\n\n" .

$xmlDataEmptyRow .

"   <Row>\n" .
"    <Cell ss:MergeAcross='4' ss:StyleID='summary_header'><Data ss:Type='String'>Test Execution Metrics</Data></Cell>" .
"    <Cell ss:MergeAcross='12' ss:StyleID='s35'/>\n" .
"   </Row>\n" .
"   <Row>\n" .
"    <Cell ss:StyleID='s25'><Data ss:Type='String'>Total cases:</Data></Cell>" .
"    <Cell ss:MergeAcross='3' ss:StyleID='summary'><Data ss:Type='Number'>$xmlDataSummaryCaseCount</Data></Cell>" .
"    <Cell ss:MergeAcross='12' ss:StyleID='s35'/>\n" .
"   </Row>\n" .
"   <Row>\n" .
"    <Cell ss:StyleID='s25'><Data ss:Type='String'>Passed:</Data></Cell>" .
"    <Cell ss:MergeAcross='3' ss:StyleID='summary'><Data ss:Type='Number'>$xmlDataSummaryPassed</Data></Cell>" .
"    <Cell ss:MergeAcross='12' ss:StyleID='s35'/>\n" .
"   </Row>\n" .
"   <Row>\n" .
"    <Cell ss:StyleID='s25'><Data ss:Type='String'>Failed:</Data></Cell>" .
"    <Cell ss:MergeAcross='3' ss:StyleID='summary'><Data ss:Type='Number'>$xmlDataSummaryFailed</Data></Cell>" .
"    <Cell ss:MergeAcross='12' ss:StyleID='s35'/>\n" .
"   </Row>\n" .
"   <Row>\n" .
"    <Cell ss:StyleID='s25'><Data ss:Type='String'>Crashed:</Data></Cell>" .
"    <Cell ss:MergeAcross='3' ss:StyleID='summary'><Data ss:Type='Number'>$xmlDataSummaryCrashed</Data></Cell>" .
"    <Cell ss:MergeAcross='12' ss:StyleID='s35'/>\n" .
"   </Row>\n" .
"   <Row>\n" .
"    <Cell ss:StyleID='s25'><Data ss:Type='String'>Timeout:</Data></Cell>" .
"    <Cell ss:MergeAcross='3' ss:StyleID='summary'><Data ss:Type='Number'>$xmlDataSummaryTimeout</Data></Cell>" .
"    <Cell ss:MergeAcross='12' ss:StyleID='s35'/>\n" .
"   </Row>\n" .
"   <Row>\n" .
"    <Cell ss:StyleID='s25'><Data ss:Type='String'>Pass rate % (total cases):</Data></Cell>" .
"    <Cell ss:MergeAcross='3' ss:StyleID='summaryreal'><Data ss:Type='Number'>$xmlDataSummaryPassRateTotal</Data></Cell>" .
"    <Cell ss:MergeAcross='12' ss:StyleID='s35'/>\n" .
"   </Row>\n" .
"   <Row>\n" .
"    <Cell ss:StyleID='s25'><Data ss:Type='String'>Pass rate % (run cases):</Data></Cell>" .
"    <Cell ss:MergeAcross='3' ss:StyleID='summaryreal'><Data ss:Type='Number'>$xmlDataSummaryPassRateRun</Data></Cell>" .
"    <Cell ss:MergeAcross='12' ss:StyleID='s35'/>\n" .
"   </Row>\n" .
"   <Row>\n" .
"    <Cell ss:StyleID='s25'><Data ss:Type='String'>Run rate %:</Data></Cell>" .
"    <Cell ss:MergeAcross='3' ss:StyleID='summaryreal'><Data ss:Type='Number'>$xmlDataSummaryRunRate</Data></Cell>" .
"    <Cell ss:MergeAcross='12' ss:StyleID='s35'/>\n" .
"   </Row>\n" .
 $xmlDataEmptyRow;

$xmlData =
"   <Row>" .
"    <Cell ss:StyleID='s21'><Data ss:Type='String'>Name:</Data></Cell>" .
"    <Cell ss:MergeAcross='15' ss:StyleID='m155266416'><Data ss:Type='String'>XML_DATA_CASE_NAME</Data></Cell>" .
"    <Cell ss:StyleID='s35'/>" .
"   </Row>";

# not included in the case documentation report
$xmlDataCaseStatusDisabled =
"   <Row>" .
"    <Cell ss:StyleID='s25'><Data ss:Type='String'>Run times:</Data></Cell>" .
"    <Cell ss:StyleID='s26'><Data ss:Type='Number'>XML_DATA_CASE_RUN_TIMES</Data></Cell>" .
#
"    <Cell ss:StyleID='s27'><Data ss:Type='String'>Crashed</Data></Cell>" .
"    <Cell ss:StyleID='s28'><Data ss:Type='Number'>XML_DATA_CASE_CRASHED</Data></Cell>" .

"    <Cell ss:StyleID='s27'><Data ss:Type='String'>Failed</Data></Cell>" .
"    <Cell ss:StyleID='s28'><Data ss:Type='Number'>XML_DATA_CASE_FAILED</Data></Cell>" .
"    <Cell ss:StyleID='s27'><Data ss:Type='String'>Passed</Data></Cell>" .
"    <Cell ss:StyleID='s28'><Data ss:Type='Number'>XML_DATA_CASE_PASSED</Data></Cell>" .
"    <Cell ss:StyleID='s27'><Data ss:Type='String'>Status</Data></Cell>" .
#orig status style id s28
"    <Cell ss:StyleID='STYLE_ID_STATUS'><Data ss:Type='String'>XML_DATA_CASE_STATUS</Data></Cell>" .
"    <Cell ss:StyleID='s28'/>" .
"    <Cell ss:StyleID='s28'/>" .
"    <Cell ss:StyleID='s28'/>" .
"    <Cell ss:StyleID='s28'/>" .
"    <Cell ss:StyleID='s28'/>" .
"    <Cell ss:StyleID='s28'/>" .
"    <Cell ss:StyleID='s28'/>" .
#"    <Cell ss:StyleID='s28'/>" .
#"    <Cell ss:StyleID='s29'/>" .
"    <Cell ss:StyleID='s35'/>" .
"   </Row>\n\n";
$xmlDataCaseStatusDisabled .= "";

$xmlData2 =
"   <Row ss:AutoFitHeight='0' ss:Height='30'>" .
"    <Cell ss:StyleID='s30'><Data ss:Type='String'>Purpose:</Data></Cell>" .
"    <Cell ss:MergeAcross='15' ss:StyleID='m155266426'><Data ss:Type='String'>XML_DATA_CASE_PURPOSE</Data></Cell>" .
"    <Cell ss:StyleID='s35'/>" .
"   </Row>" .
"   <Row ss:AutoFitHeight='0' ss:Height='30'>" .
"    <Cell ss:StyleID='s30'><Data ss:Type='String'>Means:</Data></Cell>" .
"    <Cell ss:MergeAcross='15' ss:StyleID='m155266436'><Data ss:Type='String'>XML_DATA_CASE_MEANS</Data></Cell>" .
"    <Cell ss:StyleID='s35'/>" .
"   </Row>" .
"   <Row ss:AutoFitHeight='0' ss:Height='30'>" .
"    <Cell ss:StyleID='s30'><Data ss:Type='String'>Required environment settings:</Data></Cell>" .
"    <Cell ss:MergeAcross='15' ss:StyleID='m155266446'><Data ss:Type='String'>XML_DATA_CASE_REQUIRED_SETTINGS</Data></Cell>" .
"    <Cell ss:StyleID='s35'/>" .
"   </Row>" .
"   <Row ss:AutoFitHeight='0' ss:Height='30'>" .
"    <Cell ss:StyleID='s30'><Data ss:Type='String'>Related requirements:</Data></Cell>" .
"    <Cell ss:MergeAcross='15' ss:StyleID='m155266446'><Data ss:Type='String'>XML_DATA_CASE_RELATED_REQUIREMENTS</Data></Cell>" .
"    <Cell ss:StyleID='s35'/>" .
"   </Row>" .

"   <Row ss:AutoFitHeight='0' ss:Height='30'>" .
"    <Cell ss:StyleID='s30'><Data ss:Type='String'>Verification:</Data></Cell>" .
"    <Cell ss:MergeAcross='15' ss:StyleID='m155260432'><Data ss:Type='String'>XML_DATA_CASE_VERIFICATION</Data></Cell>" .
"    <Cell ss:StyleID='s35'/>" .
"   </Row>" .
"   <Row ss:AutoFitHeight='0' ss:Height='30'>" .
"    <Cell ss:StyleID='s34'><Data ss:Type='String'>Note:</Data></Cell>" .
"    <Cell ss:MergeAcross='15' ss:StyleID='m155260442'><Data ss:Type='String'>XML_DATA_CASE_NOTE</Data></Cell>" .
"    <Cell ss:StyleID='s35'/>" .
"   </Row>\n\n";


$xmlDataBriefHeader =
"   <Row>" .
"    <Cell ss:MergeAcross='5' ss:StyleID='brief_header'><Data ss:Type='String'>Name</Data></Cell>" .
"    <Cell ss:StyleID='brief_header'><Data ss:Type='String'>Status</Data></Cell>" .
"    <Cell ss:StyleID='brief_header'><Data ss:Type='String'>Passes</Data></Cell>" .
"    <Cell ss:StyleID='brief_header'><Data ss:Type='String'>Fails</Data></Cell>" .
"    <Cell ss:StyleID='brief_header'><Data ss:Type='String'>Crashes</Data></Cell>" .
"    <Cell ss:StyleID='brief_header'><Data ss:Type='String'>Result</Data></Cell>" .
"    <Cell ss:StyleID='brief_header'><Data ss:Type='String'>Info</Data></Cell>" .
"    <Cell ss:MergeAcross='6' ss:StyleID='s35'/>" .
"   </Row>\n\n";

$xmlDataBriefNoLinks =
"   <Row>\n" .
"    <Cell ss:MergeAcross='5' ss:StyleID='m155266416'><Data ss:Type='String'>XML_DATA_CASE_NAME</Data></Cell>\n" .
"    <Cell ss:StyleID='STYLE_ID_STATUS'><Data ss:Type='String'>XML_DATA_CASE_STATUS</Data></Cell>\n" .
"    <Cell ss:StyleID='s39'><Data ss:Type='Number'>XML_DATA_CASE_PASSED</Data></Cell>\n" .
"    <Cell ss:StyleID='s39'><Data ss:Type='Number'>XML_DATA_CASE_FAILED</Data></Cell>\n" .
"    <Cell ss:StyleID='s39'><Data ss:Type='Number'>XML_DATA_CASE_CRASHED</Data></Cell>\n" .
"    <Cell ss:StyleID='s39'><Data ss:Type='Number'>XML_DATA_CASE_RESULT</Data></Cell>\n" .
"    <Cell ss:StyleID='s39'><Data ss:Type='String'>XML_DATA_CASE_REASON</Data></Cell>\n" .
"    <Cell ss:MergeAcross='7' ss:StyleID='s35'/>\n" .
"   </Row>\n\n";

$xmlDataBrief1Link =
"   <Row>\n" .
"    <Cell ss:MergeAcross='5' ss:StyleID='m155266416'><Data ss:Type='String'>XML_DATA_CASE_NAME</Data></Cell>\n" .
"    <Cell ss:StyleID='STYLE_ID_STATUS'><Data ss:Type='String'>XML_DATA_CASE_STATUS</Data></Cell>\n" .
"    <Cell ss:StyleID='s39'><Data ss:Type='Number'>XML_DATA_CASE_PASSED</Data></Cell>\n" .
"    <Cell ss:StyleID='s39'><Data ss:Type='Number'>XML_DATA_CASE_FAILED</Data></Cell>\n" .
"    <Cell ss:StyleID='s39'><Data ss:Type='Number'>XML_DATA_CASE_CRASHED</Data></Cell>\n" .
"    <Cell ss:StyleID='s39'><Data ss:Type='Number'>XML_DATA_CASE_RESULT</Data></Cell>\n" .
"    <Cell ss:StyleID='s39'><Data ss:Type='String'>XML_DATA_CASE_REASON</Data></Cell>\n" .
"    <Cell ss:StyleID='url' ss:HRef='XML_DATA_CASE_LINK1'><Data ss:Type='String'>Link</Data></Cell>\n" .
"    <Cell ss:MergeAcross='6' ss:StyleID='s35'/>\n" .
"   </Row>\n\n";

$xmlDataBrief2Links =
"   <Row>\n" .
"    <Cell ss:MergeAcross='5' ss:StyleID='m155266416'><Data ss:Type='String'>XML_DATA_CASE_NAME</Data></Cell>\n" .
"    <Cell ss:StyleID='STYLE_ID_STATUS'><Data ss:Type='String'>XML_DATA_CASE_STATUS</Data></Cell>\n" .
"    <Cell ss:StyleID='s39'><Data ss:Type='Number'>XML_DATA_CASE_PASSED</Data></Cell>\n" .
"    <Cell ss:StyleID='s39'><Data ss:Type='Number'>XML_DATA_CASE_FAILED</Data></Cell>\n" .
"    <Cell ss:StyleID='s39'><Data ss:Type='Number'>XML_DATA_CASE_CRASHED</Data></Cell>\n" .
"    <Cell ss:StyleID='s39'><Data ss:Type='Number'>XML_DATA_CASE_RESULT</Data></Cell>\n" .
"    <Cell ss:StyleID='s39'><Data ss:Type='String'>XML_DATA_CASE_REASON</Data></Cell>\n" .
"    <Cell ss:StyleID='url' ss:HRef='XML_DATA_CASE_LINK1'><Data ss:Type='String'>Link</Data></Cell>\n" .
"    <Cell ss:StyleID='url' ss:HRef='XML_DATA_CASE_LINK2'><Data ss:Type='String'>Link</Data></Cell>\n" .
"    <Cell ss:MergeAcross='5' ss:StyleID='s35'/>\n" .
"   </Row>\n\n";

$xmlCfgFileBrief =
"   <Row>" .
"    <Cell ss:MergeAcross='11' ss:StyleID='brief_heading_cfgfilename'><Data ss:Type='String'>XML_DATA_CFG_FILE</Data></Cell>" .
"    <Cell ss:MergeAcross='6' ss:StyleID='s35'/>" .
"   </Row>\n\n";


$xmlCfgFileAltHeader =
"   <Row>" .
"    <Cell ss:MergeAcross='5' ss:StyleID='brief_header'><Data ss:Type='String'>Name</Data></Cell>" .
"    <Cell ss:StyleID='brief_header'><Data ss:Type='String'>XML_DATA_ALTDATE1</Data></Cell>" .
"    <Cell ss:StyleID='brief_header'><Data ss:Type='String'>XML_DATA_ALTDATE2</Data></Cell>" .
"    <Cell ss:StyleID='brief_header'><Data ss:Type='String'>XML_DATA_ALTDATE3</Data></Cell>" .
"    <Cell ss:StyleID='brief_header'><Data ss:Type='String'>XML_DATA_ALTDATE4</Data></Cell>" .
"    <Cell ss:StyleID='brief_header'><Data ss:Type='String'>XML_DATA_ALTDATE5</Data></Cell>" .
"    <Cell ss:StyleID='brief_header'><Data ss:Type='String'>XML_DATA_ALTDATE6</Data></Cell>" .
"    <Cell ss:StyleID='brief_header'><Data ss:Type='String'>XML_DATA_ALTDATE7</Data></Cell>" .
"    <Cell ss:StyleID='brief_header'><Data ss:Type='String'>XML_DATA_ALTDATE8</Data></Cell>" .
"    <Cell ss:StyleID='brief_header'><Data ss:Type='String'>XML_DATA_ALTDATE9</Data></Cell>" .
"    <Cell ss:StyleID='brief_header'><Data ss:Type='String'>XML_DATA_ALTDATE10</Data></Cell>" .
"    <Cell ss:MergeAcross='6' ss:StyleID='s35'/>" .
"   </Row>\n\n";


$xmlCfgFileAltData =
"   <Row>" .
"    <Cell ss:MergeAcross='5' ss:StyleID='m155266416'><Data ss:Type='String'>XML_DATA_CASE_NAME</Data></Cell>\n" .
"    <Cell ss:StyleID='STYLE_ID_STATUS'><Data ss:Type='Number'>XML_DATA_ALTRESULT1</Data></Cell>" .
"    <Cell ss:StyleID='STYLE_ID_STATUS'><Data ss:Type='Number'>XML_DATA_ALTRESULT2</Data></Cell>" .
"    <Cell ss:StyleID='STYLE_ID_STATUS'><Data ss:Type='Number'>XML_DATA_ALTRESULT3</Data></Cell>" .
"    <Cell ss:StyleID='STYLE_ID_STATUS'><Data ss:Type='Number'>XML_DATA_ALTRESULT4</Data></Cell>" .
"    <Cell ss:StyleID='STYLE_ID_STATUS'><Data ss:Type='Number'>XML_DATA_ALTRESULT5</Data></Cell>" .
"    <Cell ss:StyleID='STYLE_ID_STATUS'><Data ss:Type='Number'>XML_DATA_ALTRESULT6</Data></Cell>" .
"    <Cell ss:StyleID='STYLE_ID_STATUS'><Data ss:Type='Number'>XML_DATA_ALTRESULT7</Data></Cell>" .
"    <Cell ss:StyleID='STYLE_ID_STATUS'><Data ss:Type='Number'>XML_DATA_ALTRESULT8</Data></Cell>" .
"    <Cell ss:StyleID='STYLE_ID_STATUS'><Data ss:Type='Number'>XML_DATA_ALTRESULT9</Data></Cell>" .
"    <Cell ss:StyleID='STYLE_ID_STATUS'><Data ss:Type='Number'>XML_DATA_ALTRESULT10</Data></Cell>" .
"    <Cell ss:MergeAcross='6' ss:StyleID='s35'/>" .
"   </Row>\n\n";

} # sub InitXml