package main

import (
	"context"
	"fmt"
	"gitlab.com/ianbruene/kommandant"
	"strings"
	"time"
)

var prompts = map[bool]string{false: "basic> ", true: "readline> "}

// input splice test
type dummy struct {
	Data []byte
}

func (d *dummy) Read(b []byte) (count int, err error) {
	var slicePoint int
	if len(b) > len(d.Data) {
		slicePoint = len(d.Data)
	} else {
		slicePoint = len(b)
	}
	chunk := d.Data[:slicePoint]
	d.Data = d.Data[slicePoint:]
	for i, c := range chunk {
		b[i] = c
	}
	return slicePoint, nil
}

func (d *dummy) Close() (err error) {
	return nil
}
// ==================

type sample struct {
	core *kommandant.Kmdt
}

func (s *sample) DoSplice(lineIn string) (stopOut bool) {
	existingStdin := s.core.GetStdin()
	splice := &dummy{Data:[]byte("quux!\n")}
	s.core.SetStdin(splice)
	s.core.PreCmd(context.TODO(), "reader\n")
	s.core.OneCmd(context.TODO(), "reader\n")
	s.core.PostCmd(context.TODO(), false, "reader\n")
	s.core.SetStdin(existingStdin)
	return false
}

func (s *sample) SetCore(k *kommandant.Kmdt) {
	s.core = k
}

func (s *sample) DoEOF(lineIn string) (stopOut bool) {
	return true
}

func (s *sample) DoQuit(lineIn string) (stopOut bool) {
	fmt.Println("Bye")
	return true
}

func (s *sample) DoPrompt(lineIn string) (stopOut bool) {
	s.core.SetPrompt(lineIn + " ")
	return false
}

func (s *sample) DoFoo(lineIn string) (stopOut bool) {
	s.core.WriteString("The Foodogs of War have slipped!\n" + lineIn + "\n")
	return false
}

func (s *sample) DoReader(lineIn string) (stopOut bool) {
	existingPrompt := s.core.GetPrompt()
	s.core.SetPrompt("> ")
	// read a line
	line, err := s.core.Readline()
	// print the line
	fmt.Println("Reader got:", line)
	if err != nil {
		fmt.Println("Reader error:", err)
	}
	s.core.SetPrompt(existingPrompt)
	return false
}

func (s *sample) DoLoopy(lineIn string) (stopOut bool) {
	for true {
		fmt.Println("Loopy!")
		time.Sleep(100 * time.Millisecond)
	}
	return true
}

func (s *sample) DoReadline(lineIn string) (stopOut bool) {
	// Toggles between readline and basic modes
	enabled := s.core.ReadlineEnabled()
	enabled = !enabled
	fmt.Println("Toggling readline...", enabled)
	err := s.core.EnableReadline(enabled)
	if err != nil {
		fmt.Println(err)
		return true
	}
	s.core.SetPrompt(prompts[enabled])
	return false
}

func (s *sample) DoWould(lineIn string) (stopOut bool) {
	s.core.WriteString(lineIn + "\n")
	return false
}

func (s *sample) CompleteWould(line string) (options []string) {
	myOptions := []string{"you", "kindly"}
	options = []string{}
	pieces := strings.Split(line, " ")
	last := pieces[len(pieces)-1]
	for _, str := range myOptions {
		if strings.HasPrefix(str, last) && (str != last) {
			options = append(options, str)
		}
	}
	if len(options) > 0 {
		return options
	} else {
		return myOptions
	}
}

func (s *sample) HelpFoo() {
	s.core.WriteString("SCHUUUULLLTZ!!!!!!\n")
}

func (s *sample) HelpAnything() {
	s.core.WriteString("This program is a demonstration of Kommandant\n")
}

func (s *sample) DefaultComplete(line string) (options []string) {
	return []string{"quux"}
}

func (s *sample) Default(lineIn string) (stopOut bool) {
	fmt.Println("Custom default! (unrecognized command)", lineIn)
	return false
}

func main() {
	demo := kommandant.NewKommandantDebug(&sample{}, kommandant.NODEBUG)
	demo.SetPrompt(prompts[false])
	// Run
	demo.CmdLoop(context.TODO(), "Kommandant demo program")
}
