// Copyright 1997 The Open Group Research Institute.  All rights reserved.

package krb5.lib;

import krb5.lib.asn1.*;

/**
 * Kerberos Ticket
 */
public class Ticket implements Cloneable {
    
	/**
	 * Ticket version
	 */
	public int tkt_vno;
	
	/**
	 * Realm
	 * @see krb5.lib.Realm
	 */
	public Realm realm;
	
	/**
	 * Server Name
	 * @see krb5.lib.PrincipalName
	 */
	public PrincipalName sname;
	
	/** 
	 * Encrypted data
	 * @see krb5.lib.EncryptedData
	 */
	public EncryptedData encPart;

	/**
	 * Class constructor
	 */
	private Ticket() {
	}

	/**
	 * Clones a copy of the object
	 *
	 * @return Object is a result
	 * @see java.lang.Object
	 */
	public Object clone() {
		Ticket new_ticket = new Ticket();
		new_ticket.tkt_vno = tkt_vno;
		new_ticket.realm = (Realm)realm.clone();
		new_ticket.sname = (PrincipalName)sname.clone();
		new_ticket.encPart = (EncryptedData)encPart.clone();
		return new_ticket;
	}

	/**
	 * Class constructor
	 *
	 * @param new_realm is of type Realm
	 * @param new_sname is of type PrincipalName
	 * @param new_encPart is of type EncryptedData
	 * @see krb5.lib.Realm
	 * @see krb5.lib.PrincipalName
	 * @see krb5.lib.EncryptedData
	 */
	public Ticket(
		Realm new_realm,
		PrincipalName new_sname,
		EncryptedData new_encPart
	) {
		tkt_vno = Krb5.TICKET_VNO;
		realm = new_realm;
		sname = new_sname;
		encPart = new_encPart;
	}

	/**
	 * Class constructor
	 *
	 * @param data is of type byte[]
	 * @exception Asn1Exception an exception
	 * @exception RealmException an exception
	 * @exception KrbApErrException an exception
	 * @see krb5.lib.Realm
	 * @see krb5.lib.Asn1Exception
	 * @see krb5.lib.RealmException
	 * @see krb5.lib.KrbApErrException
	 */
	public Ticket(byte[] data) throws Asn1Exception,
		RealmException, KrbApErrException {
		this(new EncodeRef(data));
	}

	/**
	 * Class constructor specifying encoding reference
	 *
	 * @param ref is of type EncodeRef
	 * @exception Asn1Exception an exception
	 * @exception RealmException an exception
	 * @exception KrbApErrException an exception
	 * @see krb5.lib.asn1.EncodeRef
	 * @see krb5.lib.Realm
	 * @see krb5.lib.RealmException
	 * @see krb5.lib.KrbApErrException
	 */
	public Ticket(EncodeRef ref) throws Asn1Exception,
		RealmException, KrbApErrException {
		if (decode.TagApp(ref) != Krb5.KRB_TKT)
			throw new Asn1Exception(Krb5.ASN1_BAD_ID);
		EncodeRef subRef = decode.Sequence(ref.startOfData());
		if (decode.Tag(subRef) == 0) {
			tkt_vno = decode.Integer(subRef.startOfData());
			if (tkt_vno != Krb5.TICKET_VNO)
				throw new KrbApErrException(Krb5.KRB_AP_ERR_BADVERSION);
			subRef.next();
		}
		else
			throw new Asn1Exception(Krb5.ASN1_BAD_ID);
		if (decode.Tag(subRef) == 1) {
			realm = new Realm(subRef.startOfData());
			subRef.next();
		}
		else
			throw new Asn1Exception(Krb5.ASN1_BAD_ID);
		if (decode.Tag(subRef) == 2) {
			sname = new PrincipalName(subRef.startOfData());
			subRef.next();
		}
		else
			throw new Asn1Exception(Krb5.ASN1_BAD_ID);
		if (decode.Tag(subRef) == 3) {
			encPart = 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
	 * @see krb5.lib.Asn1Exception
	 */
	public byte[] asn1Encode() throws Asn1Exception {
		byte[][] ticket = {
			encode.prependExplicitTag(0, encode.Integer(tkt_vno)),
			encode.prependExplicitTag(1, realm.asn1Encode()),
			encode.prependExplicitTag(2, sname.asn1Encode()),
			encode.prependExplicitTag(3, encPart.asn1Encode())
		};
		return encode.prependExplicitTag(asn1Class.APPLICATION,
			Krb5.KRB_TKT, encode.Sequence(ticket));
	}

}
