package com.nifty.cloud.ncs.http;

import java.io.InputStream;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.entity.InputStreamEntity;

/**
 * HTTP要求情報を保持するクラスです。
 *
 */
public class HttpRequest
{
	private HttpMethod method;
	private URI uri;

	private HashMap<String, String> parameters = new HashMap<String, String>();
	private HashMap<String, String> headers = new HashMap<String, String>();

	private InputStream content;
	private InputStreamEntity entity;

	private static final Log log = LogFactory.getLog(HttpRequest.class);

    /**
     * 指定したHTTPメソッドを使用してHttpRequestを構築します。
     * サポートするメソッド： GET、DELETE、HEAD、PUT
     *
     * @param method
     * 	HTTPメソッド
     */
	public HttpRequest(HttpMethod method)
	{
		this.method = method;
	}

	/**
	 * HTTPメソッドを取得します。
	 *
	 * @return
	 *  HTTPメソッド
	 */
	public HttpMethod getHttpMethod()
	{
		return (this.method);
	}

	/**
	 * HTTP要求URIを設定します。
	 *
	 * @param uri
	 *  HTTP要求URI
	 */
	public void setUri(URI uri)
	{
		this.uri = uri;
	}

	/**
	 * HTTP要求URI取得
	 *
	 * @return
	 *  HTTP要求URI
	 */
	public URI getUri()
	{
		return (this.uri);
	}

	/**
	 * デフォルトポートを使用しているかどうかの判定を行います。
	 *
	 * @return
	 *  デフォルトポート(HTTP:80、HTTPS：443)を使用している場合は<code>true</code>、
	 *  そうでなければ<code>false</code>
	 *
	 */
	public boolean isUsingDefaultPort()
	{
		if (uri == null) {
			return (true);
		}

		int port = uri.getPort();

		if (port == -1 || port == 80 || port == 443) {
			return (true);
		}

		return (false);
	}

	/**
	 * HTTP要求パラメータを追加します。
	 *
	 * @param key
	 *  要求パラメータのkey
	 * @param value
	 *  要求パラメータのvalue
	 */
	public void addParameter(String key, String value)
	{
		parameters.put(key, value);
	}

	/**
	 * 指定したkeyに紐付いた要求パラメータのvalueを取得します。
	 *
	 * @param key
	 *  要求パラメータのkey
	 * @return
	 *  指定したkeyに紐付いた要求パラメータのvalue
	 */
	public String getParameter(String key)
	{
		return (parameters.get(key));
	}

	/**
	 * 要求パラメータのマップを取得します。
	 *
	 * @return
	 *  要求パラメータのマップ
	 */
	public Map<String, String> getParameters()
	{
		return (this.parameters);
	}

	/**
	 * HTTP要求ヘッダを追加します。
	 *
	 * @param key
	 *	要求ヘッダのkey
	 * @param value
	 *  要求ヘッダのvalue
	 */
	public void addHeader(String key, String value)
	{
		headers.put(key, value);
	}

	/**
	 * 要求ヘッダから指定したkeyを削除します。
	 *
	 * @param key
	 *  要求ヘッダのkey
	 */
	public void removeHeader(String key)
	{
		headers.remove(key);
	}

	/**
	 * 指定したkeyに紐付く要求ヘッダのvalueを取得します。
	 *
	 * @param key
	 *  要求ヘッダのkey
	 * @return
	 *  指定したkeyに紐付く要求ヘッダのvalue
	 */
	public String getHeader(String key)
	{
		return (headers.get(key));
	}

	/**
	 * 要求ヘッダのマップを取得します。
	 *
	 * @return
	 *  要求ヘッダのマップ
	 */
	public Map<String, String> getHeaders()
	{
		return (this.headers);
	}

	/**
	 * HTTP要求ボディを設定します。
	 *
	 * @param content
	 *  要求ボディ
	 */
	public void setContent(InputStream content)
	{
		this.content = content;
	}

	/**
	 * 要求ボディを取得します。
	 *
	 * @return
	 *  要求ボディ
	 */
	public InputStream getContent()
	{
		return (content);
	}

	/**
	 * 要求エンティティを取得します。
	 *
	 *
	 * @return
	 *  要求エンティティ
	 */
	public InputStreamEntity getEntity()
	{
		if (entity != null) {
			return (this.entity);
		}

		long length = -2;

		if (this.content != null) {
			try {
				String lengthString = headers.get("Content-Length");
				if (lengthString != null) {
					length = Long.parseLong(lengthString);
				}
			} catch (NumberFormatException e) {
				log.warn("Unable to parse Content-Length from request header. Buffering contents in memory.");
			}
			entity = new InputStreamEntity(content, length);
			String type = headers.get("Content-Type");
			entity.setContentType(type);
		}

		return (this.entity);
	}

	@Override
	public String toString()
	{
		StringBuffer sb = new StringBuffer(1024);

		sb.append(method.toString()).append(" ");
		sb.append(uri.getHost()).append(" ");

		sb.append("/");
		if (uri.getPath() != null) {
			sb.append(uri.getPath());
		}
		sb.append(" ");

		if (parameters.isEmpty() == false) {
			sb.append("Parameters: (");
			for (String key : parameters.keySet()) {
				sb.append(key).append(": ");
				sb.append(parameters.get(key)).append(", ");
			}
			sb.append(") ");
		}

		if (headers.isEmpty() == false) {
			sb.append("Headers: (");
			for (String key : headers.keySet()) {
				sb.append(key).append(": ");
				sb.append(headers.get(key)).append(", ");
			}
			sb.append(") ");
		}

		return (sb.toString());
	}
}
