/*
 * LOGICAL-PARADOX.ORG
 * Copyright (C)2005 satoshi akabane(akabane@logical-paradox.org)
 * $Id: ResponseHeader.java,v 1.1 2005/05/11 17:48:20 rampil Exp $
 */
package org.logical_paradox.httpd;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.NoSuchElementException;

import org.logical_paradox.httpd.html.ErrorCodeDictionary;

/**
 * レスポンスヘッダクラス
 * @author satoshi akabane@logical-paradox.org
 * @version $Revision: 1.1 $
 */
public class ResponseHeader {
	/** デフォルトのサーバープロトコルとバージョン */
	public static final String DEFAULT_SERVER_PROTOCOL = "HTTP/1.1";

	/** ヘッダキー: Content-Type */
	public static final String H_CONTENT_TYPE = "Content-Type";
	/** ヘッダキー: Connection */
	public static final String H_CONNECTION = "Connection";

	/** HTTPのレスポンスコード */
	private int responseCode = 200;

	/** レスポンスヘッダ */
	private ArrayList hvp = new ArrayList();

	/**
	 * コンストラクタ
	 */
	public ResponseHeader() {
		// デフォルトのコンテンツタイプを設定する
		hvp.add(new HeaderValuePair(H_CONTENT_TYPE, HttpdProperties.getProperty(HttpdProperties.DEFAULT_CONTENTTYPE)));
		hvp.add(new HeaderValuePair(H_CONNECTION, "close"));
	}
	/**
	 * コンストラクタ
	 * @param responseCode HTTPのレスポンスコード
 	 */
	public ResponseHeader(int rc) {
		// デフォルトコンストラクタの呼出し
		this();
		// レスポンスコードの設定
		responseCode = rc;
	}
	/**
	 * コピーコンストラクタ
	 * @param rh コピー元のレスポンスヘッダ
	 */
	public ResponseHeader(ResponseHeader rh) {
		hvp = (ArrayList)rh.getHeaders().clone();
	}
	/**
	 * 登録されているレスポンスヘッダのマップを返す
	 * @return レスポンスヘッダのマップ
	 */
	private ArrayList getHeaders() {
		return hvp;
	}
	/**
	 * ヘッダを追加する
	 * @param key ヘッダ名
	 * @param value ヘッダ値
	 */
	public void put(String key, String value) {
		synchronized(hvp) {
			// ヘッダの重複を避けるため，とりあえず削除してから追加する
			remove(key);
			hvp.add(new HeaderValuePair(key, value));
		}
	}
	/**
	 * 指定されたヘッダをレスポンスヘッダのリストから削除する
	 * @param key ヘッダ文字列
	 */
	public void remove(String key) {
		synchronized(hvp) {
			HeaderValuePair p = new HeaderValuePair(key, "");
			if(hvp.contains(new HeaderValuePair(key, ""))) {
				hvp.remove(p);
			}
		}
	}
	/**
	 * レスポンスコードを返す
	 * @return HTTPレスポンスコード
	 */
	public int getResponseCode() {
		return responseCode;
	}
	/**
	 * レスポンスコードを設定する
	 * @param HTTPレスポンスコード
	 */
	public void setResponseCode(int rc) {
		responseCode = rc;
	}
	/**
	 * HTTPステータスコードとしての文字列を返す
	 * @return HTTPステータスコード(文字列表現)
	 */
	public String getHttpStatusCode() {
		return DEFAULT_SERVER_PROTOCOL + " " + getResponseCode() + " " + ErrorCodeDictionary.getMessage(getResponseCode());
	}
	/**
	 * ヘッダとキーのペアに対してアクセスするイテレータを返す
	 * @return イテレータ
	 */
	public Iterator iteratorHeader() {
		return new HeaderValueIterator(getHeaders());
	}

	/**
	 * ヘッダと値の組み合わせ文字列を取り込むイテレータ
	 * @author satoshi akabane@logical-paradox.org
	 * @version $Revision: 1.1 $
	 */
	class HeaderValueIterator implements Iterator {
		/** ヘッダと値のペアを格納した配列(イテレーションの対象) */
		private ArrayList baseArray = new ArrayList();
		/** 参照ポイント */
		private int pos = 0;

		/**
		 * コンストラクタ
		 * 配列の内容はHeaderValuePairクラス
		 * @param ar ヘッダ値の配列
		 */
		private HeaderValueIterator(ArrayList ar) {
			synchronized(ar) {
				for(Iterator it = ar.iterator(); it.hasNext();) {
					HeaderValuePair hvp = (HeaderValuePair)it.next();
					baseArray.add(hvp.toString());
				}
			}
		}
		/**
		 * メンバーを削除する
		 * このメソッドはサポートされていない
		 */
		public void remove() {
		}
		/**
		 * 次のメンバーが取得できるかどうかを返す
		 * @return true:取れる / false:取れない
		 */
		public boolean hasNext() {
			return pos < baseArray.size();
		}
		/**
		 * 次のオブジェクトを返す
		 * @return 次の値
		 */
		public Object next() {
			if(hasNext() == false) {
				throw new NoSuchElementException();
			}
			return baseArray.get(pos++);
		}
	}
	/**
	 * ヘッダと値のペアを表現するクラス
	 * @author satoshi akabane@logical-paradox.org
	 * @version $Revision: 1.1 $
	 */
	class HeaderValuePair {
		/** ヘッダ名 */
		private final String header_;
		/** ヘッダ値 */
		private final String value_;

		/**
		 * コンストラクタ
		 * @param header ヘッダ名
		 * @param value ヘッダ値
		 */
		private HeaderValuePair(String header, String value) {
			header_ = header;
			value_ = value;
		}
		/**
		 * ヘッダ文字列を返す
		 * @return ヘッダ文字列
		 */
		private String getHeader() {
			return header_;
		}
		/**
		 * ヘッダ値を返す
		 * @return ヘッダ値
		 */
		private String getValue() {
			return value_;
		}
		/**
		 * ヘッダの文字列表現を返す
		 * <ヘッダ名>: <値>
		 * の形式
		 * @return ヘッダの文字列表現
		 */
		public String toString() {
			return getHeader() + ": " + getValue();
		}
		/**
		 * オブジェクト同士を比較する
		 * キーが同じであれば，同じとみなす(同じヘッダが複数存在するのを避けるため)
		 * @param o 比較対象のオブジェクト
		 * @return true:同じ / false:違う
		 */
		public boolean equals(Object o) {
			if(o == null || o instanceof HeaderValuePair == false) {
				return false;
			}
			HeaderValuePair p = (HeaderValuePair)o;

			return getHeader().equals(p.getHeader());
		}
		/**
		 * ハッシュコードを返す
		 * ヘッダ文字列のハッシュコードを返すだけ
		 * @return ハッシュコード
		 */
		public int hashCode() {
			return getHeader().hashCode();
		}

	}
}
