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

package org.xbill.DNS;

import java.io.IOException;
import java.security.NoSuchAlgorithmException;

import org.xbill.DNS.utils.base16;

/**
 * Next SECure name 3 Parameters - this record contains the parameters (hash
 * algorithm, salt, iterations) used for a valid, complete NSEC3 chain present
 * in a zone. Zones signed using NSEC3 must include this record at the zone apex
 * to inform authoritative servers that NSEC3 is being used with the given
 * parameters.
 *
 * @author Brian Wellington
 * @author David Blacka
 */

public class NSEC3PARAMRecord extends Record {

    private static final long serialVersionUID = -8689038598776316533L;

    private int hashAlg;
    private int flags;
    private int iterations;
    private byte salt[];

    NSEC3PARAMRecord() {
    }

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

    /**
     * Creates an NSEC3PARAM record from the given data.
     *
     * @param name       The ownername of the NSEC3PARAM record (generally the zone name).
     * @param dclass     The class.
     * @param ttl        The TTL.
     * @param hashAlg    The hash algorithm.
     * @param flags      The value of the flags field.
     * @param iterations The number of hash iterations.
     * @param salt       The salt to use (may be null).
     */
    public NSEC3PARAMRecord(Name name, int dclass, long ttl, int hashAlg,
                            int flags, int iterations, byte[] salt) {
        super(name, Type.NSEC3PARAM, dclass, ttl);
        this.hashAlg = checkU8("hashAlg", hashAlg);
        this.flags = checkU8("flags", flags);
        this.iterations = checkU16("iterations", iterations);

        if (salt != null) {
            if (salt.length > 255)
                throw new IllegalArgumentException("Invalid salt " +
                        "length");
            if (salt.length > 0) {
                this.salt = new byte[salt.length];
                System.arraycopy(salt, 0, this.salt, 0, salt.length);
            }
        }
    }

    void
    rrFromWire(DNSInput in) throws IOException {
        hashAlg = in.readU8();
        flags = in.readU8();
        iterations = in.readU16();

        int salt_length = in.readU8();
        if (salt_length > 0)
            salt = in.readByteArray(salt_length);
        else
            salt = null;
    }

    void
    rrToWire(DNSOutput out, Compression c, boolean canonical) {
        out.writeU8(hashAlg);
        out.writeU8(flags);
        out.writeU16(iterations);

        if (salt != null) {
            out.writeU8(salt.length);
            out.writeByteArray(salt);
        } else
            out.writeU8(0);
    }

    void
    rdataFromString(Tokenizer st, Name origin) throws IOException {
        hashAlg = st.getUInt8();
        flags = st.getUInt8();
        iterations = st.getUInt16();

        String s = st.getString();
        if (s.equals("-"))
            salt = null;
        else {
            st.unget();
            salt = st.getHexString();
            if (salt.length > 255)
                throw st.exception("salt value too long");
        }
    }

    /**
     * Converts rdata to a String
     */
    String
    rrToString() {
        StringBuffer sb = new StringBuffer();
        sb.append(hashAlg);
        sb.append(' ');
        sb.append(flags);
        sb.append(' ');
        sb.append(iterations);
        sb.append(' ');
        if (salt == null)
            sb.append('-');
        else
            sb.append(base16.toString(salt));

        return sb.toString();
    }

    /**
     * Returns the hash algorithm
     */
    public int
    getHashAlgorithm() {
        return hashAlg;
    }

    /**
     * Returns the flags
     */
    public int
    getFlags() {
        return flags;
    }

    /**
     * Returns the number of iterations
     */
    public int
    getIterations() {
        return iterations;
    }

    /**
     * Returns the salt
     */
    public byte[]
    getSalt() {
        return salt;
    }

    /**
     * Hashes a name with the parameters of this NSEC3PARAM record.
     *
     * @param name The name to hash
     * @return The hashed version of the name
     * @throws NoSuchAlgorithmException The hash algorithm is unknown.
     */
    public byte[]
    hashName(Name name) throws NoSuchAlgorithmException {
        return NSEC3Record.hashName(name, hashAlg, iterations, salt);
    }

}
