using System;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.Core
{
///
/// Provides extension methods for content variations.
///
public static class ContentVariationExtensions
{
///
/// Determines whether the content type is invariant.
///
/// The content type.
///
/// A value indicating whether the content type is invariant.
///
public static bool VariesByNothing(this ISimpleContentType contentType) => contentType.Variations.VariesByNothing();
///
/// Determines whether the content type is invariant.
///
/// The content type.
///
/// A value indicating whether the content type is invariant.
///
public static bool VariesByNothing(this IContentTypeBase contentType) => contentType.Variations.VariesByNothing();
///
/// Determines whether the content type is invariant.
///
/// The content type.
///
/// A value indicating whether the content type is invariant.
///
public static bool VariesByNothing(this IPublishedContentType contentType) => contentType.Variations.VariesByNothing();
///
/// Determines whether the property type is invariant.
///
/// The property type.
///
/// A value indicating whether the property type is invariant.
///
public static bool VariesByNothing(this IPropertyType propertyType) => propertyType.Variations.VariesByNothing();
///
/// Determines whether the property type is invariant.
///
/// The property type.
///
/// A value indicating whether the property type is invariant.
///
public static bool VariesByNothing(this IPublishedPropertyType propertyType) => propertyType.Variations.VariesByNothing();
///
/// Determines whether a variation is invariant.
///
/// The variation.
///
/// A value indicating whether the variation is invariant.
///
public static bool VariesByNothing(this ContentVariation variation) => variation == ContentVariation.Nothing;
///
/// Determines whether the content type varies by culture.
///
/// The content type.
///
/// A value indicating whether the content type varies by culture.
///
public static bool VariesByCulture(this ISimpleContentType contentType) => contentType.Variations.VariesByCulture();
///
/// Determines whether the content type varies by culture.
///
/// The content type.
///
/// A value indicating whether the content type varies by culture.
///
public static bool VariesByCulture(this IContentTypeBase contentType) => contentType.Variations.VariesByCulture();
///
/// Determines whether the content type varies by culture.
///
/// The content type.
///
/// A value indicating whether the content type varies by culture.
///
public static bool VariesByCulture(this IPublishedContentType contentType) => contentType.Variations.VariesByCulture();
///
/// Determines whether the property type varies by culture.
///
/// The property type.
///
/// A value indicating whether the property type varies by culture.
///
public static bool VariesByCulture(this IPropertyType propertyType) => propertyType.Variations.VariesByCulture();
///
/// Determines whether the property type varies by culture.
///
/// The property type.
///
/// A value indicating whether the property type varies by culture.
///
public static bool VariesByCulture(this IPublishedPropertyType propertyType) => propertyType.Variations.VariesByCulture();
///
/// Determines whether a variation varies by culture.
///
/// The variation.
///
/// A value indicating whether the variation varies by culture.
///
public static bool VariesByCulture(this ContentVariation variation) => (variation & ContentVariation.Culture) > 0;
///
/// Determines whether the content type varies by segment.
///
/// The content type.
///
/// A value indicating whether the content type varies by segment.
///
public static bool VariesBySegment(this ISimpleContentType contentType) => contentType.Variations.VariesBySegment();
///
/// Determines whether the content type varies by segment.
///
/// The content type.
///
/// A value indicating whether the content type varies by segment.
///
public static bool VariesBySegment(this IContentTypeBase contentType) => contentType.Variations.VariesBySegment();
///
/// Determines whether the content type varies by segment.
///
/// The content type.
///
/// A value indicating whether the content type varies by segment.
///
public static bool VariesBySegment(this IPublishedContentType contentType) => contentType.Variations.VariesBySegment();
///
/// Determines whether the property type varies by segment.
///
/// The property type.
///
/// A value indicating whether the property type varies by segment.
///
public static bool VariesBySegment(this IPropertyType propertyType) => propertyType.Variations.VariesBySegment();
///
/// Determines whether the property type varies by segment.
///
/// The property type.
///
/// A value indicating whether the property type varies by segment.
///
public static bool VariesBySegment(this IPublishedPropertyType propertyType) => propertyType.Variations.VariesBySegment();
///
/// Determines whether a variation varies by segment.
///
/// The variation.
///
/// A value indicating whether the variation varies by segment.
///
public static bool VariesBySegment(this ContentVariation variation) => (variation & ContentVariation.Segment) > 0;
///
/// Determines whether the content type varies by culture and segment.
///
/// The content type.
///
/// A value indicating whether the content type varies by culture and segment.
///
public static bool VariesByCultureAndSegment(this ISimpleContentType contentType) => contentType.Variations.VariesByCultureAndSegment();
///
/// Determines whether the content type varies by culture and segment.
///
/// The content type.
///
/// A value indicating whether the content type varies by culture and segment.
///
public static bool VariesByCultureAndSegment(this IContentTypeBase contentType) => contentType.Variations.VariesByCultureAndSegment();
///
/// Determines whether the content type varies by culture and segment.
///
/// The content type.
///
/// A value indicating whether the content type varies by culture and segment.
///
public static bool VariesByCultureAndSegment(this IPublishedContentType contentType) => contentType.Variations.VariesByCultureAndSegment();
///
/// Determines whether the property type varies by culture and segment.
///
/// The property type.
///
/// A value indicating whether the property type varies by culture and segment.
///
public static bool VariesByCultureAndSegment(this IPropertyType propertyType) => propertyType.Variations.VariesByCultureAndSegment();
///
/// Determines whether the property type varies by culture and segment.
///
/// The property type.
///
/// A value indicating whether the property type varies by culture and segment.
///
public static bool VariesByCultureAndSegment(this IPublishedPropertyType propertyType) => propertyType.Variations.VariesByCultureAndSegment();
///
/// Determines whether a variation varies by culture and segment.
///
/// The variation.
///
/// A value indicating whether the variation varies by culture and segment.
///
public static bool VariesByCultureAndSegment(this ContentVariation variation) => (variation & ContentVariation.CultureAndSegment) == ContentVariation.CultureAndSegment;
///
/// Sets or removes the content type variation depending on the specified value.
///
/// The content type.
/// The variation to set or remove.
/// If set to true sets the variation; otherwise, removes the variation.
///
/// This method does not support setting the variation to nothing.
///
public static void SetVariesBy(this IContentTypeBase contentType, ContentVariation variation, bool value = true) => contentType.Variations = contentType.Variations.SetFlag(variation, value);
///
/// Sets or removes the property type variation depending on the specified value.
///
/// The property type.
/// The variation to set or remove.
/// If set to true sets the variation; otherwise, removes the variation.
///
/// This method does not support setting the variation to nothing.
///
public static void SetVariesBy(this IPropertyType propertyType, ContentVariation variation, bool value = true) => propertyType.Variations = propertyType.Variations.SetFlag(variation, value);
///
/// Returns the variations with the variation set or removed depending on the specified value.
///
/// The existing variations.
/// The variation to set or remove.
/// If set to true sets the variation; otherwise, removes the variation.
///
/// The variations with the variation set or removed.
///
///
/// This method does not support setting the variation to nothing.
///
public static ContentVariation SetFlag(this ContentVariation variations, ContentVariation variation, bool value = true)
{
return value
? variations | variation // Set flag using bitwise logical OR
: variations & ~variation; // Remove flag using bitwise logical AND with bitwise complement (reversing the bit)
}
///
/// Validates that a combination of culture and segment is valid for the variation.
///
/// The variation.
/// The culture.
/// The segment.
/// A value indicating whether to perform exact validation.
/// A value indicating whether to support wildcards.
/// A value indicating whether to throw a when the combination is invalid.
///
/// true if the combination is valid; otherwise false.
///
/// Occurs when the combination is invalid, and is true.
///
/// When validation is exact, the combination must match the variation exactly. For instance, if the variation is Culture, then
/// a culture is required. When validation is not strict, the combination must be equivalent, or more restrictive: if the variation is
/// Culture, an invariant combination is ok.
/// Basically, exact is for one content type, or one property type, and !exact is for "all property types" of one content type.
/// Both and can be "*" to indicate "all of them".
///
public static bool ValidateVariation(this ContentVariation variation, string culture, string segment, bool exact, bool wildcards, bool throwIfInvalid)
{
culture = culture.NullOrWhiteSpaceAsNull();
segment = segment.NullOrWhiteSpaceAsNull();
// if wildcards are disabled, do not allow "*"
if (!wildcards && (culture == "*" || segment == "*"))
{
if (throwIfInvalid)
throw new NotSupportedException($"Variation wildcards are not supported.");
return false;
}
if (variation.VariesByCulture())
{
// varies by culture
// in exact mode, the culture cannot be null
if (exact && culture == null)
{
if (throwIfInvalid)
throw new NotSupportedException($"Culture may not be null because culture variation is enabled.");
return false;
}
}
else
{
// does not vary by culture
// the culture cannot have a value
// unless wildcards and it's "*"
if (culture != null && !(wildcards && culture == "*"))
{
if (throwIfInvalid)
throw new NotSupportedException($"Culture \"{culture}\" is invalid because culture variation is disabled.");
return false;
}
}
// if it does not vary by segment
// the segment cannot have a value
// segment may always be null, even when the ContentVariation.Segment flag is set for this variation,
// therefore the exact parameter is not used in segment validation.
if (!variation.VariesBySegment() && segment != null && !(wildcards && segment == "*"))
{
if (throwIfInvalid)
throw new NotSupportedException($"Segment \"{segment}\" is invalid because segment variation is disabled.");
return false;
}
return true;
}
}
}