package cview

import (
	

	
)

// CheckBox implements a simple box for boolean values which can be checked and
// unchecked.
type CheckBox struct {
	*Box

	// Whether or not this box is checked.
	checked bool

	// The text to be displayed before the checkbox.
	label []byte

	// The text to be displayed after the checkbox.
	message []byte

	// The screen width of the label area. A value of 0 means use the width of
	// the label text.
	labelWidth int

	// The label color.
	labelColor tcell.Color

	// The label color when focused.
	labelColorFocused tcell.Color

	// The background color of the input area.
	fieldBackgroundColor tcell.Color

	// The background color of the input area when focused.
	fieldBackgroundColorFocused tcell.Color

	// The text color of the input area.
	fieldTextColor tcell.Color

	// The text color of the input area when focused.
	fieldTextColorFocused tcell.Color

	// An optional function which is called when the user changes the checked
	// state of this checkbox.
	changed func(checked bool)

	// An optional function which is called when the user indicated that they
	// are done entering text. The key which was pressed is provided (tab,
	// shift-tab, or escape).
	done func(tcell.Key)

	// A callback function set by the Form class and called when the user leaves
	// this form item.
	finished func(tcell.Key)

	// The rune to show when the checkbox is checked
	checkedRune rune

	// An optional rune to show within the checkbox when it is focused
	cursorRune rune

	sync.RWMutex
}

// NewCheckBox returns a new input field.
func () *CheckBox {
	return &CheckBox{
		Box:                         NewBox(),
		labelColor:                  Styles.SecondaryTextColor,
		fieldBackgroundColor:        Styles.MoreContrastBackgroundColor,
		fieldBackgroundColorFocused: Styles.ContrastBackgroundColor,
		fieldTextColor:              Styles.PrimaryTextColor,
		checkedRune:                 Styles.CheckBoxCheckedRune,
		cursorRune:                  Styles.CheckBoxCursorRune,
		labelColorFocused:           ColorUnset,
		fieldTextColorFocused:       ColorUnset,
	}
}

// SetChecked sets the state of the checkbox.
func ( *CheckBox) ( bool) {
	.Lock()
	defer .Unlock()

	.checked = 
}

// SetCheckedRune sets the rune to show when the checkbox is checked.
func ( *CheckBox) ( rune) {
	.Lock()
	defer .Unlock()

	.checkedRune = 
}

// SetCursorRune sets the rune to show within the checkbox when it is focused.
func ( *CheckBox) ( rune) {
	.Lock()
	defer .Unlock()

	.cursorRune = 
}

// IsChecked returns whether or not the box is checked.
func ( *CheckBox) () bool {
	.RLock()
	defer .RUnlock()

	return .checked
}

// SetLabel sets the text to be displayed before the input area.
func ( *CheckBox) ( string) {
	.Lock()
	defer .Unlock()

	.label = []byte()
}

// GetLabel returns the text to be displayed before the input area.
func ( *CheckBox) () string {
	.RLock()
	defer .RUnlock()

	return string(.label)
}

// SetMessage sets the text to be displayed after the checkbox
func ( *CheckBox) ( string) {
	.Lock()
	defer .Unlock()

	.message = []byte()
}

// GetMessage returns the text to be displayed after the checkbox
func ( *CheckBox) () string {
	.RLock()
	defer .RUnlock()

	return string(.message)
}

// SetLabelWidth sets the screen width of the label. A value of 0 will cause the
// primitive to use the width of the label string.
func ( *CheckBox) ( int) {
	.Lock()
	defer .Unlock()

	.labelWidth = 
}

// SetLabelColor sets the color of the label.
func ( *CheckBox) ( tcell.Color) {
	.Lock()
	defer .Unlock()

	.labelColor = 
}

// SetLabelColorFocused sets the color of the label when focused.
func ( *CheckBox) ( tcell.Color) {
	.Lock()
	defer .Unlock()

	.labelColorFocused = 
}

// SetFieldBackgroundColor sets the background color of the input area.
func ( *CheckBox) ( tcell.Color) {
	.Lock()
	defer .Unlock()

	.fieldBackgroundColor = 
}

// SetFieldBackgroundColorFocused sets the background color of the input area when focused.
func ( *CheckBox) ( tcell.Color) {
	.Lock()
	defer .Unlock()

	.fieldBackgroundColorFocused = 
}

// SetFieldTextColor sets the text color of the input area.
func ( *CheckBox) ( tcell.Color) {
	.Lock()
	defer .Unlock()

	.fieldTextColor = 
}

// SetFieldTextColorFocused sets the text color of the input area when focused.
func ( *CheckBox) ( tcell.Color) {
	.Lock()
	defer .Unlock()

	.fieldTextColorFocused = 
}

// GetFieldHeight returns the height of the field.
func ( *CheckBox) () int {
	return 1
}

// GetFieldWidth returns this primitive's field width.
func ( *CheckBox) () int {
	.RLock()
	defer .RUnlock()

	if len(.message) == 0 {
		return 1
	}

	return 2 + len(.message)
}

// SetChangedFunc sets a handler which is called when the checked state of this
// checkbox was changed by the user. The handler function receives the new
// state.
func ( *CheckBox) ( func( bool)) {
	.Lock()
	defer .Unlock()

	.changed = 
}

// SetDoneFunc sets a handler which is called when the user is done using the
// checkbox. The callback function is provided with the key that was pressed,
// which is one of the following:
//
//   - KeyEscape: Abort text input.
//   - KeyTab: Move to the next field.
//   - KeyBacktab: Move to the previous field.
func ( *CheckBox) ( func( tcell.Key)) {
	.Lock()
	defer .Unlock()

	.done = 
}

// SetFinishedFunc sets a callback invoked when the user leaves this form item.
func ( *CheckBox) ( func( tcell.Key)) {
	.Lock()
	defer .Unlock()

	.finished = 
}

// Draw draws this primitive onto the screen.
func ( *CheckBox) ( tcell.Screen) {
	if !.GetVisible() {
		return
	}

	.Box.Draw()

	.Lock()
	defer .Unlock()

	 := .GetFocusable().HasFocus()

	// Select colors
	 := .labelColor
	 := .fieldBackgroundColor
	 := .fieldTextColor
	if  {
		if .labelColorFocused != ColorUnset {
			 = .labelColorFocused
		}
		if .fieldBackgroundColorFocused != ColorUnset {
			 = .fieldBackgroundColorFocused
		}
		if .fieldTextColorFocused != ColorUnset {
			 = .fieldTextColorFocused
		}
	}

	// Prepare
	, , ,  := .GetInnerRect()
	 :=  + 
	if  < 1 ||  <=  {
		return
	}

	// Draw label.
	if .labelWidth > 0 {
		 := .labelWidth
		if  > - {
			 =  - 
		}
		Print(, .label, , , , AlignLeft, )
		 += 
	} else {
		,  := Print(, .label, , , -, AlignLeft, )
		 += 
	}

	// Draw checkbox.
	 := tcell.StyleDefault.Background().Foreground()

	 := .checkedRune
	if !.checked {
		 = ' '
	}
	 := ' '
	if .cursorRune != 0 &&  {
		 = .cursorRune
	}
	.SetContent(, , ' ', nil, )
	.SetContent(+1, , , nil, )
	.SetContent(+2, , , nil, )

	if len(.message) > 0 {
		Print(, .message, +4, , len(.message), AlignLeft, )
	}
}

// InputHandler returns the handler for this primitive.
func ( *CheckBox) () func( *tcell.EventKey,  func( Primitive)) {
	return .WrapInputHandler(func( *tcell.EventKey,  func( Primitive)) {
		if HitShortcut(, Keys.Select, Keys.Select2) {
			.Lock()
			.checked = !.checked
			.Unlock()
			if .changed != nil {
				.changed(.checked)
			}
		} else if HitShortcut(, Keys.Cancel, Keys.MovePreviousField, Keys.MoveNextField) {
			if .done != nil {
				.done(.Key())
			}
			if .finished != nil {
				.finished(.Key())
			}
		}
	})
}

// MouseHandler returns the mouse handler for this primitive.
func ( *CheckBox) () func( MouseAction,  *tcell.EventMouse,  func( Primitive)) ( bool,  Primitive) {
	return .WrapMouseHandler(func( MouseAction,  *tcell.EventMouse,  func( Primitive)) ( bool,  Primitive) {
		,  := .Position()
		, , ,  := .GetInnerRect()
		if !.InRect(, ) {
			return false, nil
		}

		// Process mouse event.
		if  == MouseLeftClick &&  ==  {
			()
			.checked = !.checked
			if .changed != nil {
				.changed(.checked)
			}
			 = true
		}

		return
	})
}