package mode

import (
	
	
	

	
	
	
	
)

// Lastcmd is a mode for inspecting the last command, and inserting part of all
// of it. It is based on the ComboBox widget.
type Lastcmd interface {
	tk.ComboBox
}

// LastcmdSpec specifies the configuration for the lastcmd mode.
type LastcmdSpec struct {
	// Key bindings.
	Bindings tk.Bindings
	// Store provides the source for the last command.
	Store LastcmdStore
	// Wordifier breaks a command into words.
	Wordifier func(string) []string
}

// LastcmdStore is a subset of histutil.Store used in lastcmd mode.
type LastcmdStore interface {
	Cursor(prefix string) histutil.Cursor
}

var _ = LastcmdStore(histutil.Store(nil))

// NewLastcmd creates a new lastcmd mode.
func ( cli.App,  LastcmdSpec) (Lastcmd, error) {
	if .Store == nil {
		return nil, errNoHistoryStore
	}
	 := .Store.Cursor("")
	.Prev()
	,  := .Get()
	if  != nil {
		return nil, fmt.Errorf("db error: %v", )
	}
	 := .Wordifier
	if  == nil {
		 = strings.Fields
	}
	 := .Text
	 := ()
	 := make([]lastcmdEntry, len()+1)
	[0] = lastcmdEntry{content: }
	for ,  := range  {
		[+1] = lastcmdEntry{strconv.Itoa(), strconv.Itoa( - len()), }
	}

	 := func( string) {
		.CodeArea().MutateState(func( *tk.CodeAreaState) {
			.Buffer.InsertAtDot()
		})
		.SetAddon(nil, false)
	}
	 := tk.NewComboBox(tk.ComboBoxSpec{
		CodeArea: tk.CodeAreaSpec{Prompt: modePrompt(" LASTCMD ", true)},
		ListBox: tk.ListBoxSpec{
			Bindings: .Bindings,
			OnAccept: func( tk.Items,  int) {
				(.(lastcmdItems).entries[].content)
			},
		},
		OnFilter: func( tk.ComboBox,  string) {
			 := filterLastcmdItems(, )
			if len(.entries) == 1 {
				(.entries[0].content)
			} else {
				.ListBox().Reset(, 0)
			}
		},
	})
	return , nil
}

type lastcmdItems struct {
	negFilter bool
	entries   []lastcmdEntry
}

type lastcmdEntry struct {
	posIndex string
	negIndex string
	content  string
}

func ( []lastcmdEntry,  string) lastcmdItems {
	if  == "" {
		return lastcmdItems{false, }
	}
	var  []lastcmdEntry
	 := strings.HasPrefix(, "-")
	for ,  := range  {
		if ( && strings.HasPrefix(.negIndex, )) ||
			(! && strings.HasPrefix(.posIndex, )) {
			 = append(, )
		}
	}
	return lastcmdItems{, }
}

func ( lastcmdItems) ( int) ui.Text {
	 := ""
	 := .entries[]
	if .negFilter {
		 = .negIndex
	} else {
		 = .posIndex
	}
	// NOTE: We now use a hardcoded width of 3 for the index, which will work as
	// long as the command has less than 1000 words (when filter is positive) or
	// 100 words (when filter is negative).
	return ui.T(fmt.Sprintf("%3s %s", , .content))
}

func ( lastcmdItems) () int { return len(.entries) }