/// <summary>
        /// Perform top-level analysis and produce standard reports
        /// </summary>
        public void DoReport()
        {
            if (!Directory.Exists(outputDirectory))
            {
                Directory.CreateDirectory(outputDirectory);
            }

            string title = string.Format("{0} Test Results", Path.GetFileNameWithoutExtension(testResultPath));

            indexPage = new HtmlPage(Path.Combine(outputDirectory, "index.html"));
            indexPage.Begin(title);

            try
            {
                resultLoader.Load(testResultPath);
            }
            catch (ApplicationException ex)
            {
                indexPage.WriteLine(ex.Message);
                throw;
            }
            catch (Exception ex)
            {
                indexPage.WriteLine(ex.ToString());
                throw;
            }

            InitializeProjectIndex();

            testCount    = 0;
            notRunCount  = 0;
            failureCount = 0;


            foreach (TestResult suiteResult in resultLoader.ProjectResults)
            {
                string projectName = Path.GetFileNameWithoutExtension(suiteResult.Name);
                Console.WriteLine("Analyzing {0}", projectName);

                TestResultAnalyzer analyzer = new TestResultAnalyzer(projectName);
                analyzer.FindFixtures(suiteResult);
                analyzer.Analyze();

                testCount    += analyzer.TestCount;
                notRunCount  += analyzer.NotRunCount;
                failureCount += analyzer.FailureCount;

                WriteIndexEntry(analyzer);
                WriteDetailPage(analyzer);
            }

            TerminateProjectIndex();

            indexPage.End();

            Console.WriteLine("Analysis Complete");
            Console.WriteLine("Report created in directory {0}", Path.GetFullPath(outputDirectory));
        }
        /// <summary>
        /// Perform top-level analysis and produce standard reports
        /// </summary>
        public void DoReport()
        {
            if( !Directory.Exists( outputDirectory ) )
                Directory.CreateDirectory( outputDirectory );

            string title = string.Format( "{0} Test Results", Path.GetFileNameWithoutExtension( testResultPath ) );
            indexPage = new HtmlPage( Path.Combine( outputDirectory, "index.html" ) );
            indexPage.Begin( title );

            try
            {
                resultLoader.Load( testResultPath );
            }
            catch ( ApplicationException ex )
            {
                indexPage.WriteLine( ex.Message );
                throw;
            }
            catch ( Exception ex )
            {
                indexPage.WriteLine( ex.ToString() );
                throw;
            }

            InitializeProjectIndex();

            testCount = 0;
            notRunCount = 0;
            failureCount = 0;

            foreach( TestResult suiteResult in resultLoader.ProjectResults )
            {
                string projectName = Path.GetFileNameWithoutExtension( suiteResult.Name );
                Console.WriteLine( "Analyzing {0}", projectName );

                TestResultAnalyzer analyzer = new TestResultAnalyzer( projectName );
                analyzer.FindFixtures( suiteResult );
                analyzer.Analyze();

                testCount += analyzer.TestCount;
                notRunCount += analyzer.NotRunCount;
                failureCount += analyzer.FailureCount;

                WriteIndexEntry( analyzer );
                WriteDetailPage( analyzer );
            }

            TerminateProjectIndex();

            indexPage.End();

            Console.WriteLine( "Analysis Complete" );
            Console.WriteLine( "Report created in directory {0}", Path.GetFullPath( outputDirectory ) );
        }
        private void WriteMissingProjectsTable(HtmlPage page, ArrayList missingProjects)
        {
            page.BeginTable();

            page.BeginRow("hdr-row");
            page.WriteHeaderCell("Missing&nbsp;Projects");
            page.EndRow();

            foreach (TestResultAnalyzer analyzer in missingProjects)
            {
                page.BeginRow();
                page.WriteCell(analyzer.Name, "name");
                page.EndRow();
            }

            page.EndTable();
        }
        private void WriteDetailTable(HtmlPage page, TestResultAnalyzer analyzer)
        {
            StringBuilder sbFailures = new StringBuilder();
            StringBuilder sbNotRun   = new StringBuilder();

            page.Begin(analyzer.Name);
            page.BeginTable("class=center");

            page.BeginRow("hdr-row");
            page.WriteHeaderCell("Class", "name");
            page.WriteHeaderCell("Tests");
            page.WriteHeaderCell("Not&nbsp;Run");
            page.WriteHeaderCell("Failures");
            page.EndRow();

            foreach (TestResultAnalyzer classAnalyzer in analyzer.Children)
            {
                if (classAnalyzer.FailureCount > 0)
                {
                    page.BeginRow("failure-row");
                }
                else
                if (classAnalyzer.NotRunCount > 0)
                {
                    page.BeginRow("notrun-row");
                }
                else
                {
                    page.BeginRow();
                }

                page.WriteCell(classAnalyzer.Name, "name");
                page.WriteCell(classAnalyzer.TestCount);
                page.WriteCell(classAnalyzer.NotRunCount);
                page.WriteCell(classAnalyzer.FailureCount);
                page.EndRow();
            }

            page.BeginRow("total-row");
            page.WriteCell("Total", "name");
            page.WriteCell(analyzer.TestCount);
            page.WriteCell(analyzer.NotRunCount);
            page.WriteCell(analyzer.FailureCount);
            page.EndRow();
            page.EndTable();
        }
        private void WriteDetailPage(TestResultAnalyzer analyzer)
        {
            HtmlPage page = new HtmlPage(Path.Combine(outputDirectory, analyzer.Name + ".html"));

            WriteDetailTable(page, analyzer);

            if (analyzer.FailureCount > 0)
            {
                WriteFailureTable(page, analyzer);
            }

            if (analyzer.NotRunCount > 0)
            {
                WriteNotRunTable(page, analyzer);
            }

            page.End();
        }
        private void WriteNotRunTable(HtmlPage page, TestResultAnalyzer analyzer)
        {
            page.BeginTable("class=center");
            page.BeginRow("notrun-row");
            page.WriteHeaderCell("Not&nbsp;Run", 2);
            page.EndRow();

            int count = 0;

            foreach (TestResult result in analyzer.TestCaseResults)
            {
                if (result.ResultState.Status == TestStatus.Skipped)
                {
                    page.BeginRow();
                    page.WriteCell(++count);
                    page.WriteCell(TruncateTestName(result.Name) + "<br>" + HttpUtility.HtmlEncode(result.Message), "text");
                    page.EndRow();
                }
            }

            page.EndTable();
        }
        private void WriteNotRunTable( HtmlPage page, TestResultAnalyzer analyzer )
        {
            page.BeginTable( "class=center" );
            page.BeginRow( "notrun-row" );
            page.WriteHeaderCell( "Not&nbsp;Run", 2 );
            page.EndRow();

            int count = 0;
            foreach( TestResult result in analyzer.TestCaseResults )
            {
                if ( result.ResultState.Status == TestStatus.Skipped )
                {
                    page.BeginRow();
                    page.WriteCell( ++count );
                    page.WriteCell( TruncateTestName(result.Name) + "<br>" + HttpUtility.HtmlEncode( result.Message ), "text" );
                    page.EndRow();
                }
            }

            page.EndTable();
        }
        private void WriteMissingProjectsTable(HtmlPage page, ArrayList missingProjects)
        {
            page.BeginTable();

            page.BeginRow( "hdr-row" );
            page.WriteHeaderCell( "Missing&nbsp;Projects"  );
            page.EndRow();

            foreach( TestResultAnalyzer analyzer in missingProjects )
            {
                page.BeginRow();
                page.WriteCell( analyzer.Name, "name" );
                page.EndRow();
            }

            page.EndTable();
        }
        private void WriteFailureTable( HtmlPage page, TestResultAnalyzer analyzer )
        {
            page.BeginTable( "class=center" );
            page.BeginRow( "failure-row" );
            page.WriteHeaderCell( "Failures", 2);
            page.EndRow();

            int count = 0;
            foreach( TestResult result in analyzer.TestCaseResults )
            {
                if ( result.ResultState.Status == TestStatus.Failed )
                {
                    page.BeginRow();
                    page.WriteCell( ++count );
                    StringBuilder sb = new StringBuilder( TruncateTestName(result.Name) );
                    sb.Append( "<br>" );
                    sb.Append( HttpUtility.HtmlEncode( result.Message ) );
                    if (result.StackTrace != null && result.StackTrace != string.Empty)
                    {
                        string[] stack = result.StackTrace.Split(new char[] { '\n' });
                        sb.Append("<pre>");
                        foreach (string line in stack)
                            sb.Append(HttpUtility.HtmlEncode(line));
                        sb.Append("</pre>");
                    }
                    page.WriteCell( sb.ToString(), "text" );
                    page.EndRow();
                }
            }

            page.EndTable();
        }
        private void WriteDetailTable( HtmlPage page, TestResultAnalyzer analyzer )
        {
            StringBuilder sbFailures = new StringBuilder();
            StringBuilder sbNotRun = new StringBuilder();

            page.Begin( analyzer.Name );
            page.BeginTable( "class=center" );

            page.BeginRow( "hdr-row" );
            page.WriteHeaderCell( "Class", "name" );
            page.WriteHeaderCell( "Tests" );
            page.WriteHeaderCell( "Not&nbsp;Run" );
            page.WriteHeaderCell( "Failures" );
            page.EndRow();

            foreach( TestResultAnalyzer classAnalyzer in analyzer.Children )
            {
                if ( classAnalyzer.FailureCount > 0 )
                    page.BeginRow( "failure-row" );
                else
                if ( classAnalyzer.NotRunCount > 0 )
                    page.BeginRow( "notrun-row" );
                else
                    page.BeginRow();

                page.WriteCell( classAnalyzer.Name, "name" );
                page.WriteCell( classAnalyzer.TestCount );
                page.WriteCell( classAnalyzer.NotRunCount );
                page.WriteCell( classAnalyzer.FailureCount );
                page.EndRow();
            }

            page.BeginRow( "total-row" );
            page.WriteCell( "Total", "name" );
            page.WriteCell( analyzer.TestCount );
            page.WriteCell( analyzer.NotRunCount );
            page.WriteCell( analyzer.FailureCount );
            page.EndRow();
            page.EndTable();
        }
        private void WriteDetailPage( TestResultAnalyzer analyzer )
        {
            HtmlPage page = new HtmlPage( Path.Combine( outputDirectory, analyzer.Name + ".html" ) );

            WriteDetailTable( page, analyzer );

            if ( analyzer.FailureCount > 0 )
                WriteFailureTable( page, analyzer );

            if ( analyzer.NotRunCount > 0 )
                WriteNotRunTable( page, analyzer );

            page.End();
        }