package dns

import (
	
	
)

const (
	year68     = 1 << 31 // For RFC1982 (Serial Arithmetic) calculations in 32 bits.
	defaultTtl = 3600    // Default internal TTL.

	// DefaultMsgSize is the standard default for messages larger than 512 bytes.
	DefaultMsgSize = 4096
	// MinMsgSize is the minimal size of a DNS packet.
	MinMsgSize = 512
	// MaxMsgSize is the largest possible DNS packet.
	MaxMsgSize = 65535
)

// Error represents a DNS error.
type Error struct{ err string }

func ( *Error) () string {
	if  == nil {
		return "dns: <nil>"
	}
	return "dns: " + .err
}

// An RR represents a resource record.
type RR interface {
	// Header returns the header of an resource record. The header contains
	// everything up to the rdata.
	Header() *RR_Header
	// String returns the text representation of the resource record.
	String() string

	// copy returns a copy of the RR
	copy() RR

	// len returns the length (in octets) of the compressed or uncompressed RR in wire format.
	//
	// If compression is nil, the uncompressed size will be returned, otherwise the compressed
	// size will be returned and domain names will be added to the map for future compression.
	len(off int, compression map[string]struct{}) int

	// pack packs the records RDATA into wire format. The header will
	// already have been packed into msg.
	pack(msg []byte, off int, compression compressionMap, compress bool) (off1 int, err error)

	// unpack unpacks an RR from wire format.
	//
	// This will only be called on a new and empty RR type with only the header populated. It
	// will only be called if the record's RDATA is non-empty.
	unpack(msg []byte, off int) (off1 int, err error)

	// parse parses an RR from zone file format.
	//
	// This will only be called on a new and empty RR type with only the header populated.
	parse(c *zlexer, origin string) *ParseError

	// isDuplicate returns whether the two RRs are duplicates.
	isDuplicate(r2 RR) bool
}

// RR_Header is the header all DNS resource records share.
type RR_Header struct {
	Name     string `dns:"cdomain-name"`
	Rrtype   uint16
	Class    uint16
	Ttl      uint32
	Rdlength uint16 // Length of data after header.
}

// Header returns itself. This is here to make RR_Header implements the RR interface.
func ( *RR_Header) () *RR_Header { return  }

// Just to implement the RR interface.
func ( *RR_Header) () RR { return nil }

func ( *RR_Header) () string {
	var  string

	if .Rrtype == TypeOPT {
		 = ";"
		// and maybe other things
	}

	 += sprintName(.Name) + "\t"
	 += strconv.FormatInt(int64(.Ttl), 10) + "\t"
	 += Class(.Class).String() + "\t"
	 += Type(.Rrtype).String() + "\t"
	return 
}

func ( *RR_Header) ( int,  map[string]struct{}) int {
	 := domainNameLen(.Name, , , true)
	 += 10 // rrtype(2) + class(2) + ttl(4) + rdlength(2)
	return 
}

func ( *RR_Header) ( []byte,  int,  compressionMap,  bool) ( int,  error) {
	// RR_Header has no RDATA to pack.
	return , nil
}

func ( *RR_Header) ( []byte,  int) (int, error) {
	panic("dns: internal error: unpack should never be called on RR_Header")
}

func ( *RR_Header) ( *zlexer,  string) *ParseError {
	panic("dns: internal error: parse should never be called on RR_Header")
}

// ToRFC3597 converts a known RR to the unknown RR representation from RFC 3597.
func ( *RFC3597) ( RR) error {
	 := make([]byte, Len())
	, ,  := packRR(, , 0, compressionMap{}, false)
	if  != nil {
		return 
	}
	 = [:]

	* = RFC3597{Hdr: *.Header()}
	.Hdr.Rdlength = uint16( - )

	if noRdata(.Hdr) {
		return nil
	}

	_,  = .unpack(, )
	return 
}

// fromRFC3597 converts an unknown RR representation from RFC 3597 to the known RR type.
func ( *RFC3597) ( RR) error {
	 := .Header()
	* = .Hdr

	// Can't overflow uint16 as the length of Rdata is validated in (*RFC3597).parse.
	// We can only get here when rr was constructed with that method.
	.Rdlength = uint16(hex.DecodedLen(len(.Rdata)))

	if noRdata(*) {
		// Dynamic update.
		return nil
	}

	// rr.pack requires an extra allocation and a copy so we just decode Rdata
	// manually, it's simpler anyway.
	,  := hex.DecodeString(.Rdata)
	if  != nil {
		return 
	}

	_,  = .unpack(, 0)
	return 
}