/// <summary>
        /// Gathers merge blocks in current document.
        /// </summary>
        /// <returns>Merge blocks in current document.</returns>
        public static List <MergeBlock> GetMergeBlocksFlattened(ServerTextControl textControl)
        {
            ValidateMergeBlockNesting(textControl);
            var result = new List <MergeBlock>();

            // Get a list of all block start and end markers ordered by their start position:
            var blockMarkers = GetBlockMarkersOrdered(textControl);

            // Gather blocks:

            var startMarkers = new Stack <TXTextControl.DocumentTarget>();

            foreach (var marker in blockMarkers)
            {
                if (marker.TargetName.StartsWith(MergeBlock.BlockStartPrefix, StringComparison.OrdinalIgnoreCase))
                {
                    // Start marker:
                    startMarkers.Push(marker);
                }
                else if (marker.TargetName.StartsWith(MergeBlock.BlockEndPrefix, StringComparison.OrdinalIgnoreCase))
                {
                    // End marker:
                    TXTextControl.DocumentTarget startMarker = startMarkers.Pop();   // Get currently open start marker
                    var blockNew = new MergeBlock(startMarker, marker);
                    result.Add(blockNew);
                }
            }

            result.Sort(MergeBlock.SortPosition);
            return(result);
        }
 /// <summary>
 /// Constructor.
 /// </summary>
 /// <param name="startMarker">Block start marker.</param>
 /// <param name="endMarker">Block end marker.</param>
 public MergeBlock(TXTextControl.DocumentTarget startMarker, TXTextControl.DocumentTarget endMarker)
 {
     StartMarker = startMarker;
     EndMarker   = endMarker;
     _fields     = new List <MergeField>();
     _children   = new List <MergeBlock>();
 }
        /// <summary>
        /// Validates merge block nesting
        /// </summary>
        public static void ValidateMergeBlockNesting(ServerTextControl textControl)
        {
            // Get a list of all block start and end markers ordered by their start position:
            var blockMarkers = GetBlockMarkersOrdered(textControl);
            var startMarkers = new Stack <TXTextControl.DocumentTarget>();

            foreach (var marker in blockMarkers)
            {
                if (marker.TargetName.StartsWith(MergeBlock.BlockStartPrefix, StringComparison.OrdinalIgnoreCase))
                {
                    // Start marker:
                    startMarkers.Push(marker);
                }
                else if (marker.TargetName.StartsWith(MergeBlock.BlockEndPrefix, StringComparison.OrdinalIgnoreCase))
                {
                    // End marker:
                    var endMarkerName = marker.TargetName.Substring(MergeBlock.BlockEndPrefix.Length);               // Get block name
                    TXTextControl.DocumentTarget startMarker = (startMarkers.Count > 0) ? startMarkers.Pop() : null; // Get currently open start marker
                    var startMarkerName
                        = (startMarker != null)
                       ? startMarker.TargetName.Substring(MergeBlock.BlockStartPrefix.Length)
                       : string.Empty;

                    if (endMarkerName.ToLower() != startMarkerName.ToLower())
                    {
                        if (startMarkerName != string.Empty)
                        {
                            throw new Exception(
                                      "Block nesting invalid somewhere after block start marker “"
                                      + MergeBlock.BlockStartPrefix + startMarkerName + "”.");
                        }
                        else
                        {
                            throw new Exception(
                                      "Invalid block end marker “"
                                      + MergeBlock.BlockEndPrefix + endMarkerName + "”.");
                        }
                    }
                }
            }
        }