package readline

import (
	"strings"
)

// vimDelete -
func (rl *Instance) viDelete(r rune) {

	// We are allowed to type iterations after a delete ('d') command.
	// in which case we don't exit the delete mode. The next thing typed
	// will thus be dispatched back here (like "2d4 then w).
	if !(r <= '9' && '0' <= r) {
		defer func() { rl.modeViMode = VimKeys }()
	}

	switch r {
	case 'b':
		vii := rl.getViIterations()
		rl.saveToRegisterTokenize(tokeniseLine, rl.viJumpB, vii)
		for i := 1; i <= vii; i++ {
			rl.viDeleteByAdjust(rl.viJumpB(tokeniseLine))
		}

	case 'B':
		vii := rl.getViIterations()
		rl.saveToRegisterTokenize(tokeniseSplitSpaces, rl.viJumpB, vii)
		for i := 1; i <= vii; i++ {
			rl.viDeleteByAdjust(rl.viJumpB(tokeniseSplitSpaces))
		}

	case 'd':
		rl.saveBufToRegister(rl.line)
		rl.clearLine()
		rl.resetHelpers()
		rl.getInfoText()

	case 'e':
		vii := rl.getViIterations()
		rl.saveToRegisterTokenize(tokeniseLine, rl.viJumpE, vii)
		for i := 1; i <= vii; i++ {
			rl.viDeleteByAdjust(rl.viJumpE(tokeniseLine) + 1)
		}

	case 'E':
		vii := rl.getViIterations()
		rl.saveToRegisterTokenize(tokeniseSplitSpaces, rl.viJumpE, vii)
		for i := 1; i <= vii; i++ {
			rl.viDeleteByAdjust(rl.viJumpE(tokeniseSplitSpaces) + 1)
		}

	case 'w':
		vii := rl.getViIterations()
		rl.saveToRegisterTokenize(tokeniseLine, rl.viJumpW, vii)
		for i := 1; i <= vii; i++ {
			rl.viDeleteByAdjust(rl.viJumpW(tokeniseLine))
		}

	case 'W':
		vii := rl.getViIterations()
		rl.saveToRegisterTokenize(tokeniseSplitSpaces, rl.viJumpW, vii)
		for i := 1; i <= vii; i++ {
			rl.viDeleteByAdjust(rl.viJumpW(tokeniseSplitSpaces))
		}

	case '%':
		rl.saveToRegister(rl.viJumpBracket())
		rl.viDeleteByAdjust(rl.viJumpBracket())

	case '$':
		rl.saveBufToRegister(rl.line[rl.pos:])
		rl.viDeleteByAdjust(len(rl.line) - rl.pos)
		// Only go back if there is an input
		if len(rl.line) > 0 {
			rl.pos--
		}

	case '[':
		rl.saveToRegister(rl.viJumpPreviousBrace())
		rl.viDeleteByAdjust(rl.viJumpPreviousBrace())

	case ']':
		rl.saveToRegister(rl.viJumpNextBrace())
		rl.viDeleteByAdjust(rl.viJumpNextBrace())

	default:
		if r <= '9' && '0' <= r {
			rl.viIteration += string(r)
		}
		rl.viUndoSkipAppend = true
	}
}

func (rl *Instance) viDeleteByAdjust(adjust int) {
	var (
		newLine []rune
		backOne bool
	)

	// Avoid doing anything if input line is empty.
	if len(rl.line) == 0 {
		return
	}

	switch {
	case adjust == 0:
		rl.viUndoSkipAppend = true
		return
	case rl.pos+adjust == len(rl.line)-1:
		// This case should normally happen only when we met ALL THOSE CONDITIONS:
		// - We are currently in Insert Mode
		// - Appending to the end of the line (the cusor pos is len(line) + 1)
		// - We just deleted a single-lettered word from the input line.
		//
		// We must therefore ake a little adjustment (the -1), otherwise this
		// single letter is kept in the input line while it should be deleted.
		newLine = rl.line[:rl.pos-1]
		if adjust != -1 {
			backOne = true
		}

	case rl.pos+adjust == 0:
		newLine = rl.line[rl.pos:]
	case adjust < 0:
		newLine = append(rl.line[:rl.pos+adjust], rl.line[rl.pos:]...)
	default:
		newLine = append(rl.line[:rl.pos], rl.line[rl.pos+adjust:]...)
	}

	rl.line = newLine

	// rl.updateHelpers()

	if adjust < 0 {
		rl.moveCursorByAdjust(adjust)
	}

	if backOne {
		rl.pos--
	}

	rl.updateHelpers()
}

func (rl *Instance) vimDeleteToken(r rune) bool {
	tokens, _, _ := tokeniseSplitSpaces(rl.line, 0)
	pos := int(r) - 48 // convert ASCII to integer
	if pos > len(tokens) {
		return false
	}

	s := string(rl.line)
	newLine := strings.Replace(s, tokens[pos-1], "", -1)
	if newLine == s {
		return false
	}

	rl.line = []rune(newLine)

	rl.updateHelpers()

	if rl.pos > len(rl.line) {
		rl.pos = len(rl.line) - 1
	}

	return true
}