package wavefront

import (
	"bufio"
	"io"
)

// Lexical Point Scanner
type PointScanner struct {
	r *bufio.Reader
}

func NewScanner(r io.Reader) *PointScanner {
	return &PointScanner{r: bufio.NewReader(r)}
}

// read reads the next rune from the buffered reader.
// Returns rune(0) if an error occurs (or io.EOF is returned).
func (s *PointScanner) read() rune {
	ch, _, err := s.r.ReadRune()
	if err != nil {
		return eof
	}
	return ch
}

// unread places the previously read rune back on the reader.
func (s *PointScanner) unread() {
	_ = s.r.UnreadRune()
}

// Scan returns the next token and literal value.
func (s *PointScanner) Scan() (Token, string) {

	// Read the next rune
	ch := s.read()
	if isWhitespace(ch) {
		return WS, string(ch)
	} else if isLetter(ch) {
		return LETTER, string(ch)
	} else if isNumber(ch) {
		return NUMBER, string(ch)
	} else if isDelta(ch) {
		return DELTA, string(ch)
	}

	// Otherwise read the individual character.
	switch ch {
	case eof:
		return EOF, ""
	case '\n':
		return NEWLINE, string(ch)
	case '.':
		return DOT, string(ch)
	case '-':
		return MINUS_SIGN, string(ch)
	case '_':
		return UNDERSCORE, string(ch)
	case '/':
		return SLASH, string(ch)
	case '\\':
		return BACKSLASH, string(ch)
	case ',':
		return COMMA, string(ch)
	case '"':
		return QUOTES, string(ch)
	case '=':
		return EQUALS, string(ch)
	}
	return ILLEGAL, string(ch)
}