/**
 * Copyright 2010 JBoss Inc
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.eclipse.webdav.internal.authentication;

import java.util.Hashtable;
import org.eclipse.webdav.client.Policy;

/**
 * Parses the HTTP "Authentication-Info" header field. The header field
 * has the following form:
 *
 * <code>
 * auth-info		= 1#(nextnonce | [ message-qop ]
 * 						| [ response-auth ] | [ cnonce ]
 * 						| [ nonce-count ] )
 * nextnonce		= "nextnonce" "=" nonce-value
 * nonce-value		= quoted-string
 * message-qop		= "qop" "=" qop-value
 * qop-value		= "auth" | "auth-int" | token
 * response-auth	= "rspauth" "=" response-digest
 * response-digest	= <"> *LHEX <">
 * cnonce			= "cnonce" "=" cnonce-value
 * cnonce-value		= nonce-value
 * nonce-count		= "nc" "=" nc-value
 * nc-value			= 8LHEX
 * </code>
 *
 * An auth-info may look like this:
 *
 * <code>
 * Authentication-Info:
 * nextnonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",
 * qop="auth",
 * rspauth="5ccc069c403ebaf9f0171e9517f40e41",
 * cnonce="0a4f113b",
 * nc=00000001
 * </code>
 */
public class AuthenticationInfo {
	private String authInfo;
	private Parser parser;
	private Hashtable info;

	/**
	 * Parses the given authentication info.
	 *
	 * @param authInfo
	 * @throws ParserException if the info is malformed
	 */
	public AuthenticationInfo(String authInfo) throws ParserException {
		this.authInfo = authInfo;
		this.parser = new Parser(authInfo);
		parse();
	}

	/**
	 * Returns the value of the cnonce parameter, or <code>null</code> if
	 * the parameter does not exist.
	 */
	public String getCNonce() {
		return (String) info.get("cnonce"); //$NON-NLS-1$
	}

	/**
	 * Returns the value of the qop parameter, or <code>null</code> if
	 * the parameter does not exist.
	 */
	public String getMessageQop() {
		return (String) info.get("qop"); //$NON-NLS-1$
	}

	/**
	 * Returns the value of the nextnonce parameter, which must exist.
	 */
	public String getNextNonce() {
		return (String) info.get("nextnonce"); //$NON-NLS-1$
	}

	/**
	 * Returns the value of the nc parameter, or <code>null</code> if
	 * the parameter does not exist.
	 */
	public String getNonceCount() {
		return (String) info.get("nc"); //$NON-NLS-1$
	}

	/**
	 * Returns the value of the rspauth parameter, or <code>null</code> if
	 * the parameter does not exist.
	 */
	public String getResponseAuth() {
		return (String) info.get("rspauth"); //$NON-NLS-1$
	}

	private void parse() throws ParserException {
		info = new Hashtable(5);

		boolean done = false;
		while (!done) {
			String param = parser.nextToken();
			parser.match('=');
			String value = null;
			parser.checkPosition();
			if (authInfo.charAt(parser.pos) == '"') { //$NON-NLS-1$
				value = parser.nextQuotedString();
			} else {
				value = parser.nextToken();
			}
			info.put(param, value);
			parser.skipWhiteSpace();
			done = parser.pos == authInfo.length();
			if (!done) {
				parser.match(',');
				parser.skipWhiteSpace();
			}
		}

		if (getNextNonce() == null) {
			throw new ParserException(Policy.bind("exception.missingNextnonce")); //$NON-NLS-1$
		}
	}
}
