package display

import (
	

	
	
	
	
	
	
	
	
)

var (
	oneThirdTerminalHeight = 3
	halfTerminalHeight     = 2
)

// Engine handles all display operations: it refreshes the terminal
// interface and stores the necessary offsets of each components.
type Engine struct {
	// Operating parameters
	highlighter    func(line []rune) string
	startCols      int
	startRows      int
	lineCol        int
	lineRows       int
	cursorRow      int
	cursorCol      int
	hintRows       int
	compRows       int
	primaryPrinted bool

	// UI components
	keys      *core.Keys
	line      *core.Line
	suggested core.Line
	cursor    *core.Cursor
	selection *core.Selection
	histories *history.Sources
	prompt    *ui.Prompt
	hint      *ui.Hint
	completer *completion.Engine
	opts      *inputrc.Config
}

// NewEngine is a required constructor for the display engine.
func ( *core.Keys,  *core.Selection,  *history.Sources,  *ui.Prompt,  *ui.Hint,  *completion.Engine,  *inputrc.Config) *Engine {
	return &Engine{
		keys:      ,
		selection: ,
		histories: ,
		prompt:    ,
		hint:      ,
		completer: ,
		opts:      ,
	}
}

// Init computes some base coordinates needed before displaying the line and helpers.
// The shell syntax highlighter is also provided here, since any consumer library will
// have bound it after instantiating a new shell instance.
func ( *Engine,  func([]rune) string) {
	.highlighter = 
}

// Refresh recomputes and redisplays the entire readline interface, except
// the first lines of the primary prompt when the latter is a multiline one.
func ( *Engine) () {
	fmt.Print(term.HideCursor)

	// Go back to the first column, and if the primary prompt
	// was not printed yet, back up to the line's beginning row.
	term.MoveCursorBackwards(term.GetWidth())

	if !.primaryPrinted {
		term.MoveCursorUp(.cursorRow)
	}

	// Print either all or the last line of the prompt.
	.prompt.LastPrint()

	// Get all positions required for the redisplay to come:
	// prompt end (thus indentation), cursor positions, etc.
	.computeCoordinates(true)

	// Print the line, and any of the secondary and right prompts.
	.displayLine()
	.displayMultilinePrompts()

	// Display hints and completions, go back
	// to the start of the line, then to cursor.
	.displayHelpers()
	.cursorHintToLineStart()
	.lineStartToCursorPos()
	fmt.Print(term.ShowCursor)
}

// PrintPrimaryPrompt redraws the primary prompt.
// There are relatively few cases where you want to use this.
// It is currently only used when using clear-screen commands.
func ( *Engine) () {
	.prompt.PrimaryPrint()
	.primaryPrinted = true
}

// ClearHelpers clears the hint and completion sections below the line.
func ( *Engine) () {
	.CursorBelowLine()
	fmt.Print(term.ClearScreenBelow)

	term.MoveCursorUp(1)
	term.MoveCursorUp(.lineRows)
	term.MoveCursorDown(.cursorRow)
	term.MoveCursorForwards(.cursorCol)
}

// ResetHelpers cancels all active hints and completions.
func ( *Engine) () {
	.hint.Reset()
	.completer.ClearMenu(true)
}

// AcceptLine redraws the current UI when the line has been accepted
// and returned to the caller. After clearing various things such as
// hints, completions and some right prompts, the shell will put the
// display at the start of the line immediately following the line.
func ( *Engine) () {
	.CursorToLineStart()

	.computeCoordinates(false)

	// Go back to the end of the non-suggested line.
	term.MoveCursorBackwards(term.GetWidth())
	term.MoveCursorDown(.lineRows)
	term.MoveCursorForwards(.lineCol)
	fmt.Print(term.ClearScreenBelow)

	// Reprint the right-side prompt if it's not a tooltip one.
	.prompt.RightPrint(.lineCol, false)

	// Go below this non-suggested line and clear everything.
	term.MoveCursorBackwards(term.GetWidth())
	fmt.Print(term.NewlineReturn)
}

// RefreshTransient goes back to the first line of the input buffer
// and displays the transient prompt, then redisplays the input line.
func ( *Engine) () {
	if !.opts.GetBool("prompt-transient") {
		return
	}

	// Go to the beginning of the primary prompt.
	.CursorToLineStart()
	term.MoveCursorUp(.prompt.PrimaryUsed())

	// And redisplay the transient/primary/line.
	.prompt.TransientPrint()
	.displayLine()
	fmt.Print(term.NewlineReturn)
}

// CursorToLineStart moves the cursor just after the primary prompt.
// This function should only be called when the cursor is on its
// "cursor" position on the input line.
func ( *Engine) () {
	term.MoveCursorBackwards(.cursorCol)
	term.MoveCursorUp(.cursorRow)
	term.MoveCursorForwards(.startCols)
}

// CursorBelowLine moves the cursor to the leftmost
// column of the first row after the last line of input.
// This function should only be called when the cursor
// is on its "cursor" position on the input line.
func ( *Engine) () {
	term.MoveCursorUp(.cursorRow)
	term.MoveCursorDown(.lineRows)
	fmt.Print(term.NewlineReturn)
}

// lineStartToCursorPos can be used if the cursor is currently
// at the very start of the input line, that is just after the
// last character of the prompt.
func ( *Engine) () {
	term.MoveCursorDown(.cursorRow)
	term.MoveCursorBackwards(term.GetWidth())
	term.MoveCursorForwards(.cursorCol)
}

// cursor is on the line below the last line of input.
func ( *Engine) () {
	term.MoveCursorUp(1)
	term.MoveCursorUp(.lineRows - .cursorRow)
	.CursorToLineStart()
}

func ( *Engine) ( bool) {
	// Get the new input line and auto-suggested one.
	.line, .cursor = .completer.Line()
	if .completer.IsInserting() {
		.suggested = *.line
	} else {
		.suggested = .histories.Suggest(.line)
	}

	// Get the position of the line's beginning by querying
	// the terminal for the cursor position.
	.startCols, .startRows = .keys.GetCursorPos()

	if .startCols > 0 {
		.startCols--
	}

	// Cursor position might be misleading if invalid (negative).
	if .startCols == -1 {
		.startCols = .prompt.LastUsed()
	}

	.cursorCol, .cursorRow = core.CoordinatesCursor(.cursor, .startCols)

	// Get the number of rows used by the line, and the end line X pos.
	if .opts.GetBool("history-autosuggest") &&  {
		.lineCol, .lineRows = core.CoordinatesLine(&.suggested, .startCols)
	} else {
		.lineCol, .lineRows = core.CoordinatesLine(.line, .startCols)
	}

	.primaryPrinted = false
}

func ( *Engine) () {
	var  string

	// Apply user-defined highlighter to the input line.
	if .highlighter != nil {
		 = .highlighter(*.line)
	} else {
		 = string(*.line)
	}

	// Highlight matching parenthesis
	if .opts.GetBool("blink-matching-paren") {
		core.HighlightMatchers(.selection)
		defer core.ResetMatchers(.selection)
	}

	// Apply visual selections highlighting if any
	 = .highlightLine([]rune(), *.selection)

	// Get the subset of the suggested line to print.
	if len(.suggested) > .line.Len() && .opts.GetBool("history-autosuggest") {
		 += color.Dim + color.Fmt(color.Fg+"242") + string(.suggested[.line.Len():]) + color.Reset
	}

	// Format tabs as spaces, for consistent display
	 = strutil.FormatTabs() + term.ClearLineAfter

	// And display the line.
	.suggested.Set([]rune()...)
	core.DisplayLine(&.suggested, .startCols)

	// Adjust the cursor if the line fits exactly in the terminal width.
	if .lineCol == 0 {
		fmt.Print(term.NewlineReturn)
		fmt.Print(term.ClearLineAfter)
	}
}

func ( *Engine) () {
	// If we have more than one line, write the columns.
	if .line.Lines() > 1 {
		term.MoveCursorUp(.lineRows)
		term.MoveCursorBackwards(term.GetWidth())
		.prompt.MultilineColumnPrint()
	}

	// Then if we have a line at all, rewrite the last column
	// character with any secondary prompt available.
	if .line.Lines() > 0 {
		term.MoveCursorBackwards(term.GetWidth())
		.prompt.SecondaryPrint()
		term.MoveCursorBackwards(term.GetWidth())
		term.MoveCursorForwards(.lineCol)
	}

	// Then prompt the right-sided prompt if possible.
	.prompt.RightPrint(.lineCol, true)
}

// displayHelpers renders the hint and completion sections.
// It assumes that the cursor is on the last line of input,
// and goes back to this same line after displaying this.
func ( *Engine) () {
	fmt.Print(term.NewlineReturn)

	// Recompute completions and hints if autocompletion is on.
	.completer.Autocomplete()

	// Display hint and completions.
	ui.DisplayHint(.hint)
	.hintRows = ui.CoordinatesHint(.hint)
	completion.Display(.completer, .AvailableHelperLines())
	.compRows = completion.Coordinates(.completer)

	// Go back to the first line below the input line.
	term.MoveCursorBackwards(term.GetWidth())
	term.MoveCursorUp(.compRows)
	term.MoveCursorUp(ui.CoordinatesHint(.hint))
}

// AvailableHelperLines returns the number of lines available below the hint section.
// It returns half the terminal space if we currently have less than 1/3rd of it below.
func ( *Engine) () int {
	 := term.GetLength()
	 :=  - .startRows - .lineRows - .hintRows

	if  < ( / oneThirdTerminalHeight) {
		 = ( / halfTerminalHeight)
	}

	return 
}