/*
 * Copyright (C) 2005-2006 Kouji Sugisawa. All rights reserved.
 */

package jp.sourceforge.livez.ezweb;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;

import jp.sourceforge.livez.IllegalUserAgentException;
import jp.sourceforge.livez.UserAgentNotFoundException;

/**
 * EZwebUserAgent を実装したクラスです。
 * 
 * @author 杉澤 浩二
 */
final class EZwebUserAgentImpl implements EZwebUserAgent {

	/**
	 * デバイスタイプのパターンです。
	 */
	private static final String DEVICE_TYPE_PATTERN = "[A-Z]{2}[A-Z0-9]{2}";

	/**
	 * WAP (HDML) 対応端末のユーザエージェントのパターンです。
	 */
	private static final String WAP_PATTERN = "^UP\\.Browser/.+-" + DEVICE_TYPE_PATTERN + " .+/.+$";

	/**
	 * WAP 2.0 (XHTML) 対応端末のユーザエージェントのパターンです。
	 */
	private static final String WAP2_PATTERN = "^KDDI-" + DEVICE_TYPE_PATTERN + " UP\\.Browser/.+ \\(GUI\\) .+/.+$";

	/**
	 * HTTP リクエスト情報からクラスを構築するコンストラクタです。
	 * 
	 * @param request HTTP リクエスト情報
	 * @throws UserAgentNotFoundException ユーザーエージェントが存在しない場合
	 * @throws IllegalUserAgentException ユーザエージェントの形式が不正な場合
	 */
	public EZwebUserAgentImpl(final HttpServletRequest request) throws UserAgentNotFoundException, IllegalUserAgentException {
		this(request.getHeader(HTTP_HEADER_KEY));
	}

	/**
	 * 指定された文字列からこのクラスを構築します。
	 * 
	 * @param ua HTTP ユーザーエージェントを表す文字列
	 * @throws UserAgentNotFoundException ユーザーエージェントが null の場合
	 * @throws IllegalUserAgentException ユーザエージェントの形式が不正な場合
	 */
	public EZwebUserAgentImpl(final String ua) throws UserAgentNotFoundException, IllegalUserAgentException {
		// ユーザエージェントの妥当性を検証します。
		if (ua == null)
			throw new UserAgentNotFoundException();
		if (!ua.matches(WAP_PATTERN) && !ua.matches(WAP2_PATTERN))
			throw new IllegalUserAgentException(ua);

		this.value = ua;
		// デバイスタイプを設定します。
		this.id = ua.substring(ua.indexOf('-') + 1, ua.indexOf(' '));
		this.wap2 = !ua.startsWith("UP.Browser");

		// ブラウザのバージョン情報を設定します。
		int start = ua.indexOf('/');
		int end;

		if (!this.wap2)
			end = ua.indexOf('-', start + 1);
		else
			end = ua.indexOf('(', start + 1);

		this.browserVersion = ua.substring(start + 1, end);

		String[] s = ua.substring(ua.lastIndexOf(' ') + 1).split("/");
		this.serverName = s[0];
		this.serverVersion = s[1];
	}

	/**
	 * ユーザエージェントの生値を保持します。
	 */
	private String value = null;

	/*
	 * @see jp.sourceforge.livez.UserAgent#getValue()
	 */
	public String getValue() {
		return value;
	}

	/**
	 * デバイスタイプを保持します。
	 */
	private String id = null;

	/*
	 * @see jp.sourceforge.livez.UserAgent#getId()
	 */
	public String getId() {
		return id;
	}

	/**
	 * WAP2 (XHTML) 対応状況を保持します。
	 */
	private boolean wap2 = false;

	/*
	 * @see jp.sourceforge.livez.ezweb.EZwebUserAgent#isWap2()
	 */
	public boolean isWap2() {
		return wap2;
	}

	/**
	 * ブラウザのバージョン情報を保持します。
	 */
	private String browserVersion = null;

	/*
	 * @see jp.sourceforge.livez.ezweb.EZwebUserAgent#getBrowserVersion()
	 */
	public String getBrowserVersion() {
		return browserVersion;
	}

	private String serverName = null;

	/*
	 * @see jp.sourceforge.livez.ezweb.EZwebUserAgent#getServerName()
	 */
	public String getServerName() {
		return serverName;
	}

	private String serverVersion = null;

	/*
	 * @see jp.sourceforge.livez.ezweb.EZwebUserAgent#getServerVersion()
	 */
	public String getServerVersion() {
		return serverVersion;
	}

	@Override
	public int hashCode() {
		return HashCodeBuilder.reflectionHashCode(this);
	}

	@Override
	public boolean equals(final Object obj) {
		return EqualsBuilder.reflectionEquals(this, obj);
	}

	@Override
	public String toString() {
		return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
	}

}
