Represents a pair of participants in an email social network.
Inheritance: ParticipantPair
    AnalyzeEmailNetworkInternal
    (
        OleDbDataReader oDataReader,
        Boolean bUseCcForEdgeWeights,
        Boolean bUseBccForEdgeWeights,
        BackgroundWorker oBackgroundWorker,
        DoWorkEventArgs oDoWorkEventArgs
    )
    {
        Debug.Assert(oDataReader != null);
        Debug.Assert(oBackgroundWorker == null || oDoWorkEventArgs != null);
        AssertValid();

        // Create a dictionary to keep track of participant pairs.  The key is
        // the pair of participants in the format used by ParticipantsToKey()
        // and the value is the edge weight between the participants.  The
        // contents of this aggregated dictionary get returned by this method.

        Dictionary<String, Int32> oAggregatedDictionary =
            new Dictionary<String, Int32>();

        // Loop through the email items.

        Int64 iRecords = 0;

        while ( oDataReader.Read() )
        {
            try
            {
                Object oFromField = oDataReader["System.Message.FromAddress"];
                Object oToField = oDataReader["System.Message.ToAddress"];
                Object oCcField = oDataReader["System.Message.CcAddress"];
                Object oBccField = oDataReader["System.Message.BccAddress"];

                AnalyzeOneEmail(oFromField, oToField, oCcField, oBccField,
                    bUseCcForEdgeWeights, bUseBccForEdgeWeights,
                    oAggregatedDictionary);
            }
            catch (OleDbException)
            {
                // In June 2009, a NodeXL team member got a repeatable
                // OleDbException while attempting to analyze his email for a
                // certain date range.  Unfortunately, the team member was on
                // the other side of the country and the exception had no inner
                // exceptions to provide more details.  (OleDbException uses a
                // custom Errors collection instead of inner exceptions, and
                // that collection doesn't get displayed by NodeXL's generic
                // error-handling scheme).  Therefore, the exact cause of the
                // error couldn't be determined.
                //
                // However, the error went away when the date range was
                // altered, leading me to believe that an email with an invalid
                // field was encountered.  Although the DataReader.Item[] and
                // AnalyzeOneEmail() calls shouldn't throw an exception on a
                // bad field, there may be some invalid field condition I'm
                // overlooking.
                //
                // Workaround: Skip emails that throw such an exception.
            }

            if (oBackgroundWorker != null)
            {
                // Check whether a cancellation has been requested.

                if (iRecords % AsyncCancelInterval == 0 &&
                    oBackgroundWorker.CancellationPending)
                {
                    // Cancel the analysis.

                    Debug.Assert(oDoWorkEventArgs != null);

                    oDoWorkEventArgs.Cancel = true;
                    return ( new EmailParticipantPair[0] );
                }
            }

            iRecords++;
        }

        // Convert the aggregated results to an array of EmailParticipantPair
        // objects.

        EmailParticipantPair [] aoEmailParticipantPairs =
            new EmailParticipantPair[oAggregatedDictionary.Count];

        Int32 i = 0;

        foreach (KeyValuePair<String, Int32> oKeyValuePair in
            oAggregatedDictionary)
        {
            String sParticipant1, sParticipant2;

            KeyToParticipants(oKeyValuePair.Key,
                out sParticipant1, out sParticipant2);

            aoEmailParticipantPairs[i] = new EmailParticipantPair(
                sParticipant1, sParticipant2, oKeyValuePair.Value);

            i++;
        }

        return (aoEmailParticipantPairs);
    }
    PopulateEdgesTable
    (
        EmailParticipantPair [] aoEmailParticipantPairs
    )
    {
        Debug.Assert(aoEmailParticipantPairs != null);
        Debug.Assert(m_oEdgeTable != null);
        AssertValid();

        Int32 iEmailParticipantPairs = aoEmailParticipantPairs.Length;

        if (iEmailParticipantPairs == 0)
        {
            return;
        }

        // Create and populate an array of edge weights.

        Object [,] aoEdgeWeights = new Object [iEmailParticipantPairs, 1];

        for (Int32 i = 0; i < iEmailParticipantPairs; i++)
        {
            EmailParticipantPair oEmailParticipantPair =
                aoEmailParticipantPairs[i];

            // Modify the pariticpant strings.

            oEmailParticipantPair.Participant1 =
                AnalyzerToParticipant(oEmailParticipantPair.Participant1);

            oEmailParticipantPair.Participant2 =
                AnalyzerToParticipant(oEmailParticipantPair.Participant2);

            aoEdgeWeights[i, 0] = oEmailParticipantPair.EdgeWeight.ToString();
        }

        Int32 iRowOffsetToWriteTo = 0;

        if (!m_bClearTablesFirst)
        {
            iRowOffsetToWriteTo = ExcelTableUtil.GetOffsetOfFirstEmptyTableRow(
                m_oEdgeTable);
        }

        // Write the arrays to the edge table.

        NodeXLWorkbookUtil.PopulateEdgeTableWithParticipantPairs(
            m_oEdgeTable, aoEmailParticipantPairs, iRowOffsetToWriteTo);

        SetEdgeWeightValues(aoEdgeWeights, iRowOffsetToWriteTo);

        ExcelUtil.ActivateWorksheet(m_oEdgeTable);
    }