package vsphere

import (
	"log"
	"sync"
	"time"
)

// TSCache is a cache of timestamps used to determine the validity of datapoints
type TSCache struct {
	ttl   time.Duration
	table map[string]time.Time
	mux   sync.RWMutex
}

// NewTSCache creates a new TSCache with a specified time-to-live after which timestamps are discarded.
func NewTSCache(ttl time.Duration) *TSCache {
	return &TSCache{
		ttl:   ttl,
		table: make(map[string]time.Time),
	}
}

// Purge removes timestamps that are older than the time-to-live
func (t *TSCache) Purge() {
	t.mux.Lock()
	defer t.mux.Unlock()
	n := 0
	for k, v := range t.table {
		if time.Now().Sub(v) > t.ttl {
			delete(t.table, k)
			n++
		}
	}
	log.Printf("D! [inputs.vsphere] purged timestamp cache. %d deleted with %d remaining", n, len(t.table))
}

// IsNew returns true if the supplied timestamp for the supplied key is more recent than the
// timestamp we have on record.
func (t *TSCache) IsNew(key string, metricName string, tm time.Time) bool {
	t.mux.RLock()
	defer t.mux.RUnlock()
	v, ok := t.table[makeKey(key, metricName)]
	if !ok {
		return true // We've never seen this before, so consider everything a new sample
	}
	return !tm.Before(v)
}

// Get returns a timestamp (if present)
func (t *TSCache) Get(key string, metricName string) (time.Time, bool) {
	t.mux.RLock()
	defer t.mux.RUnlock()
	ts, ok := t.table[makeKey(key, metricName)]
	return ts, ok
}

// Put updates the latest timestamp for the supplied key.
func (t *TSCache) Put(key string, metricName string, time time.Time) {
	t.mux.Lock()
	defer t.mux.Unlock()
	t.table[makeKey(key, metricName)] = time
}

func makeKey(resource string, metric string) string {
	return resource + "|" + metric
}
