// Copyright 1997 The Open Group Research Institute.  All rights reserved.

package krb5.lib;

import krb5.lib.asn1.*;

/**
 * AP Request
 */
public class APReq {

	/**
	 * Version
	 */
	public int pvno;

	/**
	 * Message type
	 */
	public int msgType;

	/**
	 * AP options
	 */
	public APOptions apOptions;

	/**
	 * Ticket
	 */
	public Ticket ticket;

	/**
	 * Authenticator
	 */
	public EncryptedData authenticator;

	/**
	 * Class constructor
	 *
	 * @param new_apOptions is of type APOptions
	 * @param new_ticket is of type Ticket
	 * @param new_authenticator is of type EncryptedData
	 * @see krb5.lib.APOptions
	 * @see krb5.lib.Ticket
	 * @see krb5.lib.EncryptedData
	 */
	public APReq(
		APOptions new_apOptions,
		Ticket new_ticket,
		EncryptedData new_authenticator
	) {
		pvno = Krb5.PVNO;
		msgType = Krb5.KRB_AP_REQ;
		apOptions = new_apOptions;
		ticket = new_ticket;
		authenticator = new_authenticator;
	}

	/**
	 * Class constructor
	 *
	 * @param data is of type byte[]
	 * @exception Asn1Exception an exception
	 * @exception BitStringException an exception
	 * @exception RealmException an exception
	 * @exception KrbApErrException an exception
	 * @see krb5.lib.Asn1Exception
	 * @see krb5.lib.BitStringException
	 * @see krb5.lib.RealmException
	 * @see krb5.lib.KrbApErrException
	 */
	public APReq(byte[] data) throws Asn1Exception,
		BitStringException, RealmException, KrbApErrException {
		this(new EncodeRef(data));
	}

	/**
	 * Class constructor
	 *
	 * @param ref is of type EncodeRef
	 * @exception Asn1Exception an exception
	 * @exception BitStringException an exception
	 * @exception RealmException an exception
	 * @exception KrbApErrException an exception
	 * @see krb5.lib.asn1.EncodeRef
	 * @see krb5.lib.Asn1Exception
	 * @see krb5.lib.BitStringException
	 * @see krb5.lib.RealmException
	 * @see krb5.lib.KrbApErrException
	 */
	public APReq(EncodeRef ref) throws Asn1Exception,
		BitStringException, RealmException, KrbApErrException {
		if (decode.TagApp(ref) != Krb5.KRB_AP_REQ)
			throw new Asn1Exception(Krb5.ASN1_BAD_ID);
		EncodeRef subRef = decode.Sequence(ref.startOfData());

		if (decode.Tag(subRef) == 0) {
			pvno = decode.Integer(subRef.startOfData());
			if (pvno != Krb5.PVNO)
				throw new KrbApErrException(Krb5.KRB_AP_ERR_BADVERSION);
			subRef.next();
		}
		else
			throw new Asn1Exception(Krb5.ASN1_BAD_ID);

		if (decode.Tag(subRef) == 1) {
			msgType = decode.Integer(subRef.startOfData());
			if (msgType != Krb5.KRB_AP_REQ)
				throw new KrbApErrException(Krb5.KRB_AP_ERR_MSG_TYPE);
			subRef.next();
		}
		else
			throw new Asn1Exception(Krb5.ASN1_BAD_ID);

		if (decode.Tag(subRef) == 2) {
			apOptions = new APOptions(subRef.startOfData());
			subRef.next();
		}
		else
			throw new Asn1Exception(Krb5.ASN1_BAD_ID);

		if (decode.Tag(subRef) == 3) {
			ticket = new Ticket(subRef.startOfData());
			subRef.next();
		}
		else
			throw new Asn1Exception(Krb5.ASN1_BAD_ID);

		if (decode.Tag(subRef) == 4) {
			authenticator = new EncryptedData(subRef.startOfData());
			subRef.next();
		}
		else
			throw new Asn1Exception(Krb5.ASN1_BAD_ID);

		if (subRef.isMoreInSequence())
			throw new Asn1Exception(Krb5.ASN1_BAD_ID);
	}

	/**
	 * Encodes the object in asn1
	 *
	 * @return byte[] is a result
	 * @exception Asn1Exception an exception
	 * @exception BitStringException an exception
	 * @see krb5.lib.Asn1Exception
	 * @see krb5.lib.BitStringException
	 */
	public byte[] asn1Encode() throws Asn1Exception,
		BitStringException {
		byte[][] ap_req = {
			encode.prependExplicitTag(0, encode.Integer(pvno)),
			encode.prependExplicitTag(1, encode.Integer(msgType)),
			encode.prependExplicitTag(2, apOptions.asn1Encode()),
			encode.prependExplicitTag(3, ticket.asn1Encode()),
			encode.prependExplicitTag(4, authenticator.asn1Encode())
		};
		return encode.prependExplicitTag(asn1Class.APPLICATION,
			msgType, encode.Sequence(ap_req));
	}

}