package file

// TODO(miek): the zone's implementation is basically non-existent
// we return a list and when searching for an answer we iterate
// over the list. This must be moved to a tree-like structure and
// have some fluff for DNSSEC (and be memory efficient).

import (
	"strings"

	"golang.org/x/net/context"

	"github.com/miekg/coredns/middleware"
	"github.com/miekg/dns"
)

type (
	File struct {
		Next  middleware.Handler
		Zones Zones
		// Maybe a list of all zones as well, as a []string?
	}

	Zone  []dns.RR
	Zones struct {
		Z     map[string]Zone // utterly braindead impl. TODO(miek): fix
		Names []string
	}
)

func (f File) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) {
	state := middleware.State{W: w, Req: r}
	qname := state.Name()
	zone := middleware.Zones(f.Zones.Names).Matches(qname)
	if zone == "" {
		return f.Next.ServeDNS(ctx, w, r)
	}

	names, nodata := f.Zones.Z[zone].lookup(qname, state.QType())
	var answer *dns.Msg
	switch {
	case nodata:
		answer = state.AnswerMessage()
		answer.Ns = names
	case len(names) == 0:
		answer = state.AnswerMessage()
		answer.Ns = names
		answer.Rcode = dns.RcodeNameError
	case len(names) > 0:
		answer = state.AnswerMessage()
		answer.Answer = names
	default:
		answer = state.ErrorMessage(dns.RcodeServerFailure)
	}
	// Check return size, etc. TODO(miek)
	w.WriteMsg(answer)
	return 0, nil
}

// Lookup will try to find qname and qtype in z. It returns the
// records found *or* a boolean saying NODATA. If the answer
// is NODATA then the RR returned is the SOA record.
//
// TODO(miek): EXTREMELY STUPID IMPLEMENTATION.
// Doesn't do much, no delegation, no cname, nothing really, etc.
// TODO(miek): even NODATA looks broken
func (z Zone) lookup(qname string, qtype uint16) ([]dns.RR, bool) {
	var (
		nodata bool
		rep    []dns.RR
		soa    dns.RR
	)

	for _, rr := range z {
		if rr.Header().Rrtype == dns.TypeSOA {
			soa = rr
		}
		// Match function in Go DNS?
		if strings.ToLower(rr.Header().Name) == qname {
			if rr.Header().Rrtype == qtype {
				rep = append(rep, rr)
				nodata = false
			}

		}
	}
	if nodata {
		return []dns.RR{soa}, true
	}
	return rep, false
}