// Copyright (c) 2011 - 2019 Ed Charbeneau
// License: MIT
// See https://github.com/EdCharbeneau
namespace Connected.Utilities
{
	public struct CssBuilder
	{
		private string stringBuffer;
		/// 
		/// Creates a CssBuilder used to define conditional CSS classes used in a component.
		/// Call Build() to return the completed CSS Classes as a string. 
		/// 
		/// 
		public static CssBuilder Default(string value) => new(value);
		/// 
		/// Creates an Empty CssBuilder used to define conditional CSS classes used in a component.
		/// Call Build() to return the completed CSS Classes as a string. 
		/// 
		public static CssBuilder Empty() => new();
		/// 
		/// Creates a CssBuilder used to define conditional CSS classes used in a component.
		/// Call Build() to return the completed CSS Classes as a string. 
		/// 
		/// 
		public CssBuilder(string value) => stringBuffer = value;
		/// 
		/// Adds a raw string to the builder that will be concatenated with the next class or value added to the builder.
		/// 
		/// 
		/// CssBuilder
		public CssBuilder AddValue(string value)
		{
			stringBuffer += value;
			return this;
		}
		/// 
		/// Adds a CSS Class to the builder with space separator.
		/// 
		/// CSS Class to add
		/// CssBuilder
		public CssBuilder AddClass(string? value)
		{
			if (value is null)
				return this;
			return AddValue($" {value}");
		}
		/// 
		/// Adds a conditional CSS Class to the builder with space separator.
		/// 
		/// CSS Class to conditionally add.
		/// Condition in which the CSS Class is added.
		/// CssBuilder
		public CssBuilder AddClass(string value, bool when = true) => when ? this.AddClass(value) : this;
		/// 
		/// Adds a conditional CSS Class to the builder with space separator.
		/// 
		/// CSS Class to conditionally add.
		/// Nullable condition in which the CSS Class is added.
		/// CssBuilder
		public CssBuilder AddClass(string value, bool? when = true) => when == true ? this.AddClass(value) : this;
		/// 
		/// Adds a conditional CSS Class to the builder with space separator.
		/// 
		/// CSS Class to conditionally add.
		/// Condition in which the CSS Class is added.
		/// CssBuilder
		public CssBuilder AddClass(string value, Func when = null) => this.AddClass(value, when != null && when());
		/// 
		/// Adds a conditional CSS Class to the builder with space separator.
		/// 
		/// Function that returns a CSS Class to conditionally add.
		/// Condition in which the CSS Class is added.
		/// CssBuilder
		public CssBuilder AddClass(Func value, bool when = true) => when ? this.AddClass(value()) : this;
		/// 
		/// Adds a conditional CSS Class to the builder with space separator.
		/// 
		/// Function that returns a CSS Class to conditionally add.
		/// Condition in which the CSS Class is added.
		/// CssBuilder
		public CssBuilder AddClass(Func value, Func when = null) => this.AddClass(value, when != null && when());
		/// 
		/// Adds a conditional nested CssBuilder to the builder with space separator.
		/// 
		/// CSS Class to conditionally add.
		/// Condition in which the CSS Class is added.
		/// CssBuilder
		public CssBuilder AddClass(CssBuilder builder, bool when = true) => when ? this.AddClass(builder.Build()) : this;
		/// 
		/// Adds a conditional CSS Class to the builder with space separator.
		/// 
		/// CSS Class to conditionally add.
		/// Condition in which the CSS Class is added.
		/// CssBuilder
		public CssBuilder AddClass(CssBuilder builder, Func when = null) => this.AddClass(builder, when != null && when());
		/// 
		/// Adds a conditional CSS Class when it exists in a dictionary to the builder with space separator.
		/// Null safe operation.
		/// 
		/// Additional Attribute splat parameters
		/// CssBuilder
		public CssBuilder AddClassFromAttributes(IReadOnlyDictionary additionalAttributes) =>
			 additionalAttributes == null ? this :
			 additionalAttributes.TryGetValue("class", out var c) ? AddClass(c.ToString()) : this;
		/// 
		/// Finalize the completed CSS Classes as a string.
		/// 
		/// string
		public string Build()
		{
			// String buffer finalization code
			return stringBuffer != null ? stringBuffer.Trim() : string.Empty;
		}
		// ToString should only and always call Build to finalize the rendered string.
		public override string ToString() => Build();
	}
}