// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package tokenizer

import (
	"log"
	"strconv"
	"unicode"
	"unicode/utf8"
)

// TokenType describes the category a Token belongs to.
type TokenType string

// TokenType values recognized by the lexer.
const (
	TypePound   TokenType = "POUND"   // '#'
	TypeNumber  TokenType = "NUMBER"  // A number
	TypeText    TokenType = "TEXT"    // Catch-all type
	TypeDot     TokenType = "DOT"     // '.'
	TypeNewline TokenType = "NEWLINE" // '\n'
	TypeEOF     TokenType = "EOF"     // Psuedo token to signal the end of input.
	TypeSpace   TokenType = "SPACE"   // A whitespace character
	TypeDash    TokenType = "DASH"    // '-'
)

// Token represents some atomic TAP output string.
type Token struct {
	Type  TokenType
	Value string
}

// Tokenize generates a channel of Tokens read from the given input.
func Tokenize(input []byte) <-chan Token {
	l := &lexer{
		input:  input,
		Tokens: make(chan Token, 1),
	}
	go l.run()
	return l.Tokens
}

// EOFToken is emitted to signal the end of input.
func EOFToken() Token {
	return Token{
		Type:  TypeEOF,
		Value: "",
	}
}

// The rune emitted when the end of input has been reached.
const eof = rune(-1)

// State represents a lexical analysis state. Each state accepts a lexer as input and
// returns the next lexer state. If the output state is nil, lexing stops.
type state func(*lexer) state

// Lexer manages the position of a lexical analysis on some TAP output string.
type lexer struct {
	input  []byte
	start  int
	pos    int
	width  int
	Tokens chan Token
}

func (l *lexer) run() {
	for state := lexAny; state != nil; {
		state = state(l)
	}
	close(l.Tokens)
}

func (l *lexer) emit(t TokenType) {
	l.Tokens <- Token{Type: t, Value: string(l.input[l.start:l.pos])}
	l.start = l.pos
}

func (l *lexer) next() rune {
	if l.pos >= len(l.input) {
		l.width = 0
		return eof
	}

	// Read the next rune, skipping over all invalid utf8 sequences.
	var rn rune
	rn, l.width = utf8.DecodeRune(l.input[l.pos:])
	for rn == utf8.RuneError && l.pos < len(l.input) {
		log.Printf("invalid UTF-8 found at pos %d:\n\n%s", l.pos, string(l.input))
		l.pos++
		rn, l.width = utf8.DecodeRune(l.input[l.pos:])
	}
	l.pos += l.width
	return rn
}

// Returns the current lexeme.
func (l *lexer) lexeme() lexeme {
	if l.pos >= len(l.input) {
		return lexeme(eof)
	}
	return lexeme(l.input[l.pos : l.pos+1][0])
}

// LexAny is the lexer start state. It's job is to put the lexer into the proper state
// according to the next input rune. Other states should return to this state after
// emitting their lexemes. They should also not consume runes using l.next() immediately
// before entering this state.
func lexAny(l *lexer) state {
	lxm := l.lexeme()
	if lxm.isEOF() {
		l.emit(TypeEOF)
		return nil
	}

	l.start = l.pos

	switch {
	case lxm.isDash():
		l.next()
		l.emit(TypeDash)
		return lexAny
	case lxm.isNewline():
		l.next()
		l.emit(TypeNewline)
		return lexAny
	case lxm.isDot():
		l.next()
		l.emit(TypeDot)
		return lexAny
	case lxm.isPound():
		l.next()
		l.emit(TypePound)
		return lexAny
	case lxm.isSpace():
		return lexSpace
	case lxm.isDigit():
		return lexNumber
	}

	return lexText
}

func lexSpace(l *lexer) state {
	return lexUntil(l, TypeSpace, func(lxm lexeme) bool { return !lxm.isSpace() })
}

func lexNumber(l *lexer) state {
	return lexUntil(l, TypeNumber, func(lxm lexeme) bool { return !lxm.isDigit() })
}

func lexText(l *lexer) state {
	return lexUntil(l, TypeText, func(lxm lexeme) bool { return lxm.isNonText() })
}

// LexUntil consumes all runes into a token of the given type while `stop` is false.
// Returns lexAny when complete or nil if the end of input was reached.
func lexUntil(l *lexer, typ TokenType, stop func(lexeme) bool) state {
	for {
		lxm := l.lexeme()
		if lxm.isEOF() || stop(lxm) {
			l.emit(typ)
			return lexAny
		}
		if l.next() == eof {
			break
		}
	}
	// Reached EOF
	if l.pos > l.start {
		l.emit(typ)
	}
	l.emit(TypeEOF)
	return nil
}

type lexeme rune

func (l lexeme) isSpace() bool {
	return l != '\n' && unicode.IsSpace(rune(l))
}

func (l lexeme) isNewline() bool {
	return l == '\n'
}

func (l lexeme) isDigit() bool {
	_, err := strconv.Atoi(string(l))
	return err == nil
}

func (l lexeme) isDot() bool {
	return l == '.'
}

func (l lexeme) isDash() bool {
	return l == '-'
}

func (l lexeme) isPound() bool {
	return l == '#'
}

func (l lexeme) isEOF() bool {
	return rune(l) == eof
}

func (l lexeme) isNonText() bool {
	return l.isEOF() || l.isSpace() || l.isNewline() || l.isDigit() || l.isDot() || l.isPound() || l.isDash()
}
