package pgtables

import (
	"sync"

	"code.justin.tv/release/trace/pgparse"
)

var Cache = newCache(10000)

type cacheEntry struct {
	ready  chan struct{}
	tables []string
	err    error
}

type cache struct {
	mu      sync.Mutex
	entries map[string]*cacheEntry
	order   chan string
}

func newCache(size int) *cache {
	return &cache{
		entries: make(map[string]*cacheEntry, size),
		order:   make(chan string, size),
	}
}

func (c *cache) Tables(sql string) ([]string, error) {
	c.mu.Lock()

	ce, ok := c.entries[sql]
	if ok {
		c.mu.Unlock()
		<-ce.ready
		return ce.tables, ce.err
	}

	ce = &cacheEntry{
		ready: make(chan struct{}),
	}
	c.entries[sql] = ce

	if len(c.order) == cap(c.order) {
		remove := sql
		if len(c.order) > 0 {
			remove = <-c.order
		}
		delete(c.entries, remove)
	}

	c.mu.Unlock()

	stmt, err := pgparse.Parse(sql)
	if err != nil {
		ce.err = err
		close(ce.ready)
		return ce.tables, ce.err
	}

	tr := newStatementTracker()
	tr.loadStmt(stmt)

	ce.tables, ce.err = tr.Tables(), tr.Err()
	close(ce.ready)
	return ce.tables, ce.err
}
