package core

import (
	
	
)

// Cursor is the cursor position in the current line buffer.
// Contains methods to set, move, describe and check itself.
type Cursor struct {
	pos  int
	mark int
	line *Line
}

// NewCursor is a required constructor for the line cursor,
// because some default numeric values must be negative.
func ( *Line) *Cursor {
	return &Cursor{
		pos:  0,
		mark: -1,
		line: ,
	}
}

// Set sets the position of the cursor to an absolute value.
// If either negative or greater than the length of the line,
// the cursor will be set to either 0, or the length of the line.
func ( *Cursor) ( int) {
	defer .CheckAppend()

	switch {
	case  < 0:
		.pos = 0
	case  > .line.Len():
		.pos = .line.Len()
	default:
		.pos = 
	}
}

// Pos returns the current cursor position.
// This function cannot return an invalid cursor position: it cannot be negative, nor it
// can be greater than the length of the line (note that it still can be out of line by 1).
func ( *Cursor) () int {
	.CheckAppend()
	return .pos
}

// Inc increments the cursor position by 1,
// if it's not at the end of the line.
func ( *Cursor) () {
	if .pos < .line.Len() {
		.pos++
	}
}

// Dec decrements the cursor position by 1,
// if it's not at the beginning of the line.
func ( *Cursor) () {
	if .pos > 0 {
		.pos--
	}
}

// Move moves the cursor position by a relative value. If the end result is negative,
// the cursor is set to 0. If longer than the line, the cursor is set to length of line.
func ( *Cursor) ( int) {
	defer .CheckAppend()
	.pos += 
}

// Char returns the rune (unicode point) under the cursor.
// If the line is empty, or if the cursor is appending to
// the line, the returned rune is 0 (rune(0)).
func ( *Cursor) () rune {
	.CheckAppend()

	if .line.Len() == 0 {
		return rune(0)
	}

	if .pos >= .line.Len() {
		return rune(0)
	}

	return (*.line)[.pos]
}

// ReplaceWith replaces the rune (unicode point) under the cursor with the provided one.
// If the cursor is appending to the line, the character is simply added at the end of it.
func ( *Cursor) ( rune) {
	.CheckAppend()

	switch {
	case .pos == .line.Len():
		.line.Insert(.line.Len(), )
	default:
		(*.line)[.pos] = 
	}
}

// InsertAt inserts the given runes into the line at the current cursor position.
func ( *Cursor) ( ...rune) {
	.CheckAppend()

	.line.Insert(.pos, ...)
	.pos += len()
}

// ToFirstNonSpace moves the cursor either backward or forward to
// the first character in the line that is not a space, a tab or
// a newline. If the current is not one, the cursor doesn't move.
// If the cursor is at the end of the line, the move is performed
// backward, regardless of the forward parameter value.
func ( *Cursor) ( bool) {
	if .line.Len() == 0 {
		return
	}

	defer .CheckAppend()

	if .pos >= .line.Len() {
		 = false
		.pos = .line.Len() - 1
	}

	// At line bounds
	if ! && .pos == 0 {
		return
	}

	for {
		if !.onSpace() {
			return
		}

		if  {
			.pos++
		} else {
			.pos--
		}

		if .pos <= 0 {
			return
		}
	}
}

// BeginningOfLine moves the cursor to the beginning of the current line,
// (marked by a newline) or if no newline found, to the beginning of the buffer.
func ( *Cursor) () {
	defer .CheckCommand()

	 := .line.Find(inputrc.Newline, .pos, false)
	if  != -1 {
		.pos =  + 1
	} else {
		.pos = 0
	}
}

// EndOfLine moves the cursor to the end of the current line,
// (marked by a newline) or if no newline found, to the position
// of the last character in the buffer.
func ( *Cursor) () {
	defer .CheckCommand()

	if .OnEmptyLine() {
		return
	}

	 := .line.Find(inputrc.Newline, .pos, true)

	if  != -1 {
		.pos =  - 1
	} else {
		.pos = .line.Len() - 1
	}
}

// EndOfLineAppend moves the cursor to the end of either current line
// (if buffer is multiline), or the whole buffer, in append-mode.
func ( *Cursor) () {
	defer .CheckAppend()

	if .OnEmptyLine() {
		return
	}

	 := .line.Find(inputrc.Newline, .pos-1, true)

	if  != -1 {
		.pos = 
	} else {
		.pos = .line.Len()
	}
}

// SetMark sets the current cursor position as the mark.
func ( *Cursor) () {
	.CheckAppend()
	.mark = .pos
}

// Mark returns the current mark value of the cursor, or -1 if not set.
func ( *Cursor) () int {
	return .mark
}

// ResetMark resets the insertion point mark (-1).
func ( *Cursor) () {
	.mark = -1
}

// LinePos returns the index of the current line on which the cursor is.
// A line is defined as a sequence of runes between one or two newline
// characters, between end and/or beginning of buffer, or a mix of both.
func ( *Cursor) () int {
	.CheckAppend()

	 := .line.newlines()

	// Either match between two newlines
	for ,  := range  {
		if [0] < .pos {
			continue
		}

		return 
	}

	// Or return the number of lines
	return len()
}

// LineMove moves the cursor by n lines either up (if the value is negative),
// or down (if positive). If greater than the length of possible lines above/below,
// the cursor will be set to either the first, or the last line of the buffer.
func ( *Cursor) ( int) {
	.CheckAppend()
	defer .CheckAppend()

	 := .line.newlines()
	if len() == 1 ||  == 0 {
		return
	}

	if  < 0 {
		for  := 0;  < -1*; ++ {
			.moveLineUp()
			.CheckCommand()
		}
	} else {
		for  := 0;  < ; ++ {
			.moveLineDown()
			.CheckCommand()
		}
	}
}

// OnEmptyLine returns true if the rune under the current cursor position is a newline
// and that the preceding rune in the line is also a newline, or returns false.
func ( *Cursor) () bool {
	if .line.Len() == 0 {
		return true
	}

	if .pos == 0 {
		return (*.line)[.pos] == inputrc.Newline
	} else if .pos == .line.Len() {
		return (*.line)[.pos-1] == inputrc.Newline
	}

	 := (*.line)[.pos] == inputrc.Newline
	 := (*.line)[.pos-1] == inputrc.Newline

	return  && 
}

// AtBeginningOfLine returns true if the cursor is either at the beginning
// of the line buffer, or on the first character after the previous newline.
func ( *Cursor) () bool {
	if .pos == 0 {
		return true
	}

	 := .line.newlines()

	for  := 0;  < len(); ++ {
		 := [][0]
		if  == .pos-1 {
			return true
		}
	}

	return false
}

// AtEndOfLine returns true if the cursor is either at the end of the
// buffer, or if the character immediately following it is a newline.
func ( *Cursor) () bool {
	if .pos >= .line.Len()-1 {
		return true
	}

	 := .line.newlines()

	for  := 0;  < len(); ++ {
		 := [][0]
		if  == .pos+1 {
			return true
		}
	}

	return false
}

// CheckAppend verifies that the current cursor position is neither negative,
// nor greater than the length of the input line. If either is true, the
// cursor will set its value as either 0, or the length of the line.
func ( *Cursor) () {
	// Position
	if .pos < 0 {
		.pos = 0
	}

	if .pos > .line.Len() {
		.pos = .line.Len()
	}

	// Mark, invalid position deactivates it.
	if .mark < -1 {
		.mark = -1
	}

	if .mark > .line.Len()-1 {
		.mark = -1
	}
}

// CheckCommand is like CheckAppend, but ensures the cursor position is never greater
// than the length of the line minus 1, since in Vim command mode, the cursor is on a char.
func ( *Cursor) () {
	.CheckAppend()

	if .pos == .line.Len() && !.OnEmptyLine() {
		.pos--
	}

	// The cursor can also not be on a newline sign,
	// as it will induce the line rendering into an error.
	if .line.Len() > 0 && .pos < .line.Len() && .Char() == '\n' && !.OnEmptyLine() {
		.Dec()
	}
}

// CoordinatesCursor returns the number of real terminal lines above the cursor position
// (y value), and the number of columns since the beginning of the current line (x value).
// @indent -    Used to align all lines (except the first) together on a single column.
func ( *Cursor,  int) (,  int) {
	.CheckAppend()

	 := .line.newlines()
	 := 0
	 := 0

	for ,  := range  {
		switch {
		case [0] < .pos:
			// Until we didn't reach the cursor line,
			// simply care about the line count.
			 := (*.line)[:[0]]
			 = [0] + 1
			,  := strutil.LineSpan(, , )
			 += 

		default:
			// On the cursor line, use both line and column count.
			 := (*.line)[:.pos]
			,  := strutil.LineSpan(, , )
			 += 

			return , 
		}
	}

	return
}

func ( *Cursor) () {
	var ,  int
	 = -1

	 := .line.newlines()

	for  := 0;  < len(); ++ {
		 := [][0]
		if  < .LinePos() {
			 = 
			continue
		}

		// If we are on the current line,
		// go at the end of it
		if  == .LinePos() {
			 = .pos - 
			 = 

			continue
		}

		// And either go at the end of the line
		// or to the previous cursor X coordinate.
		if - >  {
			.pos =  + 
		} else {
			.pos = 
		}

		break
	}
}

func ( *Cursor) () {
	var ,  int

	 := .line.newlines()

	for  := len() - 1;  >= 0; -- {
		 := [][0]

		if  > .LinePos() {
			continue
		}

		// Get the beginning of the previous line.
		if  > 0 {
			 = [-1][0]
		} else {
			 = -1
			--
		}

		// If we are on the current line,
		// go at the beginning of the previous one.
		if  == .LinePos() {
			 = .pos - 
			continue
		}

		// And either go at the end of the line
		// or to the previous cursor X coordinate.
		if - >  {
			.pos =  + 
		} else {
			.pos = 
		}

		break
	}
}

func ( *Cursor) () bool {
	switch .Char() {
	case inputrc.Space, inputrc.Newline, inputrc.Tab:
		return true
	default:
		return false
	}
}