package dnsresolver

import (
	"encoding/json"
	"io/ioutil"
	"net"

	"github.com/pkg/errors"
)

// This file includes all the DNS Resolvers used by package spf.

// DnsResolver looks up txt strings associated with a FQDN.
type DnsResolver interface {
	GetTxt(string) ([]string, error) // Given a DNS label, return the TXT values records.
}

// The "Live DNS" Resolver:

type dnsLive struct {
	filename string
	cache    dnsCache
}

func NewResolverLive(filename string) *dnsLive {
	// Does live DNS lookups. Records them. Writes file on Close.
	c := &dnsLive{filename: filename}
	c.cache = dnsCache{}
	return c
}

func (c *dnsLive) GetTxt(label string) ([]string, error) {
	// Try the cache.
	txts, ok := c.cache.get(label, "txt")
	if ok {
		return txts, nil
	}

	// Populate the cache:
	t, err := net.LookupTXT(label)
	if err == nil {
		c.cache.put(label, "txt", t)
	}

	return t, err
}

func (c *dnsLive) Close() {
	// Write out and close the file.
	m, _ := json.MarshalIndent(c.cache, "", "  ")
	m = append(m, "\n"...)
	ioutil.WriteFile(c.filename, m, 0666)
}

// The "Pre-Cached DNS" Resolver:

type dnsPreloaded struct {
	cache dnsCache
}

func NewResolverPreloaded(filename string) (*dnsPreloaded, error) {
	c := &dnsPreloaded{}
	c.cache = dnsCache{}
	j, err := ioutil.ReadFile(filename)
	if err != nil {
		return nil, err
	}
	err = json.Unmarshal(j, &(*c).cache)
	return c, err
}

func (c *dnsPreloaded) DumpCache() dnsCache {
	return c.cache
}

func (c *dnsPreloaded) GetTxt(label string) ([]string, error) {
	// Try the cache.
	txts, ok := c.cache.get(label, "txt")
	if ok {
		return txts, nil
	}
	return nil, errors.Errorf("No preloaded DNS entry for: %#v", label)
}
