package cview

import (
	

	
)

// Box is the base Primitive for all widgets. It has a background color and
// optional surrounding elements such as a border and a title. It does not have
// inner text. Widgets embed Box and draw their text over it.
type Box struct {
	// The position of the rect.
	x, y, width, height int

	// Padding.
	paddingTop, paddingBottom, paddingLeft, paddingRight int

	// The inner rect reserved for the box's content.
	innerX, innerY, innerWidth, innerHeight int

	// Whether or not the box is visible.
	visible bool

	// The border color when the box has focus.
	borderColorFocused tcell.Color

	// The box's background color.
	backgroundColor tcell.Color

	// Whether or not the box's background is transparent.
	backgroundTransparent bool

	// Whether or not a border is drawn, reducing the box's space for content by
	// two in width and height.
	border bool

	// The color of the border.
	borderColor tcell.Color

	// The style attributes of the border.
	borderAttributes tcell.AttrMask

	// The title. Only visible if there is a border, too.
	title []byte

	// The color of the title.
	titleColor tcell.Color

	// The alignment of the title.
	titleAlign int

	// Provides a way to find out if this box has focus. We always go through
	// this interface because it may be overridden by implementing classes.
	focus Focusable

	// Whether or not this box has focus.
	hasFocus bool

	// Whether or not this box shows its focus.
	showFocus bool

	// An optional capture function which receives a key event and returns the
	// event to be forwarded to the primitive's default input handler (nil if
	// nothing should be forwarded).
	inputCapture func(event *tcell.EventKey) *tcell.EventKey

	// An optional function which is called before the box is drawn.
	draw func(screen tcell.Screen, x, y, width, height int) (int, int, int, int)

	// An optional capture function which receives a mouse event and returns the
	// event to be forwarded to the primitive's default mouse event handler (at
	// least one nil if nothing should be forwarded).
	mouseCapture func(action MouseAction, event *tcell.EventMouse) (MouseAction, *tcell.EventMouse)

	l sync.RWMutex
}

// NewBox returns a Box without a border.
func () *Box {
	 := &Box{
		width:              15,
		height:             10,
		visible:            true,
		backgroundColor:    Styles.PrimitiveBackgroundColor,
		borderColor:        Styles.BorderColor,
		titleColor:         Styles.TitleColor,
		borderColorFocused: ColorUnset,
		titleAlign:         AlignCenter,
		showFocus:          true,
	}
	.focus = 
	.updateInnerRect()
	return 
}

func ( *Box) () {
	, , ,  := .x, .y, .width, .height

	// Subtract border space
	if .border {
		++
		++
		 -= 2
		 -= 2
	}

	// Subtract padding
	, , ,  =
		+.paddingLeft,
		+.paddingTop,
		-.paddingLeft-.paddingRight,
		-.paddingTop-.paddingBottom

	if  < 0 {
		 = 0
	}
	if  < 0 {
		 = 0
	}

	.innerX, .innerY, .innerWidth, .innerHeight = , , , 
}

// GetPadding returns the size of the padding around the box content.
func ( *Box) () (, , ,  int) {
	.l.RLock()
	defer .l.RUnlock()

	return .paddingTop, .paddingBottom, .paddingLeft, .paddingRight
}

// SetPadding sets the size of the padding around the box content.
func ( *Box) (, , ,  int) {
	.l.Lock()
	defer .l.Unlock()

	.paddingTop, .paddingBottom, .paddingLeft, .paddingRight = , , , 

	.updateInnerRect()
}

// GetRect returns the current position of the rectangle, x, y, width, and
// height.
func ( *Box) () (int, int, int, int) {
	.l.RLock()
	defer .l.RUnlock()

	return .x, .y, .width, .height
}

// GetInnerRect returns the position of the inner rectangle (x, y, width,
// height), without the border and without any padding. Width and height values
// will clamp to 0 and thus never be negative.
func ( *Box) () (int, int, int, int) {
	.l.RLock()
	defer .l.RUnlock()

	return .innerX, .innerY, .innerWidth, .innerHeight
}

// SetRect sets a new position of the primitive. Note that this has no effect
// if this primitive is part of a layout (e.g. Flex, Grid) or if it was added
// like this:
//
//   application.SetRoot(b, true)
func ( *Box) (, , ,  int) {
	.l.Lock()
	defer .l.Unlock()

	.x, .y, .width, .height = , , , 

	.updateInnerRect()
}

// SetVisible sets the flag indicating whether or not the box is visible.
func ( *Box) ( bool) {
	.l.Lock()
	defer .l.Unlock()

	.visible = 
}

// GetVisible returns a value indicating whether or not the box is visible.
func ( *Box) () bool {
	.l.RLock()
	defer .l.RUnlock()

	return .visible
}

// SetDrawFunc sets a callback function which is invoked after the box primitive
// has been drawn. This allows you to add a more individual style to the box
// (and all primitives which extend it).
//
// The function is provided with the box's dimensions (set via SetRect()). It
// must return the box's inner dimensions (x, y, width, height) which will be
// returned by GetInnerRect(), used by descendent primitives to draw their own
// content.
func ( *Box) ( func( tcell.Screen, , , ,  int) (int, int, int, int)) {
	.l.Lock()
	defer .l.Unlock()

	.draw = 
}

// GetDrawFunc returns the callback function which was installed with
// SetDrawFunc() or nil if no such function has been installed.
func ( *Box) () func( tcell.Screen, , , ,  int) (int, int, int, int) {
	.l.RLock()
	defer .l.RUnlock()

	return .draw
}

// WrapInputHandler wraps an input handler (see InputHandler()) with the
// functionality to capture input (see SetInputCapture()) before passing it
// on to the provided (default) input handler.
//
// This is only meant to be used by subclassing primitives.
func ( *Box) ( func(*tcell.EventKey, func( Primitive))) func(*tcell.EventKey, func( Primitive)) {
	return func( *tcell.EventKey,  func( Primitive)) {
		if .inputCapture != nil {
			 = .inputCapture()
		}
		if  != nil &&  != nil {
			(, )
		}
	}
}

// InputHandler returns nil.
func ( *Box) () func( *tcell.EventKey,  func( Primitive)) {
	.l.RLock()
	defer .l.RUnlock()

	return .WrapInputHandler(nil)
}

// SetInputCapture installs a function which captures key events before they are
// forwarded to the primitive's default key event handler. This function can
// then choose to forward that key event (or a different one) to the default
// handler by returning it. If nil is returned, the default handler will not
// be called.
//
// Providing a nil handler will remove a previously existing handler.
//
// Note that this function will not have an effect on primitives composed of
// other primitives, such as Form, Flex, or Grid. Key events are only captured
// by the primitives that have focus (e.g. InputField) and only one primitive
// can have focus at a time. Composing primitives such as Form pass the focus on
// to their contained primitives and thus never receive any key events
// themselves. Therefore, they cannot intercept key events.
func ( *Box) ( func( *tcell.EventKey) *tcell.EventKey) {
	.l.Lock()
	defer .l.Unlock()

	.inputCapture = 
}

// GetInputCapture returns the function installed with SetInputCapture() or nil
// if no such function has been installed.
func ( *Box) () func( *tcell.EventKey) *tcell.EventKey {
	.l.RLock()
	defer .l.RUnlock()

	return .inputCapture
}

// WrapMouseHandler wraps a mouse event handler (see MouseHandler()) with the
// functionality to capture mouse events (see SetMouseCapture()) before passing
// them on to the provided (default) event handler.
//
// This is only meant to be used by subclassing primitives.
func ( *Box) ( func(MouseAction, *tcell.EventMouse, func( Primitive)) (bool, Primitive)) func( MouseAction,  *tcell.EventMouse,  func( Primitive)) ( bool,  Primitive) {
	return func( MouseAction,  *tcell.EventMouse,  func( Primitive)) ( bool,  Primitive) {
		if .mouseCapture != nil {
			,  = .mouseCapture(, )
		}
		if  != nil &&  != nil {
			,  = (, , )
		}
		return
	}
}

// MouseHandler returns nil.
func ( *Box) () func( MouseAction,  *tcell.EventMouse,  func( Primitive)) ( bool,  Primitive) {
	return .WrapMouseHandler(func( MouseAction,  *tcell.EventMouse,  func( Primitive)) ( bool,  Primitive) {
		if  == MouseLeftClick && .InRect(.Position()) {
			()
			 = true
		}
		return
	})
}

// SetMouseCapture sets a function which captures mouse events (consisting of
// the original tcell mouse event and the semantic mouse action) before they are
// forwarded to the primitive's default mouse event handler. This function can
// then choose to forward that event (or a different one) by returning it or
// returning a nil mouse event, in which case the default handler will not be
// called.
//
// Providing a nil handler will remove a previously existing handler.
func ( *Box) ( func( MouseAction,  *tcell.EventMouse) (MouseAction, *tcell.EventMouse)) {
	.mouseCapture = 
}

// InRect returns true if the given coordinate is within the bounds of the box's
// rectangle.
func ( *Box) (,  int) bool {
	, , ,  := .GetRect()
	return  >=  &&  < + &&  >=  &&  < +
}

// GetMouseCapture returns the function installed with SetMouseCapture() or nil
// if no such function has been installed.
func ( *Box) () func( MouseAction,  *tcell.EventMouse) (MouseAction, *tcell.EventMouse) {
	return .mouseCapture
}

// SetBackgroundColor sets the box's background color.
func ( *Box) ( tcell.Color) {
	.l.Lock()
	defer .l.Unlock()

	.backgroundColor = 
}

// GetBackgroundColor returns the box's background color.
func ( *Box) () tcell.Color {
	.l.RLock()
	defer .l.RUnlock()
	return .backgroundColor
}

// SetBackgroundTransparent sets the flag indicating whether or not the box's
// background is transparent. The screen is not cleared before drawing the
// application. Overlaying transparent widgets directly onto the screen may
// result in artifacts. To resolve this, add a blank, non-transparent Box to
// the bottom layer of the interface via Panels, or set a handler via
// SetBeforeDrawFunc which clears the screen.
func ( *Box) ( bool) {
	.l.Lock()
	defer .l.Unlock()

	.backgroundTransparent = 
}

// GetBorder returns a value indicating whether the box have a border
// or not.
func ( *Box) () bool {
	.l.RLock()
	defer .l.RUnlock()
	return .border
}

// SetBorder sets the flag indicating whether or not the box should have a
// border.
func ( *Box) ( bool) {
	.l.Lock()
	defer .l.Unlock()

	.border = 

	.updateInnerRect()
}

// SetBorderColor sets the box's border color.
func ( *Box) ( tcell.Color) {
	.l.Lock()
	defer .l.Unlock()

	.borderColor = 
}

// SetBorderColorFocused sets the box's border color when the box is focused.
func ( *Box) ( tcell.Color) {
	.l.Lock()
	defer .l.Unlock()
	.borderColorFocused = 
}

// SetBorderAttributes sets the border's style attributes. You can combine
// different attributes using bitmask operations:
//
//   box.SetBorderAttributes(tcell.AttrUnderline | tcell.AttrBold)
func ( *Box) ( tcell.AttrMask) {
	.l.Lock()
	defer .l.Unlock()

	.borderAttributes = 
}

// SetTitle sets the box's title.
func ( *Box) ( string) {
	.l.Lock()
	defer .l.Unlock()

	.title = []byte()
}

// GetTitle returns the box's current title.
func ( *Box) () string {
	.l.RLock()
	defer .l.RUnlock()

	return string(.title)
}

// SetTitleColor sets the box's title color.
func ( *Box) ( tcell.Color) {
	.l.Lock()
	defer .l.Unlock()

	.titleColor = 
}

// SetTitleAlign sets the alignment of the title, one of AlignLeft, AlignCenter,
// or AlignRight.
func ( *Box) ( int) {
	.l.Lock()
	defer .l.Unlock()

	.titleAlign = 
}

// Draw draws this primitive onto the screen.
func ( *Box) ( tcell.Screen) {
	.l.Lock()
	defer .l.Unlock()

	// Don't draw anything if the box is hidden
	if !.visible {
		return
	}

	// Don't draw anything if there is no space.
	if .width <= 0 || .height <= 0 {
		return
	}

	 := tcell.StyleDefault

	// Fill background.
	 := .Background(.backgroundColor)
	if !.backgroundTransparent {
		for  := .y;  < .y+.height; ++ {
			for  := .x;  < .x+.width; ++ {
				.SetContent(, , ' ', nil, )
			}
		}
	}

	// Draw border.
	if .border && .width >= 2 && .height >= 2 {
		 := SetAttributes(.Foreground(.borderColor), .borderAttributes)
		var , , , , ,  rune

		var  bool
		if .focus ==  {
			 = .hasFocus
		} else {
			 = .focus.HasFocus()
		}

		if  && .borderColorFocused != ColorUnset {
			 = SetAttributes(.Foreground(.borderColorFocused), .borderAttributes)
		}

		if  && .showFocus {
			 = Borders.HorizontalFocus
			 = Borders.VerticalFocus
			 = Borders.TopLeftFocus
			 = Borders.TopRightFocus
			 = Borders.BottomLeftFocus
			 = Borders.BottomRightFocus
		} else {
			 = Borders.Horizontal
			 = Borders.Vertical
			 = Borders.TopLeft
			 = Borders.TopRight
			 = Borders.BottomLeft
			 = Borders.BottomRight
		}
		for  := .x + 1;  < .x+.width-1; ++ {
			.SetContent(, .y, , nil, )
			.SetContent(, .y+.height-1, , nil, )
		}
		for  := .y + 1;  < .y+.height-1; ++ {
			.SetContent(.x, , , nil, )
			.SetContent(.x+.width-1, , , nil, )
		}
		.SetContent(.x, .y, , nil, )
		.SetContent(.x+.width-1, .y, , nil, )
		.SetContent(.x, .y+.height-1, , nil, )
		.SetContent(.x+.width-1, .y+.height-1, , nil, )

		// Draw title.
		if len(.title) > 0 && .width >= 4 {
			,  := Print(, .title, .x+1, .y, .width-2, .titleAlign, .titleColor)
			if len(.title)- > 0 &&  > 0 {
				, , ,  := .GetContent(.x+.width-2, .y)
				, ,  := .Decompose()
				Print(, []byte(string(SemigraphicsHorizontalEllipsis)), .x+.width-2, .y, 1, AlignLeft, )
			}
		}
	}

	// Call custom draw function.
	if .draw != nil {
		.innerX, .innerY, .innerWidth, .innerHeight = .draw(, .x, .y, .width, .height)
	}
}

// ShowFocus sets the flag indicating whether or not the borders of this
// primitive should change thickness when focused.
func ( *Box) ( bool) {
	.l.Lock()
	defer .l.Unlock()

	.showFocus = 
}

// Focus is called when this primitive receives focus.
func ( *Box) ( func( Primitive)) {
	.l.Lock()
	defer .l.Unlock()

	.hasFocus = true
}

// Blur is called when this primitive loses focus.
func ( *Box) () {
	.l.Lock()
	defer .l.Unlock()

	.hasFocus = false
}

// HasFocus returns whether or not this primitive has focus.
func ( *Box) () bool {
	.l.RLock()
	defer .l.RUnlock()

	return .hasFocus
}

// GetFocusable returns the item's Focusable.
func ( *Box) () Focusable {
	.l.RLock()
	defer .l.RUnlock()

	return .focus
}

// GetBorderPadding returns the size of the padding around the box content.
//
// Deprecated: This function is provided for backwards compatibility.
// Developers should use GetPadding instead.
func ( *Box) () (, , ,  int) {
	return .GetPadding()
}

// SetBorderPadding sets the size of the padding around the box content.
//
// Deprecated: This function is provided for backwards compatibility.
// Developers should use SetPadding instead.
func ( *Box) (, , ,  int) {
	.SetPadding(, , , )
}