private void MakeColumnHeading(string aTitle, TAlignment aAlignment, TSortType aSortType)
        {
            if (iSortType != aSortType)
            {
                string toolTipBody = "Sort by ";
                //
                switch (aSortType)
                {
                default:
                case TSortType.ESortTypeByAddress:
                    toolTipBody += "address";
                    break;

                case TSortType.ESortTypeByType:
                    toolTipBody += "type";
                    break;

                case TSortType.ESortTypeByLength:
                    toolTipBody += "length";
                    break;
                }
                //
                string url             = PageFileName(aSortType);
                string linkWithToolTip = HeapToHTMLPageJavaScriptManager.MakeToolTipLink("Sorting", toolTipBody, url, string.Empty, aTitle);
                //
                WriteTableColumnBegin(aAlignment, "tableHeaders");
                WriteLine(linkWithToolTip);
                WriteTableColumnEnd();
            }
            else
            {
                WriteTableColumn(aTitle, aAlignment, "tableHeaderSelected");
            }
        }
        private void CreateWorkers()
        {
            // Create all the writers first
            iPageIndex            = new HeapToHTMLPageIndex(iReconstructor, PageFileNameEnsuringPathExists("Index"));
            iPageIndex.iObserver += new AsyncTextWriterBase.Observer(WriterObserver);
            //
            string entireListingFileNameByAddress = HeapToHTMLPageEntireListing.PageFileName(HeapToHTMLPageEntireListing.TSortType.ESortTypeByAddress);

            entireListingFileNameByAddress         = PageFileNameEnsuringPathExists(entireListingFileNameByAddress, iBaseOutputPath, string.Empty, string.Empty);
            iPageEntireListingByAddress            = new HeapToHTMLPageEntireListing(iReconstructor, HeapToHTMLPageEntireListing.TSortType.ESortTypeByAddress, entireListingFileNameByAddress);
            iPageEntireListingByAddress.iObserver += new AsyncTextWriterBase.Observer(WriterObserver);
            //
            string entireListingFileNameByType = HeapToHTMLPageEntireListing.PageFileName(HeapToHTMLPageEntireListing.TSortType.ESortTypeByType);

            entireListingFileNameByType         = PageFileNameEnsuringPathExists(entireListingFileNameByType, iBaseOutputPath, string.Empty, string.Empty);
            iPageEntireListingByType            = new HeapToHTMLPageEntireListing(iReconstructor, HeapToHTMLPageEntireListing.TSortType.ESortTypeByType, entireListingFileNameByType);
            iPageEntireListingByType.iObserver += new AsyncTextWriterBase.Observer(WriterObserver);
            //
            string entireListingFileNameByLength = HeapToHTMLPageEntireListing.PageFileName(HeapToHTMLPageEntireListing.TSortType.ESortTypeByLength);

            entireListingFileNameByLength         = PageFileNameEnsuringPathExists(entireListingFileNameByLength, iBaseOutputPath, string.Empty, string.Empty);
            iPageEntireListingByLength            = new HeapToHTMLPageEntireListing(iReconstructor, HeapToHTMLPageEntireListing.TSortType.ESortTypeByLength, entireListingFileNameByLength);
            iPageEntireListingByLength.iObserver += new AsyncTextWriterBase.Observer(WriterObserver);
            //
            iPageHeapCellManager            = new HeapToHTMLPageHeapCellManager(iReconstructor, iBaseOutputPath);
            iPageHeapCellManager.iObserver += new AsyncTextWriterBase.Observer(WriterObserver);
            //
            iPageJavaScriptManager            = new HeapToHTMLPageJavaScriptManager(iReconstructor, iBaseOutputPath);
            iPageJavaScriptManager.iObserver += new AsyncTextWriterBase.Observer(WriterObserver);

            // Reset their completion statuses so that we're ready to start anew
            ResetCompletionStatuses();

            // Now it's safe to start all the writers running.
            iPageIndex.AsyncWrite();
            iPageEntireListingByAddress.AsyncWrite();
            iPageEntireListingByType.AsyncWrite();
            iPageEntireListingByLength.AsyncWrite();
            iPageHeapCellManager.AsyncWrite();
            iPageJavaScriptManager.AsyncWrite();
        }
        private void OnStateBody()
        {
            HeapCell entry = iEntries[iCurrentHeapCellIndex++];
            string   link;
            string   body = string.Empty;

            string style = TableRowBodyStyleName;

            if (entry.Type == HeapCell.TType.EFree)
            {
                style = "tableRowFreeCell";
            }
            Writer.WriteLine("<TR class=\"" + style + "\">");

            // Address
            WriteTableColumnBegin();
            WriteDivisionBeginWithId(HeapCellLinkIdentifierName(entry));
            string cellAddress = "0x" + entry.Address.ToString("x8");

            MakeAddressLink(entry);
            WriteDivisionEnd();
            WriteTableColumnEnd();

            // Type
            string typeProperName = string.Empty;

            if (entry.Type == HeapCell.TType.EAllocated)
            {
                typeProperName = "Allocated";
                body           = CreateCellContentsQuickView(entry);
            }
            else if (entry.Type == HeapCell.TType.EFree)
            {
                typeProperName = "Free";
                body           = CreateCellContentsQuickView(entry);
            }

            link = HeapToHTMLPageJavaScriptManager.MakeToolTipDiv(typeProperName + " Cell", body, typeProperName, KHeapDataPreviewLength);
            WriteTableColumnBegin(TAlignment.EAlignCenter, string.Empty);
            WriteLine(link);
            WriteTableColumnEnd();

            // Alloc number
            if (iReconstructor.SourceData.MetaData.Heap.DebugAllocator)
            {
                link = HeapToHTMLPageJavaScriptManager.MakeToolTipDiv("Allocation Number", "Number " + entry.AllocationNumber.ToString() + " of " + iEntries.Count.ToString() + " cells.", entry.AllocationNumber.ToString());

                WriteTableColumnBegin(TAlignment.EAlignRight, string.Empty);
                WriteLine(link);
                WriteTableColumnEnd();
            }

            // Cell length
            body  = string.Empty;
            body += "Type:    " + typeProperName + "<BR>";
            body += "Header:  " + entry.HeaderSize.ToString() + " bytes<BR>";
            body += "Payload: " + entry.PayloadLength.ToString() + " bytes<BR><BR>";
            if (entry.Type == HeapCell.TType.EFree)
            {
                string instanceSizeAsPercentageOfTotal = iReconstructor.Statistics.CellLengthAsHeapPercentage(entry).ToString("##0.000");
                body += "This individual cell corresponds to " + instanceSizeAsPercentageOfTotal + " of the total free cells in this heap.";
            }
            link = HeapToHTMLPageJavaScriptManager.MakeToolTipDiv("Cell Length", body, entry.Length.ToString());
            WriteTableColumnBegin(TAlignment.EAlignRight, string.Empty);
            WriteLine(link);
            WriteTableColumnEnd();

            // Spacer
            WriteTableColumnSpace();

            // Symbol
            if (entry.Symbol != null)
            {
                // Get symbol tracking info.
                TrackingInfo trackingInfo = iReconstructor.Statistics.StatsAllocated.TrackerSymbols[entry.Symbol];
                System.Diagnostics.Debug.Assert(trackingInfo != null);
                string instanceSizeAsPercentageOfTotal      = iReconstructor.Statistics.CellLengthAsHeapPercentage(entry).ToString("##0.000") + "%";
                string totalSymbolicSizeAsPercentageOfTotal = NumberFormattingUtils.NumberAsPercentageThreeDP(trackingInfo.AssociatedMemory, iReconstructor.Statistics.SizeTotal) + "%";

                body = string.Empty;
                if (trackingInfo.Count > 1)
                {
                    body += "There are " + trackingInfo.Count.ToString() + " other instances of this symbol ";
                }
                else
                {
                    body += "This is the only instance of this symbol ";
                }
                body += "and each instance is using " + trackingInfo.PayloadLength.ToString() + " bytes of memory (plus cell header overhead).<BR><BR>";
                body += "Of the total allocated heap memory, cells associated with this symbolic are using a total of " + trackingInfo.AssociatedMemory.ToString() + " bytes (" + totalSymbolicSizeAsPercentageOfTotal + " of total heap) memory.<BR><BR>";
                body += "This individual cell corresponds to " + instanceSizeAsPercentageOfTotal + " of the total " + typeProperName + " heap space.<BR>";

                link = HeapToHTMLPageJavaScriptManager.MakeToolTipDiv("Symbol Information", body, entry.Symbol.NameWithoutVTablePrefix);
                WriteTableColumnBegin(TAlignment.EAlignLeft, string.Empty);
                WriteLine(link);
                WriteTableColumnEnd();
            }
            else
            {
                WriteTableColumnEmpty();
            }

            // Object name
            if (entry.Symbol != null)
            {
                WriteTableColumn(entry.Symbol.ObjectWithoutSection, TAlignment.EAlignLeft);
            }
            else
            {
                WriteTableColumnEmpty();
            }

            WriteTableRowEnd();
        }
        private void OnStateBody()
        {
            const int KDWordsPerLine = 4;

            int rawItemsCount = iCell.RawItems.Count;

            for (int i = 0; i < rawItemsCount; i += KDWordsPerLine)
            {
                RawItem rawItem = iCell[i];

                // Start new row
                WriteTableRowBegin();

                // Address
                WriteTableColumnBegin();
                WriteAnchorWithName(rawItem.Address.ToString("x8"));
                Writer.Write("0x" + rawItem.Address.ToString("x8"));
                WriteTableColumnEnd();

                // Blank spacer
                WriteTableColumnBegin(TAlignment.EAlignNone, string.Empty, 20);
                WriteSpace();
                WriteTableColumnEnd();

                // Work out how many items on this line
                int runIndex;
                int runExtent = i + KDWordsPerLine;

                // First set of columns - original data
                for (runIndex = i; runIndex < runExtent; runIndex++)
                {
                    // Get the item
                    if (runIndex < rawItemsCount)
                    {
                        rawItem = iCell[runIndex];

                        // Does the raw item have a linked cell associated with it?
                        if (rawItem.Tag != null && rawItem.Tag is Relationships.RelationshipInfo)
                        {
                            Relationships.RelationshipInfo relationshipInfo = (Relationships.RelationshipInfo)rawItem.Tag;
                            HeapCell associatedCell = relationshipInfo.ToCell;

                            string url          = "javascript:showMainFormCell(\'" + associatedCell.Address.ToString("x8") + "\')";
                            string windowTarget = "MainWindow";
                            string toolTipTitle = "Link to ";
                            if (associatedCell.Symbol != null)
                            {
                                toolTipTitle += associatedCell.Symbol.NameWithoutVTablePrefix;
                            }
                            else
                            {
                                toolTipTitle += "Cell";
                            }
                            string toolTipBody     = ToolTipBody(associatedCell);
                            string linkText        = rawItem.OriginalData.ToString("x8");
                            string linkWithToolTip = HeapToHTMLPageJavaScriptManager.MakeToolTipLink(toolTipTitle, toolTipBody, url, windowTarget, linkText);

                            WriteTableColumnBegin(TAlignment.EAlignCenter, "cellDataAsNumeric");
                            WriteLine(linkWithToolTip);
                            WriteTableColumnEnd();
                        }
                        else
                        {
                            WriteTableColumnHex(rawItem.OriginalData, TAlignment.EAlignCenter, "cellDataAsNumeric");
                        }
                    }
                    else
                    {
                        WriteTableColumnEmpty();
                        rawItem = null;
                    }
                }

                // Blank spacer
                WriteTableColumnBegin(TAlignment.EAlignNone, string.Empty, 20);
                WriteSpace();
                WriteTableColumnEnd();

                // Second set of columns - characterised data
                for (runIndex = i; runIndex < runExtent; runIndex++)
                {
                    // Get the item
                    if (runIndex < rawItemsCount)
                    {
                        rawItem = iCell[runIndex];
                        WriteTableColumn(rawItem.OriginalCharacterisedData, TAlignment.EAlignCenter, "cellDataAsString");
                    }
                    else
                    {
                        WriteTableColumnEmpty();
                        rawItem = null;
                    }
                }
            }

            WriteTableRowEnd();
        }