/// <summary>
        /// Gets the record number if the tracking options indicate it should be included
        /// </summary>
        /// <param name="record">
        /// The record. 
        /// </param>
        /// <param name="option">
        /// The options. 
        /// </param>
        /// <returns>
        /// A string with the record number if the TrackingOptions.RecordNumber flag is used, otherwise an empty string 
        /// </returns>
        public static string GetRecordNumber(this TrackingRecord record, TrackingOption option = TrackingOption.Default)
        {
            var tsb = new TraceStringBuilder();
            if (option.HasFlag(TrackingOption.RecordNumber))
            {
                tsb.AppendFormat("{0}: ", record.RecordNumber);
            }

            return tsb.ToString();
        }
        /// <summary>
        /// Returns the record as a formatted string
        /// </summary>
        /// <param name="record">
        /// The record to trace. 
        /// </param>
        /// <param name="option">
        /// The tracking options to use, if not provided will use the TrackingOptions.Default value 
        /// </param>
        /// <param name="tabs">
        /// the tabs The tabs. 
        /// </param>
        /// <returns>
        /// The formatted tracking record 
        /// </returns>
        public static string ToFormattedString(
            this FaultPropagationRecord record, TrackingOption option = TrackingOption.Default, int tabs = 0)
        {
            var tsb = new TraceStringBuilder(tabs);
            tsb.AppendFormat(
                "{0}Fault source {1}", record.GetRecordNumber(option), record.FaultSource.ToFormattedString());

            TrackingRecordExtensions.AppendInstance(
                tsb, option, record.InstanceId, record.Annotations, record.EventTime);
            return tsb.ToString();
        }
        /// <summary>
        /// The to formatted string.
        /// </summary>
        /// <param name="tabs">
        /// the tabs The tabs. 
        /// </param>
        /// <returns>
        /// The System.String. 
        /// </returns>
        public string ToFormattedString(int tabs = 0)
        {
            var tsb = new TraceStringBuilder(tabs);
            tsb.AppendTitle(this);
            using (tsb.IndentBlock())
            {
                tsb.AppendProperty("InvokeCount", this.InvokeCount);
            }

            return tsb.ToString();
        }
        /// <summary>
        /// The to formatted string.
        /// </summary>
        /// <param name="trackingQuery">
        /// The tracking query. 
        /// </param>
        /// <param name="tabs"> the tabs
        /// The number of tabs 
        /// </param>
        /// <returns>
        /// The System.String. 
        /// </returns>
        public static string ToFormattedString(this TrackingQuery trackingQuery, int tabs = 0)
        {
            var activityScheduledQuery = trackingQuery as ActivityScheduledQuery;
            if (activityScheduledQuery != null)
            {
                return activityScheduledQuery.ToFormattedString(tabs);
            }

            var activityStateQuery = trackingQuery as ActivityStateQuery;
            if (activityStateQuery != null)
            {
                return activityStateQuery.ToFormattedString(tabs);
            }

            var bookmarkResumptionQuery = trackingQuery as BookmarkResumptionQuery;
            if (bookmarkResumptionQuery != null)
            {
                return bookmarkResumptionQuery.ToFormattedString(tabs);
            }

            var cancelRequestedQuery = trackingQuery as CancelRequestedQuery;
            if (cancelRequestedQuery != null)
            {
                return cancelRequestedQuery.ToFormattedString(tabs);
            }

            var customTrackingQuery = trackingQuery as CustomTrackingQuery;
            if (customTrackingQuery != null)
            {
                return customTrackingQuery.ToFormattedString(tabs);
            }

            var faultPropagationQuery = trackingQuery as FaultPropagationQuery;
            if (faultPropagationQuery != null)
            {
                return faultPropagationQuery.ToFormattedString(tabs);
            }

            var workflowInstanceQuery = trackingQuery as WorkflowInstanceQuery;
            if (workflowInstanceQuery != null)
            {
                return workflowInstanceQuery.ToFormattedString(tabs);
            }

            var tsb = new TraceStringBuilder(tabs);

            tsb.AppendLine(trackingQuery.GetType().Name);
            using (tsb.IndentBlock())
            {
                tsb.AppendDictionary("QueryAnnotations", trackingQuery.QueryAnnotations);
            }

            return tsb.ToString();
        }
        /// <summary>
        /// Returns the record as a formatted string
        /// </summary>
        /// <param name="record">
        /// The record to trace. 
        /// </param>
        /// <param name="option">
        /// The tracking options to use, if not provided will use the TrackingOptions.Default value 
        /// </param>
        /// <param name="tabs"> the tabs
        /// The tabs.
        /// </param>
        /// <returns>
        /// The formatted tracking record 
        /// </returns>
        public static string ToFormattedString(
            this SendMessageRecord record, TrackingOption option = TrackingOption.Default, int tabs = 0)
        {
            var tsb = new TraceStringBuilder(tabs);
            tsb.AppendFormat(
                "{0}Activity {1} sent message E2E Activity ID {3}",
                record.GetRecordNumber(option),
                record.Activity.ToFormattedString(),
                record.E2EActivityId);

            TrackingRecordExtensions.AppendInstance(tsb, option, record.InstanceId, record.Annotations, record.EventTime);
            return tsb.ToString();
        }
        /// <summary>
        /// Returns the record as a formatted string
        /// </summary>
        /// <param name="record">
        /// The record to trace. 
        /// </param>
        /// <param name="option">
        /// The tracking options to use, if not provided will use the TrackingOptions.Default value 
        /// </param>
        /// <param name="tabs"> the tabs
        /// The tabs.
        /// </param>
        /// <returns>
        /// The formatted tracking record 
        /// </returns>
        public static string ToFormattedString(
            this WorkflowInstanceSuspendedRecord record, TrackingOption option = TrackingOption.Default, int tabs = 0)
        {
            var tsb = new TraceStringBuilder(tabs);

            tsb.AppendFormat(
                "{0}WorkflowInstance \"{1}\" Suspended Reason \"{2}\"",
                record.GetRecordNumber(option),
                record.ActivityDefinitionId,
                record.Reason);
            TrackingRecordExtensions.AppendInstance(tsb, option, record.InstanceId, record.Annotations, record.EventTime);
            return tsb.ToString();
        }
        /// <summary>
        /// The to formatted string.
        /// </summary>
        /// <param name="query">
        /// The query. 
        /// </param>
        /// <param name="tabs"> the tabs
        /// The tabs. 
        /// </param>
        /// <returns>
        /// The System.String. 
        /// </returns>
        public static string ToFormattedString(this WorkflowInstanceQuery query, int tabs = 0)
        {
            var tsb = new TraceStringBuilder(tabs);

            tsb.AppendLine(query.GetType().Name);
            using (tsb.IndentBlock())
            {
                tsb.AppendCollection("States", query.States);
                tsb.AppendDictionary("QueryAnnotations", query.QueryAnnotations);
            }

            return tsb.ToString();
        }
        /// <summary>
        /// The to formatted string.
        /// </summary>
        /// <param name="query">
        /// The query. 
        /// </param>
        /// <param name="tabs"> the tabs
        /// The tab indent level.
        /// </param>
        /// <returns>
        /// The System.String. 
        /// </returns>
        public static string ToFormattedString(this BookmarkResumptionQuery query, int tabs = 0)
        {
            var tsb = new TraceStringBuilder(tabs);

            tsb.AppendLine(query.GetType().Name);
            using (tsb.IndentBlock())
            {
                tsb.AppendLine("Name: {0}", query.Name);
                tsb.AppendDictionary("QueryAnnotations", query.QueryAnnotations);
            }

            return tsb.ToString();
        }
        public void AppendFormatWithArgsAndTabsAppendsText()
        {
            // Arrange
            const string Expected = "test";
            var tsb = new TraceStringBuilder(2);

            // Act
            tsb.Append(Expected);
            var actual = tsb.ToString();

            // Assert
            Assert.AreEqual("\t\t" + Expected, actual);
        }
        /// <summary>
        /// The to formatted string.
        /// </summary>
        /// <param name="query">
        /// The query. 
        /// </param>
        /// <param name="tabs"> the tabsThe tabs count</param>
        /// <returns>
        /// The System.String. 
        /// </returns>
        public static string ToFormattedString(this ActivityScheduledQuery query, int tabs = 0)
        {
            var tsb = new TraceStringBuilder(tabs);

            tsb.AppendLine(query.GetType().Name);
            using (tsb.IndentBlock())
            {
                tsb.AppendLine("ActivityName: {0}", query.ActivityName);
                tsb.AppendLine("ChildActivityName: {0}", query.ChildActivityName);
                tsb.AppendDictionary("QueryAnnotations", query.QueryAnnotations);
            }

            return tsb.ToString();
        }
        public void AppendAppendsText()
        {
            // Arrange
            const string Expected = "test";

            var tsb = new TraceStringBuilder();

            // Act
            tsb.Append(Expected);
            var actual = tsb.ToString();

            // Assert
            Assert.AreEqual(Expected, actual);
        }
        /// <summary>
        /// The to formatted string.
        /// </summary>
        /// <param name="query">
        /// The query. 
        /// </param>
        /// <param name="tabs"> the tabs
        /// The tabs indent level.
        /// </param>
        /// <returns>
        /// The System.String. 
        /// </returns>
        public static string ToFormattedString(this FaultPropagationQuery query, int tabs = 0)
        {
            var tsb = new TraceStringBuilder(tabs);

            tsb.AppendLine(query.GetType().Name);
            using (tsb.IndentBlock())
            {
                tsb.AppendLine("FaultHandlerActivityName: {0}", query.FaultHandlerActivityName);
                tsb.AppendLine("FaultSourceActivityName: {0}", query.FaultSourceActivityName);
                tsb.AppendDictionary("QueryAnnotations", query.QueryAnnotations);
            }

            return tsb.ToString();
        }
        /// <summary>
        /// Returns the record as a formatted string
        /// </summary>
        /// <param name="record">
        /// The record to trace. 
        /// </param>
        /// <param name="option">
        /// The tracking options to use, if not provided will use the TrackingOptions.Default value 
        /// </param>
        /// <param name="tabs">
        /// the tabs 
        /// </param>
        /// <returns>
        /// The formatted tracking record 
        /// </returns>
        public static string ToFormattedString(
            this ActivityScheduledRecord record, TrackingOption option = TrackingOption.Default, int tabs = 0)
        {
            var tsb = new TraceStringBuilder(tabs);

            tsb.AppendFormat(
                "{0}{1} scheduled {2}",
                record.GetRecordNumber(option),
                record.Activity.ToFormattedString(),
                record.Child.ToFormattedString("child activity"));

            TrackingRecordExtensions.AppendInstance(
                tsb, option, record.InstanceId, record.Annotations, record.EventTime);
            return tsb.ToString();
        }
        /// <summary>
        /// Converts a list of CustomTrackingRecord to a comma delimited string with activity names
        /// </summary>
        /// <param name="records">
        /// The records. 
        /// </param>
        /// <returns>
        /// The delimited list. 
        /// </returns>
        public static string ToDelimitedStateList(this IEnumerable<CustomTrackingRecord> records)
        {
            var result = new TraceStringBuilder();

            foreach (var record in records)
            {
                if (result.Length > 0)
                {
                    result.Append(", ");
                }

                result.AppendFormat("{0}", record.Data["currentstate"]);
            }

            return result.ToString();
        }
        /// <summary>
        /// The to formatted string.
        /// </summary>
        /// <param name="query">
        /// The query. 
        /// </param>
        /// <param name="tabs"> the tabs
        /// The tabs.
        /// </param>
        /// <returns>
        /// The System.String. 
        /// </returns>
        public static string ToFormattedString(this ActivityStateQuery query, int tabs = 0)
        {
            var tsb = new TraceStringBuilder(tabs);

            tsb.AppendLine(query.GetType().Name);
            using (tsb.IndentBlock())
            {
                tsb.AppendLine("ActivityName: {0}", query.ActivityName);
                tsb.AppendCollection("Arguments", query.Arguments);
                tsb.AppendDictionary("QueryAnnotations", query.QueryAnnotations);
                tsb.AppendCollection("States", query.States);
                tsb.AppendCollection("Variables", query.Variables);
            }

            return tsb.ToString();
        }
        /// <summary>
        /// Returns the record as a formatted string
        /// </summary>
        /// <param name="record">
        /// The record to trace. 
        /// </param>
        /// <param name="option">
        /// The tracking options to use, if not provided will use the TrackingOptions.Default value 
        /// </param>
        /// <returns>
        /// The formatted tracking record 
        /// </returns>
        public static string ToFormattedString(
            this ReceiveMessageRecord record, TrackingOption option = TrackingOption.Default, int tabs = 0)
        {
            var sb =
                new TraceStringBuilder(
                    tabs,
                        "{0}Activity [{1}] \"{2}\" received Message ID {3}, E2E Activity ID {4}",
                        record.GetRecordNumber(option),
                        record.Activity != null ? record.Activity.Id : Constants.Null,
                        record.Activity != null ? record.Activity.Name : Constants.Null,
                        record.MessageId,
                        record.E2EActivityId);

            TrackingRecordExtensions.AppendInstance(sb, option, record.InstanceId, record.Annotations, record.EventTime);
            return sb.ToString();
        }
        /// <summary>
        /// Returns the record as a formatted string
        /// </summary>
        /// <param name="record">
        /// The record to trace. 
        /// </param>
        /// <param name="option">
        /// The tracking options to use, if not provided will use the TrackingOptions.Default value 
        /// </param>
        /// <param name="tabs"> the tabs
        /// The tabs 
        /// </param>
        /// <returns>
        /// The formatted tracking record 
        /// </returns>
        public static string ToFormattedString(
            this WorkflowInstanceUnhandledExceptionRecord record, 
            TrackingOption option = TrackingOption.Default, 
            int tabs = 0)
        {
            var tsb = new TraceStringBuilder(tabs);

            tsb.AppendFormat(
                "{0}WorkflowInstance \"{1}\" Unhandled Exception Source \"{2}\" Exception <{3}>",
                record.GetRecordNumber(option),
                record.ActivityDefinitionId,
                record.FaultSource.Name,
                record.UnhandledException);

            TrackingRecordExtensions.AppendInstance(tsb, option, record.InstanceId, record.Annotations, record.EventTime);
            return tsb.ToString();
        }
        /// <summary>
        /// Returns the record as a formatted string
        /// </summary>
        /// <param name="record">
        /// The record to trace. 
        /// </param>
        /// <param name="option">
        /// The tracking options to use, if not provided will use the TrackingOptions.Default value 
        /// </param>
        /// <param name="tabs">
        /// the tabs The tabs. 
        /// </param>
        /// <returns>
        /// The formatted tracking record 
        /// </returns>
        public static string ToFormattedString(
            this BookmarkResumptionRecord record, TrackingOption option = TrackingOption.Default, int tabs = 0)
        {
            var traceablePayload = record.Payload as ITraceable;

            var tsb = new TraceStringBuilder(tabs);
            tsb.AppendFormat(
                "{0}Bookmark \"{1}\" resumed with payload <{2}> owner {3}",
                record.GetRecordNumber(option),
                record.BookmarkName ?? Constants.Null,
                traceablePayload != null ? traceablePayload.ToFormattedString() : record.Payload ?? Constants.Null,
                record.Owner.ToFormattedString());

            TrackingRecordExtensions.AppendInstance(
                tsb, option, record.InstanceId, record.Annotations, record.EventTime);
            return tsb.ToString();
        }
        /// <summary>
        /// Returns the record as a formatted string
        /// </summary>
        /// <param name="record">
        /// The record to trace. 
        /// </param>
        /// <param name="option">
        /// The tracking options to use, if not provided will use the TrackingOptions.Default value 
        /// </param>
        /// <param name="tabs"> the tabs
        /// The tabs.
        /// </param>
        /// <returns>
        /// The formatted tracking record 
        /// </returns>
        public static string ToFormattedString(
            this CancelRequestedRecord record, TrackingOption option = TrackingOption.Default, int tabs = 0)
        {
            var owner = record.Activity == null ? "Host" : record.Activity.ToFormattedString();

            var tsb = new TraceStringBuilder(tabs);

            tsb.AppendFormat(
                "{0}{1} requests cancel of activity [{2}] \"{3}\"",
                record.GetRecordNumber(option),
                owner,
                record.Child != null ? record.Child.Id : Constants.Null,
                record.Child != null ? record.Child.Name : Constants.Null);

            TrackingRecordExtensions.AppendInstance(tsb, option, record.InstanceId, record.Annotations, record.EventTime);
            return tsb.ToString();
        }
        /// <summary>
        /// The to formatted string.
        /// </summary>
        /// <param name="trackingProfile">
        /// The tracking profile.
        /// </param>
        /// <param name="tabs"> the tabs
        /// The tabs.
        /// </param>
        /// <returns>
        /// The System.String.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// An argument was null
        /// </exception>
        public static string ToFormattedString(this TrackingProfile trackingProfile, int tabs = 0)
        {
            Contract.Requires(trackingProfile != null);
            if (trackingProfile == null)
            {
                throw new ArgumentNullException("trackingProfile");
            }

            var tsb = new TraceStringBuilder(tabs);

            tsb.AppendTitle("Tracking profile: {0}", trackingProfile.Name);
            using (tsb.IndentBlock())
            {
                tsb.AppendLine("ActivityDefinitionId : {0}", trackingProfile.ActivityDefinitionId);
                tsb.AppendLine("ImplementationVisibility : {0}", trackingProfile.ImplementationVisibility);
                tsb.AppendCollection("Queries", trackingProfile.Queries, (trackingQuery, t) => trackingQuery.ToFormattedString(t));
            }

            var formattedString = tsb.ToString();
            return formattedString;
        }
        /// <summary>
        /// Returns the record as a formatted string
        /// </summary>
        /// <param name="record">
        /// The record to trace. 
        /// </param>
        /// <param name="option">
        /// The tracking options to use, if not provided will use the TrackingOptions.Default value 
        /// </param>
        /// <param name="tabs"> the tabs
        /// The tabs. 
        /// </param>
        /// <returns>
        /// The formatted tracking record 
        /// </returns>
        public static string ToFormattedString(
            this CustomTrackingRecord record, TrackingOption option = TrackingOption.Default, int tabs = 0)
        {
            var tsb = new TraceStringBuilder(tabs);

            tsb.AppendFormat(
                "{0}CustomTrackingRecord [{1}] \"{2}\"",
                record.GetRecordNumber(option),
                record.Activity.GetId(),
                record.Name ?? Constants.Null);

            TrackingRecordExtensions.AppendInstance(
                tsb,
                option,
                instanceId: record.InstanceId,
                annotations: record.Annotations,
                arguments: null,
                variables: null,
                data: record.Data,
                eventTime: record.EventTime);

            return tsb.ToString();
        }
 /// <summary>
 /// The to formatted string.
 /// </summary>
 /// <param name="tabs">
 /// the tabs The tabs. 
 /// </param>
 /// <returns>
 /// The System.String. 
 /// </returns>
 public string ToFormattedString(int tabs = 0)
 {
     var tsb = new TraceStringBuilder(tabs);
     tsb.AppendLine(this.GetType().Name);
     tsb.AppendCollection("Children", this.Children);
     return tsb.ToString();
 }
 /// <summary>
 /// The to formatted string.
 /// </summary>
 /// <param name="tabs">
 /// the tabs The tabs. 
 /// </param>
 /// <returns>
 /// The System.String. 
 /// </returns>
 public string ToFormattedString(int tabs = 0)
 {
     var tsb = new TraceStringBuilder(tabs);
     tsb.AppendTitle(this.GetType().Name);
     tsb.AppendCollection("Records", this.Records, (record, i) => record.ToFormattedString(tabs: i));
     return tsb.ToString();
 }
        /// <summary>
        /// Returns the record as a formatted string
        /// </summary>
        /// <param name="record">
        /// The record to trace. 
        /// </param>
        /// <param name="option">
        /// The tracking options to use, if not provided will use the TrackingOptions.Default value 
        /// </param>
        /// <param name="tabs"> the tabs
        /// The tabs.
        /// </param>
        /// <returns>
        /// The formatted tracking record 
        /// </returns>
        public static string ToFormattedString(
            this StateMachineStateRecord record, TrackingOption option = TrackingOption.Default, int tabs = 0)
        {
            var tsb = new TraceStringBuilder(tabs);

            tsb.AppendFormat(
                "{0}StateMachineStateRecord [{1}] \"{2}\" CurrentStateMachine State <{3}>",
                record.GetRecordNumber(option),
                record.Activity.GetId(),
                record.StateMachineName ?? Constants.Null,
                record.StateName);

            TrackingRecordExtensions.AppendInstance(
                tsb, option, record.InstanceId, record.Annotations, null, null, record.Data, record.EventTime);

            return tsb.ToString();
        }
        /// <summary>
        /// The to formatted string.
        /// </summary>
        /// <param name="tabs">
        /// the tabs The tabs. 
        /// </param>
        /// <returns>
        /// The System.String. 
        /// </returns>
        public string ToFormattedString(int tabs = 0)
        {
            var tsb = new TraceStringBuilder(tabs);
            tsb.AppendLine(this.GetType().Name);
            using (tsb.IndentBlock())
            {
                tsb.AppendProperty("Message", this.Message);
                tsb.AppendProperty("BookmarkName", this.BookmarkName);
                tsb.AppendProperty("Result", this.Result);
                tsb.AppendProperty("Value", this.Value);
            }

            return tsb.ToString();
        }
        public void OpenBraceSetsOpenBrace()
        {
            // Arrange
            const string Expected = @"Test[
            }
            ";

            // Act
            var tsb = new TraceStringBuilder("Test") { OpenBrace = '[' };
            using (tsb.IndentBlock())
            {
            }

            var actual = tsb.ToString();

            // Assert
            Assert.AreEqual(Expected, actual);
        }
        public void UnindentDecrementsTab()
        {
            // Arrange
            const int Expected = 0;

            var tsb = new TraceStringBuilder();
            tsb.Indent();

            // Act
            tsb.Unindent();
            var actual = tsb.Tabs;

            // Assert
            Assert.AreEqual(Expected, actual);
        }
        public void UnindentZeroThrowsInvalidOperation()
        {
            // Arrange
            var tsb = new TraceStringBuilder();

            // Act / Assert
            AssertHelper.Throws<InvalidOperationException>(tsb.Unindent);
        }
        public void AppendFormatWithArgsAppendsText()
        {
            // Arrange
            const string Expected = "test";
            const string Format = Expected + " {0}";
            var tsb = new TraceStringBuilder();

            // Act
            tsb.AppendFormat(Format, 1);
            var actual = tsb.ToString();

            // Assert
            Assert.AreEqual(Expected + " 1", actual);
        }
                /// <summary>
                /// The to formatted string.
                /// </summary>
                /// <param name="tabs"> the tabs
                /// The tabs.
                /// </param>
                /// <returns>
                /// The System.String.
                /// </returns>
                public string ToFormattedString(int tabs = 0)
                {
                    var tsb = new TraceStringBuilder(tabs);
                    tsb.AppendTitle(this.GetType().Name);
                    using (tsb.IndentBlock())
                    {
                        tsb.AppendCollection("Strings", this.Strings);
                    }

                    return tsb.ToString();
                }