package proof;

import sdsi.*;
import sdsi.sexp.*;
import Tools.*;

import java.security.*;
import java.util.*;

/**
 * This proof verifies a proof involving restricted transitive
 * delegation, Theorem E6, that subsumes Axiom E1 as well.
 */
public class TwoStepProof
	extends Proof {

	Proof p0;
	Proof p1;
	Tag intersectedAuthorization;

	static final String LABEL = "two-step";

	/**
	 * Parse a proof from an S-Expression.
	 */
	public TwoStepProof(SexpList list)
		throws SexpParseException {
		if (!(list.getType().equals(Proof.LABEL)
				&& ((SexpString) list.elementAt(1)).stringContent()
					.equals(LABEL)
				&& list.size()==4
				&& (list.elementAt(2) instanceof SexpList)
				&& (list.elementAt(3) instanceof SexpList)
			)) {
			throw new SexpParseException(	
				"incorrectly formatted "+LABEL+" proof");
		}
		p0 = Proof.parse((SexpList) list.elementAt(2));
		p1 = Proof.parse((SexpList) list.elementAt(3));
		srep = list;
	}

	/**
	 * Construct a two-step proof from two appropriate lemmas.
	 * 
	 * @todo Verify right here that the lemmas fit together correctly,
	 * rather than waiting until the proof is sent to a server,
	 * to make it easier to debug client code.
	 */
	public TwoStepProof(Proof p0, Proof p1) {
		this.p0 = p0;
		this.p1 = p1;
		Sexp[] sexpary = new Sexp[4];
		sexpary[0] = new SexpString(Proof.LABEL);
		sexpary[1] = new SexpString(LABEL);
		sexpary[2] = p0.getSrep();
		sexpary[3] = p1.getSrep();
		srep = new SexpList(sexpary);
	}

	public SDSIPrincipal getIssuer() {
		return p0.getIssuer();
	}

	public Subject getSubject() {
		return p1.getSubject();
	}

	/**
	 * verify that the proof steps are indeed valid, and that they
	 * combine as advertised to show the claimed result
	 */
	protected void directVerify()
		throws InvalidProofException {
		if (!(p0.getSubject() instanceof SDSIPrincipal)
			|| !(KeyTools.arePrincipalsEquivalent(
						((SDSIPrincipal) p0.getSubject()),
						p1.getIssuer()
					)
				)
			) {
			throw new InvalidProofException("Chain not sequential: Issuer "
				+p1.getIssuer().toReadableString(72)
				+" not equal to subject "
				+((SDSIObject) p0.getSubject()).toReadableString(72));
		}
		p0.verify();
		p1.verify();
		// TODO (unimplemented security!) check validity dates.
	}

	void preorder(List addToMe, int what) {
		// if this node had its own issuer, we'd insert it here.
		if (what==Proof.PROOFS) {
			addToMe.add(this);
		}
		p0.preorder(addToMe, what);
		p1.preorder(addToMe, what);
	}

	public Tag getTag() {
		if (intersectedAuthorization==null) {
			intersectedAuthorization = p0.getTag().intersect(p1.getTag());
		}
		return intersectedAuthorization;
	}

	public Proof getChildProof(int i) {
		if (i==0) {
			return p0;
		} else if (i==1) {
			return p1;
		} else {
			return null;
		}
	}

	public Proof substituteProof(int i, Proof subProof) {
		Proof np0 = (i==0) ? subProof : p0;
		Proof np1 = (i==1) ? subProof : p1;
		return new TwoStepProof(np0, np1);
	}
}
