// [END add_performance_max_product_listing_group_tree_2]

            // [START add_performance_max_product_listing_group_tree_3]
            /// <summary>
            /// Creates a list of MutateOperations that remove all the descendents of the specified
            /// AssetGroupListingGroupFilter resource name. The order of removal is post-order,
            /// where all the children (and their children, recursively) are removed first. Then,
            /// the node itself is removed.
            /// </summary>
            /// <returns>A list of MutateOperations</returns>
            public List <MutateOperation> RemoveDescendentsAndFilter(string resourceName)
            {
                List <MutateOperation> operations = new List <MutateOperation>();

                if (this.parentsToChildren.ContainsKey(resourceName))
                {
                    HashSet <string> children = this.parentsToChildren[resourceName];

                    foreach (string child in children)
                    {
                        operations.AddRange(this.RemoveDescendentsAndFilter(child));
                    }
                }

                AssetGroupListingGroupFilterOperation operation =
                    new AssetGroupListingGroupFilterOperation()
                {
                    Remove = resourceName
                };

                operations.Add(
                    new MutateOperation()
                {
                    AssetGroupListingGroupFilterOperation = operation
                }
                    );

                return(operations);
            }
            // [END add_performance_max_product_listing_group_tree_5]

            // [START add_performance_max_product_listing_group_tree_6]
            /// <summary>
            /// Creates a MutateOperation that creates a child AssetGroupListingGroupFilter
            /// for the factory's AssetGroup.
            ///
            /// Use this method if the filter won't have child filters. Otherwise, use the
            /// CreateSubdivision method.
            /// </summary>
            /// <param name="parent">The ID of the parent AssetGroupListingGroupFilter.</param>
            /// <param name="id">The ID of AssetGroupListingGroupFilter that will be
            /// created.</param>
            /// <param name="dimension">The dimension to associate with the
            /// AssetGroupListingGroupFilter.</param>
            /// <returns>A MutateOperation</returns>
            public MutateOperation CreateUnit(
                long parent,
                long id,
                ListingGroupFilterDimension dimension)
            {
                AssetGroupListingGroupFilter listingGroupFilter = new AssetGroupListingGroupFilter()
                {
                    ResourceName = ResourceNames.AssetGroupListingGroupFilter(
                        this.customerId,
                        this.assetGroupId,
                        id
                        ),

                    AssetGroup = ResourceNames.AssetGroup(
                        this.customerId,
                        this.assetGroupId
                        ),

                    ParentListingGroupFilter = ResourceNames.AssetGroupListingGroupFilter(
                        this.customerId,
                        this.assetGroupId,
                        parent
                        ),

                    // We must use the UnitIncluded type to indicate that the
                    // AssetGroupListingGroupFilter won't have children.
                    Type = ListingGroupFilterType.UnitIncluded,

                    // Because this is a Performance Max campaign for retail, we need to specify
                    // that this is in the shopping vertical.
                    Vertical = ListingGroupFilterVertical.Shopping,

                    CaseValue = dimension
                };

                AssetGroupListingGroupFilterOperation filterOperation =
                    new AssetGroupListingGroupFilterOperation()
                {
                    Create = listingGroupFilter
                };

                return(new MutateOperation()
                {
                    AssetGroupListingGroupFilterOperation = filterOperation
                });
            }
            // [START add_performance_max_product_listing_group_tree_4]
            /// <summary>
            /// Creates a MutateOperation that creates a root AssetGroupListingGroupFilter for the
            /// factory's AssetGroup.
            ///
            /// The root node or partition is the default, which is displayed as "All Products".
            /// </summary>
            /// <returns>A MutateOperation</returns>
            public MutateOperation CreateRoot()
            {
                AssetGroupListingGroupFilter listingGroupFilter = new AssetGroupListingGroupFilter()
                {
                    ResourceName = ResourceNames.AssetGroupListingGroupFilter(
                        this.customerId,
                        this.assetGroupId,
                        this.rootListingGroupId
                        ),

                    AssetGroup = ResourceNames.AssetGroup(
                        this.customerId,
                        this.assetGroupId
                        ),

                    // Since this is the root node, do not set the ParentListingGroupFilter. For all
                    // other nodes, this would refer to the parent listing group filter resource
                    // name.
                    // ParentListingGroupFilter = "<PARENT FILTER NAME>"

                    // Unlike AddPerformanceMaxRetailCampaign, the type for the root node here must
                    // be Subdivision because we add child partitions under it.
                    Type = ListingGroupFilterType.Subdivision,

                    // Because this is a Performance Max campaign for retail, we need to specify
                    // that this is in the shopping vertical.
                    Vertical = ListingGroupFilterVertical.Shopping
                };

                AssetGroupListingGroupFilterOperation operation =
                    new AssetGroupListingGroupFilterOperation()
                {
                    Create = listingGroupFilter
                };

                return(new MutateOperation()
                {
                    AssetGroupListingGroupFilterOperation = operation
                });
            }
        // [END add_performance_max_product_listing_group_tree_7]

        /// <summary>
        /// Prints the details of a MutateGoogleAdsResponse. Parses the "response" oneof field name
        /// and uses it to extract the new entity's name and resource name.
        /// </summary>
        /// <param name="request">A MutateGoogleAdsRequest instance.</param>
        /// <param name="response">A MutateGoogleAdsResponse instance.</param>
        private void PrintResponseDetails(MutateGoogleAdsRequest request, MutateGoogleAdsResponse response)
        {
            // Parse the Mutate response to print details about the entities that were created
            // in the request.
            for (int i = 0; i < response.MutateOperationResponses.Count; i++)
            {
                MutateOperation         operationRequest  = request.MutateOperations[i];
                MutateOperationResponse operationResponse = response.MutateOperationResponses[i];

                if (operationResponse.ResponseCase != MutateOperationResponse.ResponseOneofCase.AssetGroupListingGroupFilterResult)
                {
                    string entityName = operationResponse.ResponseCase.ToString();
                    // Trim the substring "Result" from the end of the entity name.
                    entityName = entityName.Remove(entityName.Length - 6);

                    Console.WriteLine($"Unsupported entity type: {entityName}");
                }

                string resourceName = operationResponse.AssetGroupListingGroupFilterResult.ResourceName;
                AssetGroupListingGroupFilterOperation assetOperation = operationRequest.AssetGroupListingGroupFilterOperation;

                switch (assetOperation.OperationCase)
                {
                case AssetGroupListingGroupFilterOperation.OperationOneofCase.Create:
                    Console.WriteLine(
                        $"Created a(n) AssetGroupListingGroupFilter with resource name: '{resourceName}'.");
                    break;

                case AssetGroupListingGroupFilterOperation.OperationOneofCase.Remove:
                    Console.WriteLine(
                        $"Removed a(n) AssetGroupListingGroupFilter with resource name: '{resourceName}'.");
                    break;

                default:
                    Console.WriteLine($"Unsupported operation type: {assetOperation.OperationCase.ToString()}");
                    continue;
                }
            }
        }
        // [END add_performance_max_retail_campaign_9]

        // [START add_performance_max_retail_campaign_10]
        /// <summary>
        /// Creates a list of MutateOperations that create a new asset group
        /// listing group filter.
        /// </summary>
        /// <param name="assetGroupResourceName">The resource name of the asset group.</param>
        /// <returns>A list of mutate operations.</returns>
        private List <MutateOperation> CreateAssetGroupListingGroupOperations(
            string assetGroupResourceName)
        {
            List <MutateOperation> operations = new List <MutateOperation>();

            // Creates a new ad group criterion containing the "default" listing group (All
            // products).
            AssetGroupListingGroupFilter listingGroupFilter = new AssetGroupListingGroupFilter()
            {
                AssetGroup = assetGroupResourceName,

                // Since this is the root node, do not set the ParentListingGroupFilter. For all
                // other nodes, this would refer to the parent listing group filter resource name.
                // ParentListingGroupFilter = "<PARENT FILTER NAME>"

                // The UnitIncluded means this node has no children.
                Type = ListingGroupFilterType.UnitIncluded,

                // Because this is a Performance Max campaign for retail, we need to specify that
                // this is in the shopping vertical.
                Vertical = ListingGroupFilterVertical.Shopping
            };

            AssetGroupListingGroupFilterOperation operation =
                new AssetGroupListingGroupFilterOperation()
            {
                Create = listingGroupFilter
            };

            operations.Add(
                new MutateOperation()
            {
                AssetGroupListingGroupFilterOperation = operation
            }
                );

            return(operations);
        }