package xsql

import "fmt"

var Language = &ParseTree{}

type ParseTree struct {
	Handlers map[Token]func(*Parser) (Statement, error)
	Tokens   map[Token]*ParseTree
	Keys     []string
}

func (t *ParseTree) Handle(tok Token, fn func(*Parser) (Statement, error)) {
	// Verify that there is no conflict for this token in this parse tree.
	if _, conflict := t.Tokens[tok]; conflict {
		panic(fmt.Sprintf("conflict for token %s", tok))
	}

	if _, conflict := t.Handlers[tok]; conflict {
		panic(fmt.Sprintf("conflict for token %s", tok))
	}

	if t.Handlers == nil {
		t.Handlers = make(map[Token]func(*Parser) (Statement, error))
	}
	t.Handlers[tok] = fn
	t.Keys = append(t.Keys, tok.String())
}

func (pt *ParseTree) Parse(p *Parser) (Statement, error) {
	tok, _ := p.scanIgnoreWhitespace()
	p.unscan()
	if f, ok := pt.Handlers[tok]; ok {
		return f(p)
	}
	return nil, nil
}

func init() {
	Language.Handle(SELECT, func(p *Parser) (Statement, error) {
		return p.Parse()
	})

	Language.Handle(CREATE, func(p *Parser) (statement Statement, e error) {
		return p.ParseCreateStreamStmt()
	})

	Language.Handle(SHOW, func(p *Parser) (statement Statement, e error) {
		return p.parseShowStreamsStmt()
	})

	Language.Handle(EXPLAIN, func(p *Parser) (statement Statement, e error) {
		return p.parseExplainStreamsStmt()
	})

	Language.Handle(DESCRIBE, func(p *Parser) (statement Statement, e error) {
		return p.parseDescribeStreamStmt()
	})

	Language.Handle(DROP, func(p *Parser) (statement Statement, e error) {
		return p.parseDropStreamsStmt()
	})
}
