package proof;

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

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

/**
 * Proof of a conclusion that depends upon the left-monotonicity
 * property of names, Axiom E17.
 */
public class NameLeftMonotonicity
	extends Proof {

	Proof p0;
	SexpString[] suffixNames;
	SDSIPrincipal issuer;	// p0.issuer \cdot suffixNames
	SDSIPrincipal subject;	// p0.subject \cdot suffixNames

	static final String LABEL = "name-left-monotonicity";

	/**
	 * Parse the proof out of an S-Expression.
	 */
	public NameLeftMonotonicity(SexpList list)
		throws SexpParseException {
		if (!(list.getType().equals(Proof.LABEL)
				&& ((SexpString) list.elementAt(1)).stringContent()
					.equals(LABEL)
				&& list.size()>=4	// two labels, a principal,
									// and a nonempty name chain
				&& (list.elementAt(2) instanceof SexpList)	// the principal
			)) {
			throw new SexpParseException(	
				"incorrectly formatted "+LABEL+" proof");
		}
		p0 = Proof.parse((SexpList) list.elementAt(2));

		final int suffixOffset = 3;
		suffixNames = new SexpString[list.size()-suffixOffset];
		for (int i=suffixOffset; i<list.size(); i++) {
			try {
				suffixNames[i-suffixOffset] = (SexpString) list.elementAt(i);
			} catch (ClassCastException ex) {
				throw new SexpParseException(	
					"incorrectly formatted "+LABEL+" proof");
			}
		}
		srep = list;
		setupIssuerSubject();
	}

	/**
	 * Construct a new proof from a premise ({@tex $B \speaksfor A$})
	 * and the string of suffixes to append to both principals.
	 * Notice that you can supply a string of name suffixes, so that
	 * this single proof step collapses a series of <em>n</em>
	 * applications of Axiom E17.
	 */
	public NameLeftMonotonicity(Proof p0, SexpString[] suffixNames)
		throws SexpParseException {
		if (suffixNames.length==0) {
			throw new SexpParseException(	
				"incorrectly formatted "+LABEL
				+" proof: suffix list must be nonempty");
		}
		this.p0 = p0;
		this.suffixNames = suffixNames;
		SexpList tmpSrep = new SexpList();
		tmpSrep.append(Proof.LABEL);
		tmpSrep.append(LABEL);
		tmpSrep.append(p0.getSrep());
		for (int i=0; i<suffixNames.length; i++) {
			tmpSrep.append(suffixNames[i]);
		}
		srep = tmpSrep;
		setupIssuerSubject();
	}

	protected void setupIssuerSubject()
		throws SexpParseException {
		issuer = concatenateName(p0.getIssuer());
		subject = concatenateName((SDSIPrincipal) p0.getSubject());
	}

	protected SDSIPrincipal concatenateName(SDSIPrincipal p)
		throws SexpParseException {
		try {
			// build a Name by concatenation
			// I use the SexpList Name constructor because I'm not comfortable
			// squishing names (which can be raw bytestrings) through Java's
			// abusive Unicode String class.
			SexpList sl = new SexpList();
			sl = sl.append("name");
			// append pieces of original principal
			if (p instanceof Name) {
				Name pn = (Name) p;
				sl = sl.append(pn.getPrincipal().getSrep());
				for (int i=0; i<pn.size(); i++) {
					sl = sl.append(pn.getNameIndex(i));
				}
			} else {
				sl = sl.append(p.getSrep());
			}
			// and append the suffix
			for (int i=0; i<suffixNames.length; i++) {
				sl = sl.append(suffixNames[i]);
			}
	
			// System.out.println("building name with: "+sl.toReadableString(0,72,0));
			return new Name(sl, null);
		} catch (SDSIException ex) {
			throw new SexpParseException(
				"Trouble concatenating subject/issuer");
		} catch (SexpParseException ex) {
			throw new SexpParseException(
				"Trouble concatenating subject/issuer");
		}
	}

	public SDSIPrincipal getIssuer() {
		return issuer;
	}

	public Subject getSubject() {
		return subject;
	}

	/**
	 * verify that the proof steps are indeed valid, and that they
	 * combine as advertised to show the claimed result
	 */
	protected void directVerify()
		throws InvalidProofException {
		p0.verify();
		// If A=>B (the preceding verify), then
		// A \cdot N1 ... => B \cdot N1 ...
		// The conclusion is shown in the logic; no other explicit
		// data to check in the implementation.
	}

	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);
	}

	public Tag getTag() {
		return p0.getTag();
	}

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

	public Proof substituteProof(int i, Proof subProof) {
		if (i==0) {
			try {
				return new NameLeftMonotonicity(subProof, suffixNames);
			} catch (SexpParseException ex) {
				// this shouldn't happen, since we know suffixNames isn't
				// empty and we were able to build _this_ object without
				// an exception...
				return null;
			}
		} else {
			// meaningless substitution
			return this;
		}
	}
}
