package tk

import (
	

	
	
	
)

// TextView is a Widget for displaying text, with support for vertical
// scrolling.
//
// NOTE: This widget now always crops long lines. In future it should support
// wrapping and horizontal scrolling.
type TextView interface {
	Widget
	// ScrollBy scrolls the widget by the given delta. Positive values scroll
	// down, and negative values scroll up.
	ScrollBy(delta int)
	// MutateState mutates the state.
	MutateState(f func(*TextViewState))
	// CopyState returns a copy of the State.
	CopyState() TextViewState
}

// TextViewSpec specifies the configuration and initial state for a Widget.
type TextViewSpec struct {
	// Key bindings.
	Bindings Bindings
	// If true, a vertical scrollbar will be shown when there are more lines
	// that can be displayed, and the widget responds to Up and Down keys.
	Scrollable bool
	// State. Specifies the initial state if used in New.
	State TextViewState
}

// TextViewState keeps mutable state of TextView.
type TextViewState struct {
	Lines []string
	First int
}

type textView struct {
	// Mutex for synchronizing access to the state.
	StateMutex sync.RWMutex
	TextViewSpec
}

// NewTextView builds a TextView from the given spec.
func ( TextViewSpec) TextView {
	if .Bindings == nil {
		.Bindings = DummyBindings{}
	}
	return &textView{TextViewSpec: }
}

func ( *textView) (,  int) *term.Buffer {
	,  := .getStateForRender()
	 := .Scrollable && ( > 0 || + < len())
	 := 
	if  {
		--
	}

	 := term.NewBufferBuilder()
	for  := ;  < + &&  < len(); ++ {
		if  >  {
			.Newline()
		}
		.Write(wcwidth.Trim([], ))
	}
	 := .Buffer()

	if  {
		 := VScrollbar{
			Total: len(), Low: , High:  + }
		.ExtendRight(.Render(1, ))
	}
	return 
}

func ( *textView) ( int) ( []string,  int) {
	.MutateState(func( *TextViewState) {
		if .First > len(.Lines)- && len(.Lines)- >= 0 {
			.First = len(.Lines) - 
		}
		,  = .Lines, .First
	})
	return
}

func ( *textView) ( term.Event) bool {
	if .Bindings.Handle(, ) {
		return true
	}

	if .Scrollable {
		switch  {
		case term.K(ui.Up):
			.ScrollBy(-1)
			return true
		case term.K(ui.Down):
			.ScrollBy(1)
			return true
		}
	}
	return false
}

func ( *textView) ( int) {
	.MutateState(func( *TextViewState) {
		.First += 
		if .First < 0 {
			.First = 0
		}
		if .First >= len(.Lines) {
			.First = len(.Lines) - 1
		}
	})
}

func ( *textView) ( func(*TextViewState)) {
	.StateMutex.Lock()
	defer .StateMutex.Unlock()
	(&.State)
}

// CopyState returns a copy of the State while r-locking the StateMutex.
func ( *textView) () TextViewState {
	.StateMutex.RLock()
	defer .StateMutex.RUnlock()
	return .State
}