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

package org.xbill.DNS;

import java.io.*;
import java.util.*;

/**
 * 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.
 * <p/>
 * 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.
 *
 * @author Brian Wellington
 * @see Message
 * @see Resolver
 */

public class OPTRecord extends Record {

    private static final long serialVersionUID = -6254521894809367938L;

    private List options;

    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) {
            EDNSOption option = EDNSOption.fromWire(in);
            options.add(option);
        }
    }

    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()) {
            EDNSOption option = (EDNSOption) it.next();
            option.toWire(out);
        }
    }

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

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

}
