/// <summary>
        /// Build permission for specified resource (e.g. datasource, project, workbook), user/group, and capability
        /// </summary>
        /// <param name="granteeType"></param>
        /// <param name="granteeId"></param>
        /// <param name="capabilityName"></param>
        /// <param name="capabilityMode"></param>
        public static TableauPermission BuildDefaultPermission(
            GranteeType granteeType,
            string granteeId,
            CapabilityName capabilityName,
            CapabilityMode capabilityMode
            )
        {
            var permission = new TableauPermission();

            var granteeCapabilities = new TableauGranteeCapabilities();

            switch (granteeType)
            {
            case GranteeType.Group:
                granteeCapabilities.Group = new TableauGroup()
                {
                    Id = granteeId
                };
                break;

            case GranteeType.User:
                granteeCapabilities.User = new TableauUser()
                {
                    Id = granteeId
                };
                break;

            default:
                throw new Exception("Unsupported user/group type");
            }
            granteeCapabilities.Capabilities = new TableauCapabilities()
            {
                Capability = new TableauCapability[] {
                    new TableauCapability()
                    {
                        Name = capabilityName.ToString(),
                        Mode = capabilityMode.ToString()
                    }
                }
            };

            permission.GranteeCapabilities = new TableauGranteeCapabilities[] { granteeCapabilities };

            return(permission);
        }
        /// <summary>
        /// <see cref="ITableauPermissionService.DeleteDefaultPermissionAsync"/>
        /// </summary>
        public async Task DeleteDefaultPermissionAsync(
            string projectId,
            ResourceType resourceType,
            TableauPermission permission
            )
        {
            _logger?.Debug($"Deleting default {resourceType.ToString().ToLower()} permission for project {projectId}");

            foreach (var granteeCapability in permission.GranteeCapabilities)
            {
                var granteeTypeName = "";
                var granteeId       = "";
                if (granteeCapability.Group != null)
                {
                    granteeTypeName = GranteeType.Group.ToString().ToLower();
                    granteeId       = granteeCapability.Group.Id;
                }
                else if (granteeCapability.User != null)
                {
                    granteeTypeName = GranteeType.User.ToString().ToLower();
                    granteeId       = granteeCapability.User.Id;
                }
                else
                {
                    throw new Exception("Unsupported resource/object type");
                }

                foreach (var capability in granteeCapability.Capabilities.Capability)
                {
                    _logger?.Debug(
                        String.Format(
                            "Deleting default {0} permission on {1} for {2} {3}: {4} {5}",
                            resourceType.ToString().ToLower(),
                            projectId,
                            granteeTypeName,
                            granteeId,
                            capability.Mode,
                            capability.Name
                            )
                        );

                    var url = _tableauApiService.SiteUrl.AppendUri(
                        $"projects/{projectId}/default-permissions/" +
                        $"{resourceType.ToString().ToLower()}s/" +
                        $"{granteeTypeName}s/{granteeId}/" +
                        $"{capability.Name}/{capability.Mode}"
                        );

                    try
                    {
                        var responseString = await _tableauApiService.SendDeleteAsync(url).ConfigureAwait(false);

                        _logger?.Debug($"Response: {responseString}");
                        _logger?.Debug($"Default permission deleted");
                    }
                    catch (Exception ex)
                    {
                        _logger?.Error($"Error deleting default permission: {ex.ToString()}");
                    }
                }
            }

            _logger?.Debug($"Default permission deleted");
        }
        /// <summary>
        /// <see cref="ITableauPermissionService.AddDefaultPermissionAsync"/>
        /// </summary>
        public async Task <TableauPermission> AddDefaultPermissionAsync(
            string projectId,
            ResourceType resourceType,
            TableauPermission permission
            )
        {
            _logger?.Debug($"Adding default {resourceType.ToString().ToLower()} permission for project {projectId}");

            foreach (var granteeCapability in permission.GranteeCapabilities)
            {
                var granteeTypeName = "";
                var granteeId       = "";
                if (granteeCapability.Group != null)
                {
                    granteeTypeName = GranteeType.Group.ToString().ToLower();
                    granteeId       = granteeCapability.Group.Id;
                }
                else if (granteeCapability.User != null)
                {
                    granteeTypeName = GranteeType.User.ToString().ToLower();
                    granteeId       = granteeCapability.User.Id;
                }
                else
                {
                    throw new Exception("Unsupported grantee type");
                }

                foreach (var capability in granteeCapability.Capabilities.Capability)
                {
                    _logger?.Debug(
                        String.Format(
                            "Adding default {0} permission on {1} for {2} {3}: {4} {5}",
                            resourceType.ToString().ToLower(),
                            projectId,
                            granteeTypeName,
                            granteeId,
                            capability.Mode,
                            capability.Name
                            )
                        );
                }
            }

            var url = _tableauApiService.SiteUrl.AppendUri(
                $"projects/{projectId}/default-permissions/{resourceType.ToString().ToLower()}s/"
                );

            var requestJson = new JObject();

            requestJson["permissions"] = JToken.Parse(permission.ToRequestString());

            var responseString = await _tableauApiService.SendPutAsync(
                url, requestJson.ToString()
                ).ConfigureAwait(false);

            var responseJson = JToken.Parse(responseString);

            var newPermission = JsonConvert.DeserializeObject <TableauPermission>(
                responseJson.Value <JObject>("permissions").ToString()
                );

            _logger?.Debug($"Default permission added");

            return(newPermission);
        }
        /// <summary>
        /// <see cref="ITableauPermissionService.DeletePermissionAsync"/>
        /// </summary>
        public async Task DeletePermissionAsync(TableauPermission permission)
        {
            _logger?.Debug($"Deleting permission");
            var resourceTypeName = "";
            var resourceId       = "";

            if (permission.Datasource != null)
            {
                resourceTypeName = ResourceType.Datasource.ToString().ToLower();
                resourceId       = permission.Datasource.Id;
            }
            else if (permission.Project != null)
            {
                resourceTypeName = ResourceType.Project.ToString().ToLower();
                resourceId       = permission.Project.Id;
            }
            else if (permission.Workbook != null)
            {
                resourceTypeName = ResourceType.Workbook.ToString().ToLower();
                resourceId       = permission.Workbook.Id;
            }

            foreach (var granteeCapability in permission.GranteeCapabilities)
            {
                var granteeTypeName = "";
                var granteeId       = "";
                if (granteeCapability.Group != null)
                {
                    granteeTypeName = GranteeType.Group.ToString().ToLower();
                    granteeId       = granteeCapability.Group.Id;
                }
                else if (granteeCapability.User != null)
                {
                    granteeTypeName = GranteeType.User.ToString().ToLower();
                    granteeId       = granteeCapability.User.Id;
                }
                else
                {
                    throw new Exception("Unsupported resource/object type");
                }

                foreach (var capability in granteeCapability.Capabilities.Capability)
                {
                    _logger?.Debug(
                        String.Format(
                            "Deleting permission for {0} {1} to {2} {3}: {4} {5}",
                            resourceTypeName,
                            resourceId,
                            granteeTypeName,
                            granteeId,
                            capability.Mode,
                            capability.Name
                            )
                        );

                    var url = _tableauApiService.SiteUrl.AppendUri(
                        $"{resourceTypeName}s/{resourceId}/permissions/{granteeTypeName}s/{granteeId}/" +
                        $"{capability.Name}/{capability.Mode}"
                        );

                    try
                    {
                        var responseString = await _tableauApiService.SendDeleteAsync(url).ConfigureAwait(false);

                        _logger?.Debug($"Response: {responseString}");
                        _logger?.Debug($"Permission deleted");
                    }
                    catch (Exception ex)
                    {
                        _logger?.Error($"Error deleting permission: {ex.ToString()}");
                    }
                }
            }

            _logger?.Debug($"Permission deleted");
        }
        /// <summary>
        /// <see cref="ITableauPermissionService.AddPermissionAsync"/>
        /// </summary>
        public async Task <TableauPermission> AddPermissionAsync(TableauPermission permission)
        {
            _logger?.Debug($"Adding permission");
            var resourceTypeName = "";
            var resourceId       = "";

            if (permission.Datasource != null)
            {
                resourceTypeName = ResourceType.Datasource.ToString().ToLower();
                resourceId       = permission.Datasource.Id;
            }
            else if (permission.Project != null)
            {
                resourceTypeName = ResourceType.Project.ToString().ToLower();
                resourceId       = permission.Project.Id;
            }
            else if (permission.Workbook != null)
            {
                resourceTypeName = ResourceType.Workbook.ToString().ToLower();
                resourceId       = permission.Workbook.Id;
            }
            else
            {
                throw new Exception("Unsupported resource/object type");
            }

            foreach (var granteeCapability in permission.GranteeCapabilities)
            {
                var granteeTypeName = "";
                var granteeId       = "";
                if (granteeCapability.Group != null)
                {
                    granteeTypeName = GranteeType.Group.ToString().ToLower();
                    granteeId       = granteeCapability.Group.Id;
                }
                else if (granteeCapability.User != null)
                {
                    granteeTypeName = GranteeType.User.ToString().ToLower();
                    granteeId       = granteeCapability.User.Id;
                }
                else
                {
                    throw new Exception("Unsupported grantee type");
                }

                foreach (var capability in granteeCapability.Capabilities.Capability)
                {
                    _logger?.Debug(
                        String.Format(
                            "Adding permission for {0} {1} to {2} {3}: {4} {5}",
                            resourceTypeName,
                            resourceId,
                            granteeTypeName,
                            granteeId,
                            capability.Mode,
                            capability.Name
                            )
                        );
                }
            }

            var url = _tableauApiService.SiteUrl.AppendUri($"{resourceTypeName}s/{resourceId}/permissions");

            var requestJson = new JObject();

            requestJson["permissions"] = JToken.Parse(permission.ToRequestString());

            var responseString = await _tableauApiService.SendPutAsync(url, requestJson.ToString()).ConfigureAwait(false);

            var responseJson = JToken.Parse(responseString);

            var newPermission = JsonConvert.DeserializeObject <TableauPermission>(
                responseJson.Value <JObject>("permissions").ToString()
                );

            _logger?.Debug($"Permission added");

            return(newPermission);
        }