//*************************************************************************
        //  Method: DataGridViewRowToEmailParticipantCriteria()
        //
        /// <summary>
        /// Creates a <see cref="EmailParticipantCriteria" /> object from the
        /// contents of a DataGridViewRow from the dgvParticipants DataGridView.
        /// </summary>
        ///
        /// <returns>
        /// A <see cref="EmailParticipantCriteria" /> object.  Important: The
        /// DataGridViewRow is not validated and the returned object may contain
        /// invalid data.
        /// </returns>
        //*************************************************************************
        protected EmailParticipantCriteria DataGridViewRowToEmailParticipantCriteria(
            DataGridViewRow oRow
            )
        {
            Debug.Assert(oRow != null);
            AssertValid();

            EmailParticipantCriteria oEmailParticipantCriteria =
            new EmailParticipantCriteria();

            String sParticipant =
            (String)oRow.Cells[this.colParticipant.Name].Value;

            if ( !String.IsNullOrEmpty(sParticipant) )
            {
            // Trim the participant string.

            sParticipant = sParticipant.Trim();
            oRow.Cells[this.colParticipant.Name].Value = sParticipant;
            }

            if ( !String.IsNullOrEmpty(sParticipant) )
            {
            sParticipant = ParticipantToAnalyzer(sParticipant);
            }

            oEmailParticipantCriteria.Participant = sParticipant;

            IncludedIn eIncludedIn = IncludedIn.None;

            if ( DataGridViewCheckBoxCellIsChecked(oRow, this.colFrom.Name) )
            {
            eIncludedIn |= IncludedIn.From;
            }

            if ( DataGridViewCheckBoxCellIsChecked(oRow, this.colTo.Name) )
            {
            eIncludedIn |= IncludedIn.To;
            }

            if ( DataGridViewCheckBoxCellIsChecked(oRow, this.colCc.Name) )
            {
            eIncludedIn |= IncludedIn.Cc;
            }

            if ( DataGridViewCheckBoxCellIsChecked(oRow, this.colBcc.Name) )
            {
            eIncludedIn |= IncludedIn.Bcc;
            }

            oEmailParticipantCriteria.IncludedIn = eIncludedIn;

            return (oEmailParticipantCriteria);
        }
        //*************************************************************************
        //  Method: AnalyzeEmailNetworkInternal()
        //
        /// <summary>
        /// Analyzes the part of a user's email social network that satisfies
        /// specified criteria.
        /// </summary>
        ///
        /// <param name="participantsCriteria">
        /// See the synchronous method.
        /// </param>
        ///
        /// <param name="startTime">
        /// See AnalyzeEmailNetwork().
        /// </param>
        ///
        /// <param name="endTime">
        /// See AnalyzeEmailNetwork().
        /// </param>
        ///
        /// <param name="subjectText">
        /// See AnalyzeEmailNetwork().
        /// </param>
        ///
        /// <param name="bodyText">
        /// See AnalyzeEmailNetwork().
        /// </param>
        ///
        /// <param name="folder">
        /// See AnalyzeEmailNetwork().
        /// </param>
        ///
        /// <param name="minimumSize">
        /// See AnalyzeEmailNetwork().
        /// </param>
        ///
        /// <param name="maximumSize">
        /// See AnalyzeEmailNetwork().
        /// </param>
        ///
        /// <param name="attachmentFilter">
        /// See AnalyzeEmailNetwork().
        /// </param>
        ///
        /// <param name="hasCc">
        /// See AnalyzeEmailNetwork().
        /// </param>
        ///
        /// <param name="hasBcc">
        /// See AnalyzeEmailNetwork().
        /// </param>
        ///
        /// <param name="isReplyFromParticipant1">
        /// See AnalyzeEmailNetwork().
        /// </param>
        ///
        /// <param name="useCcForEdgeWeights">
        /// See the synchronous method.
        /// </param>
        ///
        /// <param name="useBccForEdgeWeights">
        /// See the synchronous method.
        /// </param>
        ///
        /// <param name="backgroundWorker">
        /// A BackgroundWorker object if this method is being called
        /// asynchronously, or null if it is being called synchronously.
        /// </param>
        ///
        /// <param name="doWorkEventArgs">
        /// A DoWorkEventArgs object if this method is being called
        /// asynchronously, or null if it is being called synchronously.
        /// </param>
        ///
        /// <returns>
        /// See AnalyzeEmailNetwork().
        /// </returns>
        //*************************************************************************
        protected EmailParticipantPair[] AnalyzeEmailNetworkInternal(
            EmailParticipantCriteria [] participantsCriteria,
            Nullable<DateTime> startTime,
            Nullable<DateTime> endTime,
            String subjectText,
            String bodyText,
            String folder,
            Nullable<Int64> minimumSize,
            Nullable<Int64> maximumSize,
            Nullable<AttachmentFilter> attachmentFilter,
            Nullable<Boolean> hasCc,
            Nullable<Boolean> hasBcc,
            Nullable<Boolean> isReplyFromParticipant1,
            Boolean useCcForEdgeWeights,
            Boolean useBccForEdgeWeights,
            BackgroundWorker backgroundWorker,
            DoWorkEventArgs doWorkEventArgs
            )
        {
            CheckAnalyzeMethodArguments(participantsCriteria, startTime, endTime,
            subjectText, bodyText, folder, minimumSize, maximumSize,
            attachmentFilter, isReplyFromParticipant1);

            Debug.Assert(backgroundWorker == null || doWorkEventArgs != null);

            AssertValid();

            String sQuery = CreateQuery(participantsCriteria, startTime, endTime,
            subjectText, bodyText, folder, minimumSize, maximumSize,
            attachmentFilter, hasCc, hasBcc, isReplyFromParticipant1);

            OleDbDataReader oDataReader = GetDataReader(sQuery);

            EmailParticipantPair [] aoEmailParticipantPairs = null;

            try
            {
            aoEmailParticipantPairs = AnalyzeEmailNetworkInternal(
                oDataReader, useCcForEdgeWeights, useBccForEdgeWeights,
                backgroundWorker, doWorkEventArgs);
            }
            finally
            {
            oDataReader.Close();
            }

            return (aoEmailParticipantPairs);
        }
        //*************************************************************************
        //  Method: AnalyzeEmailNetworkAsync()
        //
        /// <summary>
        /// Asynchronously analyzes the part of a user's email social network that
        /// satisfies specified criteria.
        /// </summary>
        ///
        /// <param name="participantsCriteria">
        /// See the synchronous method.
        /// </param>
        ///
        /// <param name="startTime">
        /// See the synchronous method.
        /// </param>
        ///
        /// <param name="endTime">
        /// See the synchronous method.
        /// </param>
        ///
        /// <param name="subjectText">
        /// See the synchronous method.
        /// </param>
        ///
        /// <param name="bodyText">
        /// See the synchronous method.
        /// </param>
        ///
        /// <param name="folder">
        /// See the synchronous method.
        /// </param>
        ///
        /// <param name="minimumSize">
        /// See the synchronous method.
        /// </param>
        ///
        /// <param name="maximumSize">
        /// See the synchronous method.
        /// </param>
        ///
        /// <param name="attachmentFilter">
        /// See the synchronous method.
        /// </param>
        ///
        /// <param name="hasCc">
        /// See the synchronous method.
        /// </param>
        ///
        /// <param name="hasBcc">
        /// See the synchronous method.
        /// </param>
        ///
        /// <param name="isReplyFromParticipant1">
        /// See the synchronous method.
        /// </param>
        ///
        /// <param name="useCcForEdgeWeights">
        /// See the synchronous method.
        /// </param>
        ///
        /// <param name="useBccForEdgeWeights">
        /// See the synchronous method.
        /// </param>
        ///
        /// <remarks>
        /// When the analysis completes, the <see cref="AnalysisCompleted" /> event
        /// fires.  The <see cref="RunWorkerCompletedEventArgs.Result" /> property
        /// will return an array of zero or more <see cref="EmailParticipantPair" />
        /// objects, one for each pair of participants in the user's email social
        /// network that satisfy the specified criteria.  The property is never
        /// null.
        ///
        /// <para>
        /// To cancel the analysis, call <see cref="CancelAsync" />.
        /// </para>
        ///
        /// </remarks>
        //*************************************************************************
        public void AnalyzeEmailNetworkAsync(
            EmailParticipantCriteria [] participantsCriteria,
            Nullable<DateTime> startTime,
            Nullable<DateTime> endTime,
            String subjectText,
            String bodyText,
            String folder,
            Nullable<Int64> minimumSize,
            Nullable<Int64> maximumSize,
            Nullable<AttachmentFilter> attachmentFilter,
            Nullable<Boolean> hasCc,
            Nullable<Boolean> hasBcc,
            Nullable<Boolean> isReplyFromParticipant1,
            Boolean useCcForEdgeWeights,
            Boolean useBccForEdgeWeights
            )
        {
            AssertValid();

            const String MethodName = "AnalyzeEmailNetworkAsync";

            if (this.IsBusy)
            {
            throw new InvalidOperationException( String.Format(

                "{0}:{1}: An asynchronous operation is already in progress."
                ,
                this.ClassName,
                MethodName
                ) );
            }

            // Wrap the arguments in an object that can be passed to
            // BackgroundWorker.RunWorkerAsync().

            AnalyzeEmailNetworkAsyncArgs oAnalyzeEmailNetworkAsyncArgs =
            new AnalyzeEmailNetworkAsyncArgs();

            oAnalyzeEmailNetworkAsyncArgs.ParticipantsCriteria =
            participantsCriteria;

            oAnalyzeEmailNetworkAsyncArgs.StartTime = startTime;
            oAnalyzeEmailNetworkAsyncArgs.EndTime = endTime;
            oAnalyzeEmailNetworkAsyncArgs.SubjectText = subjectText;
            oAnalyzeEmailNetworkAsyncArgs.BodyText = bodyText;
            oAnalyzeEmailNetworkAsyncArgs.Folder = folder;
            oAnalyzeEmailNetworkAsyncArgs.MinimumSize = minimumSize;
            oAnalyzeEmailNetworkAsyncArgs.MaximumSize = maximumSize;
            oAnalyzeEmailNetworkAsyncArgs.AttachmentFilter = attachmentFilter;
            oAnalyzeEmailNetworkAsyncArgs.HasCc = hasCc;
            oAnalyzeEmailNetworkAsyncArgs.HasBcc = hasBcc;

            oAnalyzeEmailNetworkAsyncArgs.IsReplyFromParticipant1 =
            isReplyFromParticipant1;

            oAnalyzeEmailNetworkAsyncArgs.UseCcForEdgeWeights =
            useCcForEdgeWeights;

            oAnalyzeEmailNetworkAsyncArgs.UseBccForEdgeWeights =
            useBccForEdgeWeights;

            // Create a BackgroundWorker and handle its events.

            m_oBackgroundWorker = new BackgroundWorker();

            m_oBackgroundWorker.WorkerSupportsCancellation = true;

            m_oBackgroundWorker.DoWork += new DoWorkEventHandler(
            BackgroundWorker_DoWork);

            m_oBackgroundWorker.RunWorkerCompleted +=
            new RunWorkerCompletedEventHandler(
                BackgroundWorker_RunWorkerCompleted);

            m_oBackgroundWorker.RunWorkerAsync(oAnalyzeEmailNetworkAsyncArgs);
        }
        //*************************************************************************
        //  Method: AnalyzeEmailNetwork()
        //
        /// <summary>
        /// Synchronously analyzes the part of a user's email social network that
        /// satisfies specified criteria.
        /// </summary>
        ///
        /// <param name="participantsCriteria">
        /// An array of <see cref="EmailParticipantCriteria" /> objects, one for
        /// each participant to filter on, or null to not filter on participants.
        /// For each element in the array, <see
        /// cref="EmailParticipantCriteria.Participant" /> must be specified, but
        /// <see cref="EmailParticipantCriteria.IncludedIn" /> can be <see
        /// cref="IncludedIn.None" />.
        /// </param>
        ///
        /// <param name="startTime">
        /// If specified, only emails sent on or after the specified time are
        /// included in the aggregated results.  Use null to specify "no start
        /// time."
        /// </param>
        ///
        /// <param name="endTime">
        /// If specified, only emails sent on or before the specified time are
        /// included in the aggregated results.  Use null to specify "no end time."
        /// </param>
        ///
        /// <param name="subjectText">
        /// Subject text to filter on, or null to not filter on subject text.
        /// Can't be an empty string.  If specified, only emails that include the
        /// specified subject text are included in the aggregated results.
        /// </param>
        ///
        /// <param name="bodyText">
        /// Body text to filter on, or null to not filter on body text.  Can't be
        /// an empty string.  If specified, only emails that include the specified
        /// body text are included in the aggregated results.
        /// </param>
        ///
        /// <param name="folder">
        /// Email folder to filter on, or null to not filter on the email folder.
        /// Can't be an empty string.  If specified, only emails in the specified
        /// folder are included in the aggregated results.  Sample: "Inbox".
        /// </param>
        ///
        /// <param name="minimumSize">
        /// If specified, only emails that have a size greater than or equal to the
        /// specified value are included in the aggregated results.
        /// </param>
        ///
        /// <param name="maximumSize">
        /// If specified, only emails that have a size less than or equal to the
        /// specified value are included in the aggregated results.
        /// </param>
        ///
        /// <param name="attachmentFilter">
        /// If not null, specifies how attachments are used to determine which
        /// emails are included in the aggregated results.  Use null to specify
        /// "don't care."
        /// </param>
        ///
        /// <param name="hasCc">
        /// If specified, only emails that have or don't have a Cc line are
        /// included in the aggregated results.  Use null to specify "don't care."
        /// </param>
        ///
        /// <param name="hasBcc">
        /// If specified, only emails that have or don't have a Bcc line are
        /// included in the aggregated results.  Use null to specify "don't care."
        /// </param>
        ///
        /// <param name="isReplyFromParticipant1">
        /// If specified, only emails that are or are not replies from <paramref
        /// name="participant1" /> are included in the aggregated results.
        /// Use null to specify "don't care."
        ///
        /// <para>
        /// [IMPORTANT NOTE: As of April 2008, the System.Message.IsFwdOrReply
        /// message property needed to implement this is always null.  Specifying
        /// true or false for this parameter will always return an empty array.
        /// The parameter is retained in case the missing property is fixed in a
        /// future version of Windows Desktop Search.]
        /// </para>
        ///
        /// </param>
        ///
        /// <param name="useCcForEdgeWeights">
        /// If true, an edge weight of one is assigned to the sender and each
        /// participant on the Cc line.  (An edge weight of one is always assigned
        /// to the sender and each participant on the To line.)
        /// </param>
        ///
        /// <param name="useBccForEdgeWeights">
        /// If true, an edge weight of one is assigned to the sender and each
        /// participant on the Bcc line.  (An edge weight of one is always assigned
        /// to the sender and each participant on the To line.)
        /// </param>
        ///
        /// <returns>
        /// An array of zero or more <see cref="EmailParticipantPair" /> objects,
        /// one for each pair of participants in the user's email social network
        /// that satisfy the specified criteria.  The return value is never null.
        /// </returns>
        ///
        /// <remarks>
        /// This overload does the same thing as the <see
        /// cref="AnalyzeEmailNetwork()" /> overload, but only those emails that
        /// match the specified criteria are aggregated.
        /// </remarks>
        //*************************************************************************
        public EmailParticipantPair[] AnalyzeEmailNetwork(
            EmailParticipantCriteria [] participantsCriteria,
            Nullable<DateTime> startTime,
            Nullable<DateTime> endTime,
            String subjectText,
            String bodyText,
            String folder,
            Nullable<Int64> minimumSize,
            Nullable<Int64> maximumSize,
            Nullable<AttachmentFilter> attachmentFilter,
            Nullable<Boolean> hasCc,
            Nullable<Boolean> hasBcc,
            Nullable<Boolean> isReplyFromParticipant1,
            Boolean useCcForEdgeWeights,
            Boolean useBccForEdgeWeights
            )
        {
            AssertValid();

            return ( AnalyzeEmailNetworkInternal(participantsCriteria, startTime,
            endTime, subjectText, bodyText, folder, minimumSize, maximumSize,
            attachmentFilter, hasCc, hasBcc, isReplyFromParticipant1,
            useCcForEdgeWeights, useBccForEdgeWeights, null, null) );
        }
        //*************************************************************************
        //  Method: CreateQuery()
        //
        /// <summary>
        /// Creates a query that uses specified criteria.
        /// </summary>
        ///
        /// <param name="participantsCriteria">
        /// See AnalyzeEmailNetwork().
        /// </param>
        ///
        /// <param name="startTime">
        /// See AnalyzeEmailNetwork().
        /// </param>
        ///
        /// <param name="endTime">
        /// See AnalyzeEmailNetwork().
        /// </param>
        ///
        /// <param name="subjectText">
        /// See AnalyzeEmailNetwork().
        /// </param>
        ///
        /// <param name="bodyText">
        /// See AnalyzeEmailNetwork().
        /// </param>
        ///
        /// <param name="folder">
        /// See AnalyzeEmailNetwork().
        /// </param>
        ///
        /// <param name="minimumSize">
        /// See AnalyzeEmailNetwork().
        /// </param>
        ///
        /// <param name="maximumSize">
        /// See AnalyzeEmailNetwork().
        /// </param>
        ///
        /// <param name="attachmentFilter">
        /// See AnalyzeEmailNetwork().
        /// </param>
        ///
        /// <param name="hasCc">
        /// See AnalyzeEmailNetwork().
        /// </param>
        ///
        /// <param name="hasBcc">
        /// See AnalyzeEmailNetwork().
        /// </param>
        ///
        /// <param name="isReplyFromParticipant1">
        /// See AnalyzeEmailNetwork().
        /// </param>
        ///
        /// <returns>
        /// A query that uses the specified criteria.
        /// </returns>
        //*************************************************************************
        protected String CreateQuery(
            EmailParticipantCriteria [] participantsCriteria,
            Nullable<DateTime> startTime,
            Nullable<DateTime> endTime,
            String subjectText,
            String bodyText,
            String folder,
            Nullable<Int64> minimumSize,
            Nullable<Int64> maximumSize,
            Nullable<AttachmentFilter> attachmentFilter,
            Nullable<Boolean> hasCc,
            Nullable<Boolean> hasBcc,
            Nullable<Boolean> isReplyFromParticipant1
            )
        {
            AssertValid();

            StringBuilder oStringBuilder = new StringBuilder();
            oStringBuilder.Append(BaseQuery);

            String sEscapedFirstParticipant = null;
            Int32 i = 0;

            StringBuilder oParticipantCriteriaStringBuilder =
            new StringBuilder();

            if (participantsCriteria != null)
            {
            foreach (EmailParticipantCriteria oParticipantCriteria in
                participantsCriteria)
            {
                String sEscapedParticipant =
                    EscapeStringForContains(oParticipantCriteria.Participant);

                Debug.Assert( !String.IsNullOrEmpty(sEscapedParticipant) );

                if (i == 0)
                {
                    sEscapedFirstParticipant = sEscapedParticipant;
                }

                i++;

                IncludedIn eIncludedIn = oParticipantCriteria.IncludedIn;

                if (eIncludedIn == IncludedIn.None)
                {
                    // Skip this one.

                    continue;
                }

                if (oParticipantCriteriaStringBuilder.Length > 0)
                {
                    // The participants are ORed together.

                    oParticipantCriteriaStringBuilder.Append(" OR ");
                }

                // This part of the query will look like this, in pseudocode:
                //
                // ( Contains(To, Participant)
                // OR Contains(From, Participant) OR Contains(Cc, Participant)
                // OR Contains(Bcc, Participant) )

                // Open the outer clause.

                oParticipantCriteriaStringBuilder.Append("(");

                // Append a clause for each IncludedIn flag.

                Boolean bParticipantClauseAppended = false;

                AppendParticipantClauseToQuery(sEscapedParticipant,
                    eIncludedIn, IncludedIn.From,
                    oParticipantCriteriaStringBuilder,
                    ref bParticipantClauseAppended);

                AppendParticipantClauseToQuery(sEscapedParticipant,
                    eIncludedIn, IncludedIn.To,
                    oParticipantCriteriaStringBuilder,
                    ref bParticipantClauseAppended);

                AppendParticipantClauseToQuery(sEscapedParticipant,
                    eIncludedIn, IncludedIn.Cc,
                    oParticipantCriteriaStringBuilder,
                    ref bParticipantClauseAppended);

                AppendParticipantClauseToQuery(sEscapedParticipant,
                    eIncludedIn, IncludedIn.Bcc,
                    oParticipantCriteriaStringBuilder,
                    ref bParticipantClauseAppended);

                // Close the outer clause.

                oParticipantCriteriaStringBuilder.Append(")");
            }

            if (oParticipantCriteriaStringBuilder.Length > 0)
            {
                oStringBuilder.AppendFormat(

                    " AND ({0}) "
                    ,
                    oParticipantCriteriaStringBuilder
                    );
            }
            }

            const String DateSentClause =
            " AND System.Message.DateSent {0} '{1}'"
            ;

            if (startTime.HasValue)
            {
            oStringBuilder.AppendFormat(

                DateSentClause
                ,
                ">=",
                FormatTime(startTime.Value)
                );
            }

            if (endTime.HasValue)
            {
            oStringBuilder.AppendFormat(

                DateSentClause
                ,
                "<=",
                FormatTime(endTime.Value)
                );
            }

            if ( !String.IsNullOrEmpty(subjectText) )
            {
            // Important note:
            //
            // System.Subject works for the subject on Vista with its original
            // search engine, and with Windows Desktop Search 4.0.  On XP with
            // Windows.Desktop.Search, however, System.Subject does not work.
            // System.Title works in Vista/WDS4.0 and XP/WDS4.0.  (It has not
            // yet been tested on Vista with its original search engine).

            oStringBuilder.AppendFormat(

                " AND Contains(System.Title, '\"{0}\"')"
                ,
                EscapeStringForContains(subjectText)
                );
            }

            if ( !String.IsNullOrEmpty(bodyText) )
            {
            oStringBuilder.AppendFormat(

                " AND Contains ('\"{0}\"')"
                ,
                EscapeStringForContains(bodyText)
                );
            }

            if ( !String.IsNullOrEmpty(folder) )
            {
            oStringBuilder.AppendFormat(

                " AND System.ItemFolderPathDisplay = '{0}'"
                ,
                EscapeStringForEquals(folder)
                );
            }

            if (minimumSize.HasValue)
            {
            oStringBuilder.AppendFormat(

                " AND System.Size >= {0}"
                ,
                minimumSize.Value
                );
            }

            if (maximumSize.HasValue)
            {
            oStringBuilder.AppendFormat(

                " AND System.Size <= {0}"
                ,
                maximumSize.Value
                );
            }

            if (attachmentFilter.HasValue)
            {
            oStringBuilder.AppendFormat(

                " AND System.Message.HasAttachments = {0}"
                ,
                attachmentFilter.Value == AttachmentFilter.NoAttachment ?
                    "FALSE" : "TRUE"
                );

            if (attachmentFilter.Value ==
                AttachmentFilter.HasAttachmentFromParticipant1)
            {
                Debug.Assert( !String.IsNullOrEmpty(sEscapedFirstParticipant) );

                oStringBuilder.AppendFormat(

                    " AND Contains(System.Message.FromAddress, '\"{0}\"')"
                    ,
                    sEscapedFirstParticipant
                    );
            }
            }

            if (hasCc.HasValue)
            {
            oStringBuilder.AppendFormat(

                " AND System.Message.CcAddress IS {0} NULL"
                ,
                hasCc.Value ? "NOT": String.Empty
                );
            }

            if (hasBcc.HasValue)
            {
            oStringBuilder.AppendFormat(

                " AND System.Message.BccAddress IS {0} NULL"
                ,
                hasBcc.Value ? "NOT": String.Empty
                );
            }

            if (isReplyFromParticipant1.HasValue)
            {
            // IMPORTANT NOTE: As of April 2008, the
            // System.Message.IsFwdOrReply message property needed to implement
            // this is always null, so specifying a value here will always
            // return an empty recordset.
            //
            // Note: System.Message.IsFwdOrReply is an Int32, not a Boolean.
            // The documentation doesn't indicate what the possible values are.
            // I'm assuming that 1 means true and 0 means false.

            oStringBuilder.AppendFormat(

                " AND ( System.Message.IsFwdOrReply = {0} AND"
                + " Contains(System.Message.FromAddress, '\"{1}\"') )"
                ,
                isReplyFromParticipant1.Value ? 1 : 0,
                sEscapedFirstParticipant
                );
            }

            return ( oStringBuilder.ToString() );
        }
        //*************************************************************************
        //  Method: CheckAnalyzeMethodArguments()
        //
        /// <summary>
        /// Checks the arguments passed to AnalyzeEmailNetwork().
        /// </summary>
        ///
        /// <param name="participantsCriteria">
        /// See AnalyzeEmailNetwork().
        /// </param>
        ///
        /// <param name="startTime">
        /// See AnalyzeEmailNetwork().
        /// </param>
        ///
        /// <param name="endTime">
        /// See AnalyzeEmailNetwork().
        /// </param>
        ///
        /// <param name="subjectText">
        /// See AnalyzeEmailNetwork().
        /// </param>
        ///
        /// <param name="bodyText">
        /// See AnalyzeEmailNetwork().
        /// </param>
        ///
        /// <param name="folder">
        /// See AnalyzeEmailNetwork().
        /// </param>
        ///
        /// <param name="minimumSize">
        /// See AnalyzeEmailNetwork().
        /// </param>
        ///
        /// <param name="maximumSize">
        /// See AnalyzeEmailNetwork().
        /// </param>
        ///
        /// <param name="attachmentFilter">
        /// See AnalyzeEmailNetwork().
        /// </param>
        ///
        /// <param name="isReplyFromParticipant1">
        /// See AnalyzeEmailNetwork().
        /// </param>
        ///
        /// <remarks>
        /// This method throws an exception if any arguments are invalid.
        /// </remarks>
        //*************************************************************************
        protected void CheckAnalyzeMethodArguments(
            EmailParticipantCriteria [] participantsCriteria,
            Nullable<DateTime> startTime,
            Nullable<DateTime> endTime,
            String subjectText,
            String bodyText,
            String folder,
            Nullable<Int64> minimumSize,
            Nullable<Int64> maximumSize,
            Nullable<AttachmentFilter> attachmentFilter,
            Nullable<Boolean> isReplyFromParticipant1
            )
        {
            AssertValid();

            ArgumentChecker oArgumentChecker = this.ArgumentChecker;

            Boolean bHasFirstParticipant = false;

            if (participantsCriteria != null)
            {
            foreach (EmailParticipantCriteria participantCriteria in
                participantsCriteria)
            {
                if ( String.IsNullOrEmpty(participantCriteria.Participant) )
                {
                    oArgumentChecker.ThrowArgumentException(AnalyzeMethodName,
                        "participantsCriteria",
                        "An email address wasn't specified.",
                        null
                        );
                }

                bHasFirstParticipant = true;
            }
            }

            if (startTime.HasValue && endTime.HasValue &&
            endTime.Value < startTime.Value)
            {
            oArgumentChecker.ThrowArgumentException(AnalyzeMethodName,
                "endTime",

                "The end time must be greater than or equal to the start"
                + " time.",

                null
                );
            }

            CheckAnalyzeMethodArgument(subjectText, "subjectText");
            CheckAnalyzeMethodArgument(bodyText, "bodyText");
            CheckAnalyzeMethodArgument(folder, "folder");

            if (minimumSize.HasValue)
            {
            oArgumentChecker.CheckArgumentPositive(
                AnalyzeMethodName, "minimumSize", minimumSize.Value);
            }

            if (maximumSize.HasValue)
            {
            oArgumentChecker.CheckArgumentPositive(
                AnalyzeMethodName, "maximumSize", maximumSize.Value);
            }

            if (minimumSize.HasValue && maximumSize.HasValue &&
            maximumSize.Value < minimumSize.Value)
            {
            oArgumentChecker.ThrowArgumentException(AnalyzeMethodName,
                "maximumSize",

                "maximumSize must be greater than or equal to"
                + " minimumSize."
                ,
                null
                );
            }

            if (attachmentFilter.HasValue &&
            attachmentFilter.Value ==
                AttachmentFilter.HasAttachmentFromParticipant1
            && !bHasFirstParticipant)
            {
            oArgumentChecker.ThrowArgumentException(AnalyzeMethodName,
                "attachmentFilter",

                "If attachmentFilter is HasAttachmentsFromParticipant1, a"
                + " first participant must also be specified.",

                null
                );
            }

            if (isReplyFromParticipant1.HasValue && !bHasFirstParticipant)
            {
            oArgumentChecker.ThrowArgumentException(AnalyzeMethodName,
                "optionaIsReplyFromParticipant1",

                "If isReplyFromParticipant1 is specified, a first participant"
                + " must also be specified."
                ,
                null
                );
            }
        }