/* 
 * E-XML Library:  For XML, XML-RPC, HTTP, and related.
 * Copyright (C) 2002-2008  Elias Ross
 * 
 * genman@noderunner.net
 * http://noderunner.net/~genman
 * 
 * 1025 NE 73RD ST
 * SEATTLE WA 98115
 * USA
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * 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.
 * 
 * $Id$
 */

package net.noderunner.http;

import java.net.URL;
import java.util.StringTokenizer;

/**
 * This is a immutable implementation of an HTTP request line.
 */
public class RequestLine {
	
	private Method method;

	private String requestURI;

	private HttpVersion version;

	private String toString;

	/**
	 * Constructs using a method, a request URI, and the default HTTP/1.1
	 * version. If the URI is empty, defaults to the file <code>/</code>.
	 */
	public RequestLine(Method method, String requestURI) {
		this(method, requestURI, HttpVersion.HTTP11);
	}

	/**
	 * Constructs using all <code>Request-Line<code> parts.
	 */
	public RequestLine(Method method, String requestURI, HttpVersion version) {
		if (method == null)
			throw new IllegalArgumentException("Null method");
		if (requestURI == null)
			throw new IllegalArgumentException("Null requestURI string");
		if (version == null)
			throw new IllegalArgumentException("Null version");
		this.method = method;
		if (requestURI.length() == 0)
			requestURI = "/";
		this.requestURI = requestURI;
		this.version = version;
	}

	/**
	 * Construct using an unparsed request line. This string should not end in
	 * <code>CRLF</code>.
	 * 
	 * @throws HttpException
	 *             if an invalid HTTP Request-Line was used in initialization
	 */
	public RequestLine(String line) throws HttpException {
		StringTokenizer st = new StringTokenizer(line, " ");
		try {
			method = Method.valueOf(st.nextToken());
			requestURI = st.nextToken();
			if (st.hasMoreTokens())
				version = HttpVersion.parseVersion(st.nextToken());
			else
				version = HttpVersion.HTTP10;
		} catch (RuntimeException e) {
			throw new HttpException("Invalid Request-Line: " + line);
		}
	}

	/**
	 * Copy-constructs a new RequestLine using a different requestURI.
	 * @param requestLine existing request line
	 * @param fileName new file name
	 */
	public RequestLine(RequestLine requestLine, String requestURI) {
		this(requestLine.getMethod(), requestURI, requestLine.getHttpVersion());
	}

	/**
	 * Creates and returns a request line based on a URL and method.
	 * For any method, the line consists of the given method, the filename,
	 * and HTTP/1.1 request line.  For example, a valid method
	 * is the constant {@link RequestLine#METHOD_GET}.
	 */
	public static RequestLine create(URL url, Method method) {
		if (url == null)
			throw new IllegalArgumentException("Null url");
		if (method == null)
			throw new IllegalArgumentException("Null method");
		return new RequestLine(method, url.getFile());
	}

	/**
	 * Returns the name of the request method. This should be either one of the
	 * constant string methods in this class, or an
	 * <code>extension-method</code>.
	 */
	public Method getMethod() {
		return method;
	}

	/**
	 * Returns the URI of this request.
	 */
	public String getRequestURI() {
		return requestURI;
	}

	/**
	 * Returns the version of this request.
	 */
	public HttpVersion getHttpVersion() {
		return version;
	}

	/**
	 * Returns this <code>RequestLine</code> as:
	 * 
	 * <pre>
	 * getMethod() + ' ' + getRequestURI() + ' ' + getHttpVersion()
	 * </pre>
	 * 
	 * Note: Does not include <code>CRLF</code>.
	 */
	public String toString() {
		if (toString == null)
			toString = getMethod().name() + ' ' + getRequestURI() + ' '
					+ getHttpVersion();
		return toString;
	}
}
