// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)

package org.xbill.DNS;

import java.io.*;
import java.util.*;
import org.xbill.DNS.utils.*;

/**
 * Options - describes Extended DNS (EDNS) properties of a Message.
 * No specific options are defined other than those specified in the
 * header.  An OPT should be generated by Resolver.
 *
 * EDNS is a method to extend the DNS protocol while providing backwards
 * compatibility and not significantly changing the protocol.  This
 * implementation of EDNS is mostly complete at level 0.
 *
 * @see Message
 * @see Resolver 
 *
 * @author Brian Wellington
 */

public class OPTRecord extends Record {

public static class Option {
	public final int code;
	public final byte [] data;

	/**
	 * Creates an option with the given option code and data.
	 */
	public
	Option(int code, byte [] data) {
		this.code = checkU8("option code", code);
		this.data = data;
	}

	public String
	toString() {
		return "{" + code + " <" + base16.toString(data) + ">}";
	}
}

private List options;
private static List emptyList = Collections.unmodifiableList(new ArrayList());

OPTRecord() {}

Record
getObject() {
	return new OPTRecord();
}

/**
 * Creates an OPT Record.  This is normally called by SimpleResolver, but can
 * also be called by a server.
 * @param payloadSize The size of a packet that can be reassembled on the 
 * sending host.
 * @param xrcode The value of the extended rcode field.  This is the upper
 * 16 bits of the full rcode.
 * @param flags Additional message flags.
 * @param version The EDNS version that this DNS implementation supports.
 * This should be 0 for dnsjava.
 * @param options The list of options that comprise the data field.  There
 * are currently no defined options.
 * @see ExtendedFlags
 */
public
OPTRecord(int payloadSize, int xrcode, int version, int flags, List options) {
	super(Name.root, Type.OPT, payloadSize, 0);
	checkU16("payloadSize", payloadSize);
	checkU8("xrcode", xrcode);
	checkU8("version", version);
	checkU16("flags", flags);
	ttl = ((long)xrcode << 24) + ((long)version << 16) + flags;
	if (options != null) {
		this.options = new ArrayList(options);
	}
}

/**
 * Creates an OPT Record with no data.  This is normally called by
 * SimpleResolver, but can also be called by a server.
 * @param payloadSize The size of a packet that can be reassembled on the 
 * sending host.
 * @param xrcode The value of the extended rcode field.  This is the upper
 * 16 bits of the full rcode.
 * @param flags Additional message flags.
 * @param version The EDNS version that this DNS implementation supports.
 * This should be 0 for dnsjava.
 * @see ExtendedFlags
 */
public
OPTRecord(int payloadSize, int xrcode, int version, int flags) {
	this(payloadSize, xrcode, version, flags, null);
}

/**
 * Creates an OPT Record with no data.  This is normally called by
 * SimpleResolver, but can also be called by a server.
 */
public
OPTRecord(int payloadSize, int xrcode, int version) {
	this(payloadSize, xrcode, version, 0, null);
}

void
rrFromWire(DNSInput in) throws IOException {
	if (in.remaining() > 0)
		options = new ArrayList();
	while (in.remaining() > 0) {
		int code = in.readU16();
		int len = in.readU16();
		byte [] data = in.readByteArray(len);
		options.add(new Option(code, data));
	}
}

void
rdataFromString(Tokenizer st, Name origin) throws IOException {
	throw st.exception("no text format defined for OPT");
}

/** Converts rdata to a String */
String
rrToString() {
	StringBuffer sb = new StringBuffer();
	if (options != null) {
		sb.append(options);
		sb.append(" ");
	}
	sb.append(" ; payload ");
	sb.append(getPayloadSize());
	sb.append(", xrcode ");
	sb.append(getExtendedRcode());
	sb.append(", version ");
	sb.append(getVersion());
	sb.append(", flags ");
	sb.append(getFlags());
	return sb.toString();
}

/** Returns the maximum allowed payload size. */
public int
getPayloadSize() {
	return dclass;
}

/**
 * Returns the extended Rcode
 * @see Rcode
 */
public int
getExtendedRcode() {
	return (int)(ttl >>> 24);
}

/** Returns the highest supported EDNS version */
public int
getVersion() {
	return (int)((ttl >>> 16) & 0xFF);
}

/** Returns the EDNS flags */
public int
getFlags() {
	return (int)(ttl & 0xFFFF);
}

void
rrToWire(DNSOutput out, Compression c, boolean canonical) {
	if (options == null)
		return;
	Iterator it = options.iterator();
	while (it.hasNext()) {
		Option opt = (Option) it.next();
		out.writeU16(opt.code);
		out.writeU16(opt.data.length);
		out.writeByteArray(opt.data);
	}
}

/**
 * Gets all options in the OPTRecord.  This returns a list of Options.
 */
public List
getOptions() {
	if (options == null)
		return emptyList;
	return Collections.unmodifiableList(options);
}

/**
 * Gets all options in the OPTRecord with a specific code.  This returns a
 * list of byte arrays.
 */
public List
getOptions(int code) {
	if (options == null)
		return emptyList;
	List list = null;
	for (Iterator it = options.iterator(); it.hasNext(); ) {
		Option opt = (Option) it.next();
		if (opt.code == code) {
			if (list == null)
				list = new ArrayList();
			list.add(opt.data);
		}
	}
	if (list == null)
		list = emptyList;
	return list;
}

}

@@ -1040,87 +1040,8 @@
 ons;
-%0Aprivate static List emptyList = Collections.unmodifiableList(new ArrayList());
 %0A%0AOP
@@ -4589,25 +4589,38 @@
 %09return 
-emptyList
+Collections.EMPTY_LIST
 ;%0A%09retur
@@ -4836,25 +4836,38 @@
 %09return 
-emptyList
+Collections.EMPTY_LIST
 ;%0A%09List 
@@ -5102,24 +5102,37 @@
 )%0A%09%09
-list = emptyList
+return Collections.EMPTY_LIST
 ;%0A%09r

Use Collections.EMPTY_LIST.