// TOML Parser.

package toml

import (
	"fmt"
	"reflect"
	"strconv"
	"time"
)

type parser struct {
	flow         chan token
	tree         *TomlTree
	tokensBuffer []token
	currentGroup string
}

type parserStateFn func(*parser) parserStateFn

func (p *parser) run() {
	for state := parseStart; state != nil; {
		state = state(p)
	}
}

func (p *parser) peek() *token {
	if len(p.tokensBuffer) != 0 {
		return &(p.tokensBuffer[0])
	}

	tok, ok := <-p.flow
	if !ok {
		return nil
	}
	p.tokensBuffer = append(p.tokensBuffer, tok)
	return &tok
}

func (p *parser) assume(typ tokenType) {
	tok := p.getToken()
	if tok == nil {
		panic(fmt.Sprintf("was expecting token %s, but token stream is empty", typ))
	}
	if tok.typ != typ {
		panic(fmt.Sprintf("was expecting token %s, but got %s", typ, tok.typ))
	}
}

func (p *parser) getToken() *token {
	if len(p.tokensBuffer) != 0 {
		tok := p.tokensBuffer[0]
		p.tokensBuffer = p.tokensBuffer[1:]
		return &tok
	}
	tok, ok := <-p.flow
	if !ok {
		return nil
	}
	return &tok
}

func parseStart(p *parser) parserStateFn {
	tok := p.peek()

	// end of stream, parsing is finished
	if tok == nil {
		return nil
	}

	switch tok.typ {
	case tokenLeftBracket:
		return parseGroup
	case tokenKey:
		return parseAssign
	case tokenEOF:
		return nil
	default:
		panic("unexpected token")
	}
	return nil
}

func parseGroup(p *parser) parserStateFn {
	p.getToken() // discard the [
	key := p.getToken()
	if key.typ != tokenKeyGroup {
		panic(fmt.Sprintf("unexpected token %s, was expecting a key group", key))
	}
	if p.tree.Has(key.val) {
		panic("duplicated tables")
	}
	p.tree.createSubTree(key.val)
	p.assume(tokenRightBracket)
	p.currentGroup = key.val
	return parseStart(p)
}

func parseAssign(p *parser) parserStateFn {
	key := p.getToken()
	p.assume(tokenEqual)
	value := parseRvalue(p)
	final_key := key.val
	if p.currentGroup != "" {
		final_key = p.currentGroup + "." + key.val
	}
	if p.tree.Get(final_key) != nil {
		panic(fmt.Sprintf("the following key was defined twice: %s", final_key))
	}
	p.tree.Set(final_key, value)
	return parseStart(p)
}

func parseRvalue(p *parser) interface{} {
	tok := p.getToken()
	if tok == nil || tok.typ == tokenEOF {
		panic("expecting a value")
	}

	switch tok.typ {
	case tokenString:
		return tok.val
	case tokenTrue:
		return true
	case tokenFalse:
		return false
	case tokenInteger:
		val, err := strconv.ParseInt(tok.val, 10, 64)
		if err != nil {
			panic(err)
		}
		return val
	case tokenFloat:
		val, err := strconv.ParseFloat(tok.val, 64)
		if err != nil {
			panic(err)
		}
		return val
	case tokenDate:
		val, err := time.Parse(time.RFC3339, tok.val)
		if err != nil {
			panic(err)
		}
		return val
	case tokenLeftBracket:
		return parseArray(p)
	case tokenError:
		panic(tok.val)
	}

	panic("never reached")

	return nil
}

func parseArray(p *parser) []interface{} {
	array := make([]interface{}, 0)
	arrayType := reflect.TypeOf(nil)
	for {
		follow := p.peek()
		if follow == nil || follow.typ == tokenEOF {
			panic("unterminated array")
		}
		if follow.typ == tokenRightBracket {
			p.getToken()
			return array
		}
		val := parseRvalue(p)
		if arrayType == nil {
			arrayType = reflect.TypeOf(val)
		}
		if reflect.TypeOf(val) != arrayType {
			panic("mixed types in array")
		}
		array = append(array, val)
		follow = p.peek()
		if follow == nil {
			panic("unterminated array")
		}
		if follow.typ != tokenRightBracket && follow.typ != tokenComma {
			fmt.Println(follow.typ)
			fmt.Println(follow.val)
			panic("missing comma")
		}
		if follow.typ == tokenComma {
			p.getToken()
		}
	}
	return array
}

func parse(flow chan token) *TomlTree {
	result := make(TomlTree)
	parser := &parser{
		flow:         flow,
		tree:         &result,
		tokensBuffer: make([]token, 0),
		currentGroup: "",
	}
	parser.run()
	return parser.tree
}
