/**
 * Part of the CCNx Java Library.
 *
 * Copyright (C) 2008, 2009 Palo Alto Research Center, Inc.
 *
 * This library is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License version 2.1
 * as published by the Free Software Foundation. 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details. You should have received
 * a copy of the GNU Lesser General Public License along with this library;
 * if not, write to the Free Software Foundation, Inc., 51 Franklin Street,
 * Fifth Floor, Boston, MA 02110-1301 USA.
 */

package org.ccnx.ccn.protocol;

import java.io.Serializable;

import org.ccnx.ccn.impl.encoding.GenericXMLEncodable;
import org.ccnx.ccn.impl.encoding.XMLDecoder;
import org.ccnx.ccn.impl.encoding.XMLEncodable;
import org.ccnx.ccn.impl.encoding.XMLEncoder;
import org.ccnx.ccn.io.content.ContentDecodingException;
import org.ccnx.ccn.io.content.ContentEncodingException;



/**
 * We wish to securely refer to a key. We do that by specifying a ContentName
 * where it can be retrieved, and (optionally) information about who must
 * have signed it for us to consider it valid. This can be a direct specification
 * of who must have signed it -- effectively saying that a specific key, corresponding
 * to an individual, most have signed the target for us to find it acceptable.
 * More powerfully, this can incorporate a level of indirection -- we can say that
 * an acceptable key is one signed by anyone whose own key was signed by the
 * specified publisher, effectively allowing for a form of certification. 
 * 
 * For now we allow a variety of specification of publisher, including some using
 * digital certificates. These may be unnecessary and elided in the future.
 */
public class KeyName extends GenericXMLEncodable implements XMLEncodable, Serializable {
	
	private static final long serialVersionUID = -4486998061731593809L;

	protected static final String KEY_NAME_ELEMENT = "KeyName";

	protected ContentName _name;
	protected PublisherID _publisher;
	
	/**
	 * Build a KeyName
	 * @param name the name at which we can find the key
	 * @param publisher the publisher we require to have signed the key, or to have signed
	 * 	the key that signed the key
	 */
	public KeyName(ContentName name, 
				   PublisherID publisher) {
		_name = name;
		_publisher = publisher;
	}
	
	public KeyName(ContentName name, PublisherPublicKeyDigest publisher) {
		_name = name;
		_publisher = new PublisherID(publisher);
	}
	
	/**
	 * Build a KeyName
	 * @param name the name at which we can find the key
	 */
	public KeyName(ContentName name) {
		this(name, (PublisherID)null);
	}

	/**
	 * For use by decoders
	 */
	public KeyName() {}

	/**
	 * Get the name
	 * @return the name
	 */
	public ContentName name() { return _name; }
	
	/**
	 * Get the required publisher information, if specified.
	 * @return the publisher specification
	 */
	public PublisherID publisher() { return _publisher; }
	
	/**
	 * Thought about encoding and decoding as flat -- no wrapping
	 * declaration. But then couldn't use these solo.
	 */
	@Override
	public void decode(XMLDecoder decoder) throws ContentDecodingException {
		decoder.readStartElement(getElementLabel());

		_name = new ContentName();
		_name.decode(decoder);
		
		if (PublisherID.peek(decoder)) {
			_publisher = new PublisherID();
			_publisher.decode(decoder);
		}
		
		decoder.readEndElement();
	}

	@Override
	public void encode(XMLEncoder encoder) throws ContentEncodingException {
		if (!validate()) {
			throw new ContentEncodingException("Cannot encode " + this.getClass().getName() + ": field values missing.");
		}
		encoder.writeStartElement(getElementLabel());
		
		name().encode(encoder);
		if (null != publisher())
			publisher().encode(encoder);

		encoder.writeEndElement();   		
	}
	
	@Override
	public String getElementLabel() { return KEY_NAME_ELEMENT; }

	@Override
	public boolean validate() {
		// DKS -- do we do recursive validation?
		// null signedInfo ok
		return (null != name());
	}

	@Override
	public int hashCode() {
		final int PRIME = 31;
		int result = 1;
		result = PRIME * result + ((_publisher == null) ? 0 : _publisher.hashCode());
		result = PRIME * result + ((_name == null) ? 0 : _name.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		final KeyName other = (KeyName) obj;
		if (_publisher == null) {
			if (other._publisher != null)
				return false;
		} else if (!_publisher.equals(other._publisher))
			return false;
		if (_name == null) {
			if (other._name != null)
				return false;
		} else if (!_name.equals(other._name))
			return false;
		return true;
	}
	
	@Override 
	public String toString() {
		return ((null != name()) ? name() : "") + ((null != publisher()) ? " " + publisher() : "");
	}
}

@@ -835,16 +835,68 @@
 zable;%0A%0A
+import org.ccnx.ccn.impl.encoding.CCNProtocolDTags;%0A
 import o
@@ -2181,72 +2181,8 @@
 L;%0A%0A
-%09protected static final String KEY_NAME_ELEMENT = %22KeyName%22;%0D%0A%0D%0A
 %09pro
@@ -4097,20 +4097,18 @@
 %09public 
-Stri
+Lo
 ng getEl
@@ -4133,24 +4133,41 @@
 urn 
-KEY_NAME_ELEMENT
+CCNProtocolDTags.KeyName.getTag()
 ; %7D%0D

Move to new encoding model.