package rui

import (
	"fmt"
	"strings"
)

// Constants related to view's border description
const (
	// NoneLine constant specifies that there is no border
	NoneLine = 0

	// SolidLine constant specifies the border/line as a solid line
	SolidLine = 1

	// DashedLine constant specifies the border/line as a dashed line
	DashedLine = 2

	// DottedLine constant specifies the border/line as a dotted line
	DottedLine = 3

	// DoubleLine constant specifies the border/line as a double solid line
	DoubleLine = 4

	// DoubleLine constant specifies the border/line as a double solid line
	WavyLine = 5

	// LeftStyle is the constant for "left-style" property tag.
	//
	// Used by BorderProperty.
	// Left border line style.
	//
	// Supported types: int, string.
	//
	// Values:
	//  - 0 (NoneLine) or "none" - The border will not be drawn.
	//  - 1 (SolidLine) or "solid" - Solid line as a border.
	//  - 2 (DashedLine) or "dashed" - Dashed line as a border.
	//  - 3 (DottedLine) or "dotted" - Dotted line as a border.
	//  - 4 (DoubleLine) or "double" - Double line as a border.
	LeftStyle PropertyName = "left-style"

	// RightStyle is the constant for "right-style" property tag.
	//
	// Used by BorderProperty.
	// Right border line style.
	//
	// Supported types: int, string.
	//
	// Values:
	//  - 0 (NoneLine) or "none" - The border will not be drawn.
	//  - 1 (SolidLine) or "solid" - Solid line as a border.
	//  - 2 (DashedLine) or "dashed" - Dashed line as a border.
	//  - 3 (DottedLine) or "dotted" - Dotted line as a border.
	//  - 4 (DoubleLine) or "double" - Double line as a border.
	RightStyle PropertyName = "right-style"

	// TopStyle is the constant for "top-style" property tag.
	//
	// Used by BorderProperty.
	// Top border line style.
	//
	// Supported types: int, string.
	//
	// Values:
	//  - 0 (NoneLine) or "none" - The border will not be drawn.
	//  - 1 (SolidLine) or "solid" - Solid line as a border.
	//  - 2 (DashedLine) or "dashed" - Dashed line as a border.
	//  - 3 (DottedLine) or "dotted" - Dotted line as a border.
	//  - 4 (DoubleLine) or "double" - Double line as a border.
	TopStyle PropertyName = "top-style"

	// BottomStyle is the constant for "bottom-style" property tag.
	//
	// Used by BorderProperty.
	// Bottom border line style.
	//
	// Supported types: int, string.
	//
	// Values:
	//  - 0 (NoneLine) or "none" - The border will not be drawn.
	//  - 1 (SolidLine) or "solid" - Solid line as a border.
	//  - 2 (DashedLine) or "dashed" - Dashed line as a border.
	//  - 3 (DottedLine) or "dotted" - Dotted line as a border.
	//  - 4 (DoubleLine) or "double" - Double line as a border.
	BottomStyle PropertyName = "bottom-style"

	// LeftWidth is the constant for "left-width" property tag.
	//
	// Used by BorderProperty.
	// Left border line width.
	//
	// Supported types: SizeUnit, SizeFunc, string, float, int.
	//
	// Internal type is SizeUnit, other types converted to it during assignment.
	// See [SizeUnit] description for more details.
	LeftWidth PropertyName = "left-width"

	// RightWidth is the constant for "right-width" property tag.
	//
	// Used by BorderProperty.
	// Right border line width.
	//
	// Supported types: SizeUnit, SizeFunc, string, float, int.
	//
	// Internal type is SizeUnit, other types converted to it during assignment.
	// See [SizeUnit] description for more details.
	RightWidth PropertyName = "right-width"

	// TopWidth is the constant for "top-width" property tag.
	//
	// Used by BorderProperty.
	// Top border line width.
	//
	// Supported types: SizeUnit, SizeFunc, string, float, int.
	//
	// Internal type is SizeUnit, other types converted to it during assignment.
	// See [SizeUnit] description for more details.
	TopWidth PropertyName = "top-width"

	// BottomWidth is the constant for "bottom-width" property tag.
	//
	// Used by BorderProperty.
	// Bottom border line width.
	//
	// Supported types: SizeUnit, SizeFunc, string, float, int.
	//
	// Internal type is SizeUnit, other types converted to it during assignment.
	// See [SizeUnit] description for more details.
	BottomWidth PropertyName = "bottom-width"

	// LeftColor is the constant for "left-color" property tag.
	//
	// Used by BorderProperty.
	// Left border line color.
	//
	// Supported types: Color, string.
	//
	// Internal type is Color, other types converted to it during assignment.
	// See [Color] description for more details.
	LeftColor PropertyName = "left-color"

	// RightColor is the constant for "right-color" property tag.
	//
	// Used by BorderProperty.
	// Right border line color.
	//
	// Supported types: Color, string.
	//
	// Internal type is Color, other types converted to it during assignment.
	// See [Color] description for more details.
	RightColor PropertyName = "right-color"

	// TopColor is the constant for "top-color" property tag.
	//
	// Used by BorderProperty.
	// Top border line color.
	//
	// Supported types: Color, string.
	//
	// Internal type is Color, other types converted to it during assignment.
	// See [Color] description for more details.
	TopColor PropertyName = "top-color"

	// BottomColor is the constant for "bottom-color" property tag.
	//
	// Used by BorderProperty.
	// Bottom border line color.
	//
	// Supported types: Color, string.
	//
	// Internal type is Color, other types converted to it during assignment.
	// See [Color] description for more details.
	BottomColor PropertyName = "bottom-color"
)

// BorderProperty is the interface of a view border data
type BorderProperty interface {
	Properties
	fmt.Stringer
	stringWriter

	// ViewBorders returns top, right, bottom and left borders information all together
	ViewBorders(session Session) ViewBorders

	deleteTag(tag PropertyName) bool
	cssStyle(builder cssBuilder, session Session)
	cssWidth(builder cssBuilder, session Session)
	cssColor(builder cssBuilder, session Session)
	cssStyleValue(session Session) string
	cssWidthValue(session Session) string
	cssColorValue(session Session) string
}

type borderProperty struct {
	dataProperty
}

func newBorderProperty(value any) BorderProperty {
	border := new(borderProperty)
	border.init()

	if value != nil {
		switch value := value.(type) {
		case BorderProperty:
			return value

		case DataNode:
			if value.Type() == ObjectNode {
				_ = border.setBorderObject(value.Object())
			} else {
				return nil
			}

		case DataObject:
			_ = border.setBorderObject(value)

		case ViewBorder:
			border.properties[Style] = value.Style
			border.properties[Width] = value.Width
			border.properties[ColorTag] = value.Color

		case ViewBorders:
			if value.Left.Style == value.Right.Style &&
				value.Left.Style == value.Top.Style &&
				value.Left.Style == value.Bottom.Style {
				border.properties[Style] = value.Left.Style
			} else {
				border.properties[LeftStyle] = value.Left.Style
				border.properties[RightStyle] = value.Right.Style
				border.properties[TopStyle] = value.Top.Style
				border.properties[BottomStyle] = value.Bottom.Style
			}
			if value.Left.Width.Equal(value.Right.Width) &&
				value.Left.Width.Equal(value.Top.Width) &&
				value.Left.Width.Equal(value.Bottom.Width) {
				border.properties[Width] = value.Left.Width
			} else {
				border.properties[LeftWidth] = value.Left.Width
				border.properties[RightWidth] = value.Right.Width
				border.properties[TopWidth] = value.Top.Width
				border.properties[BottomWidth] = value.Bottom.Width
			}
			if value.Left.Color == value.Right.Color &&
				value.Left.Color == value.Top.Color &&
				value.Left.Color == value.Bottom.Color {
				border.properties[ColorTag] = value.Left.Color
			} else {
				border.properties[LeftColor] = value.Left.Color
				border.properties[RightColor] = value.Right.Color
				border.properties[TopColor] = value.Top.Color
				border.properties[BottomColor] = value.Bottom.Color
			}

		default:
			invalidPropertyValue(Border, value)
			return nil
		}
	}
	return border
}

// NewBorder creates the new BorderProperty.
// The following properties can be used:
//
// "style" (Style). Determines the line style (int). Valid values: 0 (NoneLine), 1 (SolidLine), 2 (DashedLine), 3 (DottedLine), or 4 (DoubleLine);
//
// "color" (ColorTag). Determines the line color (Color);
//
// "width" (Width). Determines the line thickness (SizeUnit).
func NewBorder(params Params) BorderProperty {
	border := new(borderProperty)
	border.init()

	if params != nil {
		for _, tag := range []PropertyName{Style, Width, ColorTag, Left, Right, Top, Bottom,
			LeftStyle, RightStyle, TopStyle, BottomStyle,
			LeftWidth, RightWidth, TopWidth, BottomWidth,
			LeftColor, RightColor, TopColor, BottomColor} {
			if value, ok := params[tag]; ok && value != nil {
				border.Set(tag, value)
			}
		}
	}
	return border
}

func (border *borderProperty) init() {
	border.dataProperty.init()
	border.normalize = normalizeBorderTag
	border.get = borderGet
	border.set = borderSet
	border.remove = borderRemove
	border.supportedProperties = []PropertyName{
		Left,
		Right,
		Top,
		Bottom,
		Style,
		LeftStyle,
		RightStyle,
		TopStyle,
		BottomStyle,
		Width,
		LeftWidth,
		RightWidth,
		TopWidth,
		BottomWidth,
		ColorTag,
		LeftColor,
		RightColor,
		TopColor,
		BottomColor,
	}
}

func normalizeBorderTag(tag PropertyName) PropertyName {
	tag = defaultNormalize(tag)
	switch tag {
	case BorderLeft, CellBorderLeft:
		return Left

	case BorderRight, CellBorderRight:
		return Right

	case BorderTop, CellBorderTop:
		return Top

	case BorderBottom, CellBorderBottom:
		return Bottom

	case BorderStyle, CellBorderStyle:
		return Style

	case BorderLeftStyle, CellBorderLeftStyle, "style-left":
		return LeftStyle

	case BorderRightStyle, CellBorderRightStyle, "style-right":
		return RightStyle

	case BorderTopStyle, CellBorderTopStyle, "style-top":
		return TopStyle

	case BorderBottomStyle, CellBorderBottomStyle, "style-bottom":
		return BottomStyle

	case BorderWidth, CellBorderWidth:
		return Width

	case BorderLeftWidth, CellBorderLeftWidth, "width-left":
		return LeftWidth

	case BorderRightWidth, CellBorderRightWidth, "width-right":
		return RightWidth

	case BorderTopWidth, CellBorderTopWidth, "width-top":
		return TopWidth

	case BorderBottomWidth, CellBorderBottomWidth, "width-bottom":
		return BottomWidth

	case BorderColor, CellBorderColor:
		return ColorTag

	case BorderLeftColor, CellBorderLeftColor, "color-left":
		return LeftColor

	case BorderRightColor, CellBorderRightColor, "color-right":
		return RightColor

	case BorderTopColor, CellBorderTopColor, "color-top":
		return TopColor

	case BorderBottomColor, CellBorderBottomColor, "color-bottom":
		return BottomColor
	}

	return tag
}

func (border *borderProperty) writeString(buffer *strings.Builder, indent string) {
	buffer.WriteString("_{ ")
	comma := false

	write := func(tag PropertyName, value any) {
		if comma {
			buffer.WriteString(", ")
		}
		buffer.WriteString(string(tag))
		buffer.WriteString(" = ")
		writePropertyValue(buffer, BorderStyle, value, indent)
		comma = true
	}

	for _, tag := range []PropertyName{Style, Width, ColorTag} {
		if value, ok := border.properties[tag]; ok {
			write(tag, value)
		}
	}

	for _, side := range []PropertyName{Top, Right, Bottom, Left} {
		style, okStyle := border.properties[side+"-"+Style]
		width, okWidth := border.properties[side+"-"+Width]
		color, okColor := border.properties[side+"-"+ColorTag]
		if okStyle || okWidth || okColor {
			if comma {
				buffer.WriteString(", ")
				comma = false
			}

			buffer.WriteString(string(side))
			buffer.WriteString(" = _{ ")
			if okStyle {
				write(Style, style)
			}
			if okWidth {
				write(Width, width)
			}
			if okColor {
				write(ColorTag, color)
			}
			buffer.WriteString(" }")
			comma = true
		}
	}

	buffer.WriteString(" }")
}

func (border *borderProperty) String() string {
	return runStringWriter(border)
}

func (border *borderProperty) setBorderObject(obj DataObject) bool {
	result := true
	for i := 0; i < obj.PropertyCount(); i++ {
		if node := obj.Property(i); node != nil {
			tag := PropertyName(node.Tag())
			switch node.Type() {
			case TextNode:
				if borderSet(border, tag, node.Text()) == nil {
					result = false
				}

			case ObjectNode:
				if borderSet(border, tag, node.Object()) == nil {
					result = false
				}

			default:
				result = false
			}
		} else {
			result = false
		}
	}
	return result
}

func borderRemove(properties Properties, tag PropertyName) []PropertyName {
	result := []PropertyName{}
	removeTag := func(t PropertyName) {
		if properties.getRaw(t) != nil {
			properties.setRaw(t, nil)
			result = append(result, t)
		}
	}

	switch tag {
	case Style:
		for _, t := range []PropertyName{tag, TopStyle, RightStyle, BottomStyle, LeftStyle} {
			removeTag(t)
		}

	case Width:
		for _, t := range []PropertyName{tag, TopWidth, RightWidth, BottomWidth, LeftWidth} {
			removeTag(t)
		}

	case ColorTag:
		for _, t := range []PropertyName{tag, TopColor, RightColor, BottomColor, LeftColor} {
			removeTag(t)
		}

	case Left, Right, Top, Bottom:
		removeTag(tag + "-style")
		removeTag(tag + "-width")
		removeTag(tag + "-color")

	case LeftStyle, RightStyle, TopStyle, BottomStyle:
		removeTag(tag)
		if style := properties.getRaw(Style); style != nil {
			for _, t := range []PropertyName{TopStyle, RightStyle, BottomStyle, LeftStyle} {
				if t != tag {
					if properties.getRaw(t) == nil {
						properties.setRaw(t, style)
						result = append(result, t)
					}
				}
			}
		}

	case LeftWidth, RightWidth, TopWidth, BottomWidth:
		removeTag(tag)
		if width := properties.getRaw(Width); width != nil {
			for _, t := range []PropertyName{TopWidth, RightWidth, BottomWidth, LeftWidth} {
				if t != tag {
					if properties.getRaw(t) == nil {
						properties.setRaw(t, width)
						result = append(result, t)
					}
				}
			}
		}

	case LeftColor, RightColor, TopColor, BottomColor:
		removeTag(tag)
		if color := properties.getRaw(ColorTag); color != nil {
			for _, t := range []PropertyName{TopColor, RightColor, BottomColor, LeftColor} {
				if t != tag {
					if properties.getRaw(t) == nil {
						properties.setRaw(t, color)
						result = append(result, t)
					}
				}
			}
		}

	default:
		ErrorLogF(`"%s" property is not compatible with the BorderProperty`, tag)
	}

	return result
}

func borderSet(properties Properties, tag PropertyName, value any) []PropertyName {

	setSingleBorderObject := func(prefix PropertyName, obj DataObject) []PropertyName {
		result := []PropertyName{}
		if text, ok := obj.PropertyValue(string(Style)); ok {
			props := setEnumProperty(properties, prefix+"-style", text, enumProperties[BorderStyle].values)
			if props == nil {
				return nil
			}
			result = append(result, props...)
		}
		if text, ok := obj.PropertyValue(string(ColorTag)); ok {
			props := setColorProperty(properties, prefix+"-color", text)
			if props == nil && len(result) == 0 {
				return nil
			}
			result = append(result, props...)
		}
		if text, ok := obj.PropertyValue("width"); ok {
			props := setSizeProperty(properties, prefix+"-width", text)
			if props == nil && len(result) == 0 {
				return nil
			}
			result = append(result, props...)
		}
		if len(result) > 0 {
			result = append(result, prefix)
		}
		return result
	}

	switch tag {
	case Style:
		if result := setEnumProperty(properties, Style, value, enumProperties[BorderStyle].values); result != nil {
			for _, side := range []PropertyName{TopStyle, RightStyle, BottomStyle, LeftStyle} {
				if value := properties.getRaw(side); value != nil {
					properties.setRaw(side, nil)
					result = append(result, side)
				}
			}
			return result
		}

	case Width:
		if result := setSizeProperty(properties, Width, value); result != nil {
			for _, side := range []PropertyName{TopWidth, RightWidth, BottomWidth, LeftWidth} {
				if value := properties.getRaw(side); value != nil {
					properties.setRaw(side, nil)
					result = append(result, side)
				}
			}
			return result
		}

	case ColorTag:
		if result := setColorProperty(properties, ColorTag, value); result != nil {
			for _, side := range []PropertyName{TopColor, RightColor, BottomColor, LeftColor} {
				if value := properties.getRaw(side); value != nil {
					properties.setRaw(side, nil)
					result = append(result, side)
				}
			}
			return result
		}

	case LeftStyle, RightStyle, TopStyle, BottomStyle:
		return setEnumProperty(properties, tag, value, enumProperties[BorderStyle].values)

	case LeftWidth, RightWidth, TopWidth, BottomWidth:
		return setSizeProperty(properties, tag, value)

	case LeftColor, RightColor, TopColor, BottomColor:
		return setColorProperty(properties, tag, value)

	case Left, Right, Top, Bottom:
		switch value := value.(type) {
		case string:
			if obj := ParseDataText(value); obj != nil {
				return setSingleBorderObject(tag, obj)
			}

		case DataObject:
			return setSingleBorderObject(tag, value)

		case BorderProperty:
			result := []PropertyName{}
			styleTag := tag + "-" + Style
			if style := value.Get(styleTag); value != nil {
				properties.setRaw(styleTag, style)
				result = append(result, styleTag)
			}
			colorTag := tag + "-" + ColorTag
			if color := value.Get(colorTag); value != nil {
				properties.setRaw(colorTag, color)
				result = append(result, colorTag)
			}
			widthTag := tag + "-" + Width
			if width := value.Get(widthTag); value != nil {
				properties.setRaw(widthTag, width)
				result = append(result, widthTag)
			}
			return result

		case ViewBorder:
			properties.setRaw(tag+"-"+Style, value.Style)
			properties.setRaw(tag+"-"+Width, value.Width)
			properties.setRaw(tag+"-"+ColorTag, value.Color)
			return []PropertyName{tag + "-" + Style, tag + "-" + Width, tag + "-" + ColorTag}
		}
		fallthrough

	default:
		ErrorLogF(`"%s" property is not compatible with the BorderProperty`, tag)
	}

	return nil
}

func borderGet(properties Properties, tag PropertyName) any {
	if result := properties.getRaw(tag); result != nil {
		return result
	}

	switch tag {
	case Left, Right, Top, Bottom:
		result := newBorderProperty(nil)
		if style := properties.getRaw(tag + "-" + Style); style != nil {
			result.Set(Style, style)
		} else if style := properties.getRaw(Style); style != nil {
			result.Set(Style, style)
		}
		if width := properties.getRaw(tag + "-" + Width); width != nil {
			result.Set(Width, width)
		} else if width := properties.getRaw(Width); width != nil {
			result.Set(Width, width)
		}
		if color := properties.getRaw(tag + "-" + ColorTag); color != nil {
			result.Set(ColorTag, color)
		} else if color := properties.getRaw(ColorTag); color != nil {
			result.Set(ColorTag, color)
		}
		return result

	case LeftStyle, RightStyle, TopStyle, BottomStyle:
		if style := properties.getRaw(tag); style != nil {
			return style
		}
		return properties.getRaw(Style)

	case LeftWidth, RightWidth, TopWidth, BottomWidth:
		if width := properties.getRaw(tag); width != nil {
			return width
		}
		return properties.getRaw(Width)

	case LeftColor, RightColor, TopColor, BottomColor:
		if color := properties.getRaw(tag); color != nil {
			return color
		}
		return properties.getRaw(ColorTag)
	}

	return nil
}

func (border *borderProperty) deleteTag(tag PropertyName) bool {

	result := false
	removeTags := func(tags []PropertyName) {
		for _, tag := range tags {
			if border.getRaw(tag) != nil {
				border.setRaw(tag, nil)
				result = true
			}
		}
	}

	switch tag {
	case Style:
		removeTags([]PropertyName{Style, LeftStyle, RightStyle, TopStyle, BottomStyle})

	case Width:
		removeTags([]PropertyName{Width, LeftWidth, RightWidth, TopWidth, BottomWidth})

	case ColorTag:
		removeTags([]PropertyName{ColorTag, LeftColor, RightColor, TopColor, BottomColor})

	case Left, Right, Top, Bottom:
		if border.Get(Style) != nil {
			border.properties[tag+"-"+Style] = 0
			result = true
			removeTags([]PropertyName{tag + "-" + ColorTag, tag + "-" + Width})
		} else {
			removeTags([]PropertyName{tag + "-" + Style, tag + "-" + ColorTag, tag + "-" + Width})
		}

	case LeftStyle, RightStyle, TopStyle, BottomStyle:
		if border.getRaw(tag) != nil {
			if border.Get(Style) != nil {
				border.properties[tag] = 0
				result = true
			} else {
				removeTags([]PropertyName{tag})
			}
		}

	case LeftWidth, RightWidth, TopWidth, BottomWidth:
		if border.getRaw(tag) != nil {
			if border.Get(Width) != nil {
				border.properties[tag] = AutoSize()
				result = true
			} else {
				removeTags([]PropertyName{tag})
			}
		}

	case LeftColor, RightColor, TopColor, BottomColor:
		if border.getRaw(tag) != nil {
			if border.Get(ColorTag) != nil {
				border.properties[tag] = 0
				result = true
			} else {
				removeTags([]PropertyName{tag})
			}
		}
	}

	return result
}

func (border *borderProperty) ViewBorders(session Session) ViewBorders {

	defStyle, _ := valueToEnum(border.getRaw(Style), BorderStyle, session, NoneLine)
	defWidth, _ := sizeProperty(border, Width, session)
	defColor, _ := colorProperty(border, ColorTag, session)

	getBorder := func(prefix PropertyName) ViewBorder {
		var result ViewBorder
		var ok bool
		if result.Style, ok = valueToEnum(border.getRaw(prefix+Style), BorderStyle, session, NoneLine); !ok {
			result.Style = defStyle
		}
		if result.Width, ok = sizeProperty(border, prefix+Width, session); !ok {
			result.Width = defWidth
		}
		if result.Color, ok = colorProperty(border, prefix+ColorTag, session); !ok {
			result.Color = defColor
		}
		return result
	}

	return ViewBorders{
		Top:    getBorder("top-"),
		Left:   getBorder("left-"),
		Right:  getBorder("right-"),
		Bottom: getBorder("bottom-"),
	}
}

func (border *borderProperty) cssStyle(builder cssBuilder, session Session) {
	borders := border.ViewBorders(session)
	values := enumProperties[BorderStyle].cssValues
	if borders.Top.Style == borders.Right.Style &&
		borders.Top.Style == borders.Left.Style &&
		borders.Top.Style == borders.Bottom.Style {
		builder.add(string(BorderStyle), values[borders.Top.Style])
	} else {
		builder.addValues(string(BorderStyle), " ", values[borders.Top.Style],
			values[borders.Right.Style], values[borders.Bottom.Style], values[borders.Left.Style])
	}
}

func (border *borderProperty) cssWidth(builder cssBuilder, session Session) {
	borders := border.ViewBorders(session)
	if borders.Top.Width == borders.Right.Width &&
		borders.Top.Width == borders.Left.Width &&
		borders.Top.Width == borders.Bottom.Width {
		if borders.Top.Width.Type != Auto {
			builder.add("border-width", borders.Top.Width.cssString("0", session))
		}
	} else {
		builder.addValues("border-width", " ",
			borders.Top.Width.cssString("0", session),
			borders.Right.Width.cssString("0", session),
			borders.Bottom.Width.cssString("0", session),
			borders.Left.Width.cssString("0", session))
	}
}

func (border *borderProperty) cssColor(builder cssBuilder, session Session) {
	borders := border.ViewBorders(session)
	if borders.Top.Color == borders.Right.Color &&
		borders.Top.Color == borders.Left.Color &&
		borders.Top.Color == borders.Bottom.Color {
		if borders.Top.Color != 0 {
			builder.add("border-color", borders.Top.Color.cssString())
		}
	} else {
		builder.addValues("border-color", " ", borders.Top.Color.cssString(),
			borders.Right.Color.cssString(), borders.Bottom.Color.cssString(), borders.Left.Color.cssString())
	}
}

func (border *borderProperty) cssStyleValue(session Session) string {
	var builder cssValueBuilder
	border.cssStyle(&builder, session)
	return builder.finish()
}

func (border *borderProperty) cssWidthValue(session Session) string {
	var builder cssValueBuilder
	border.cssWidth(&builder, session)
	return builder.finish()
}

func (border *borderProperty) cssColorValue(session Session) string {
	var builder cssValueBuilder
	border.cssColor(&builder, session)
	return builder.finish()
}

// ViewBorder describes parameters of a view border
type ViewBorder struct {
	// Style of the border line
	Style int

	// Color of the border line
	Color Color

	// Width of the border line
	Width SizeUnit
}

// ViewBorders describes the top, right, bottom, and left border of a view
type ViewBorders struct {
	Top, Right, Bottom, Left ViewBorder
}

// AllTheSame returns true if all borders are the same
func (border *ViewBorders) AllTheSame() bool {
	return border.Top.Style == border.Right.Style &&
		border.Top.Style == border.Left.Style &&
		border.Top.Style == border.Bottom.Style &&
		border.Top.Color == border.Right.Color &&
		border.Top.Color == border.Left.Color &&
		border.Top.Color == border.Bottom.Color &&
		border.Top.Width.Equal(border.Right.Width) &&
		border.Top.Width.Equal(border.Left.Width) &&
		border.Top.Width.Equal(border.Bottom.Width)
}

func getBorderProperty(properties Properties, tag PropertyName) BorderProperty {
	if value := properties.getRaw(tag); value != nil {
		if border, ok := value.(BorderProperty); ok {
			return border
		}
	}
	return nil
}

func setBorderPropertyElement(properties Properties, mainTag, tag PropertyName, value any) []PropertyName {
	border := getBorderProperty(properties, mainTag)
	if border == nil {
		border = NewBorder(nil)
		if border.Set(tag, value) {
			properties.setRaw(mainTag, border)
			return []PropertyName{mainTag, tag}
		}
	} else if border.Set(tag, value) {
		return []PropertyName{mainTag, tag}
	}
	return nil
}