package com.nifty.cloud.ncs.service;

import java.io.InputStream;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;


/**
 * ニフクラストレージのオブジェクト情報を保持するクラスです。
 *
 */
public class NcsObject
{
	private String objectName = null;
	private String bucketName = null;
	private HashMap<String, String> userMetadata = new HashMap<String, String>();
	private HashMap<String, Object> metadata = new HashMap<String, Object>();
	private InputStream content = null;

	private Owner owner = null;

	/**
	 * 名前を指定せずに新しいNcsObjectを構築します。
	 *
	 */
	public NcsObject()
	{
	}

	/**
	 * 指定した名前を使用して新しいNcsObjectを構築します。
	 *
	 * @param objectName
	 *  オブジェクト名
	 */
	public NcsObject(String objectName)
	{
		this.objectName = objectName;
	}

	/**
	 * バケット名、オブジェクト名を指定して新しいNcsObjectを構築します。
	 *
	 * @param bucketName
	 *  バケット名
	 * @param objectName
	 *  オブジェクト名
	 */
	public NcsObject(String bucketName, String objectName)
	{
		this.bucketName = bucketName;
		this.objectName = objectName;
	}

	/**
	 * オブジェクトのオーナーを設定します。
	 *
	 * @param owner
	 *  オブジェクトのオーナー
	 */
	public void setOwner(Owner owner)
	{
		this.owner = owner;
	}

	/**
	 * オブジェクトのオーナーを取得します。
	 *
	 * @return
	 *  オブジェクトのオーナー
	 */
	public Owner getOwner()
	{
		return (owner);
	}

	/**
	 * オブジェクト名を設定します。
	 *
	 * @param objectName
	 *  オブジェクト名
	 */
	public void setObjectName(String objectName)
	{
		this.objectName = objectName;
	}

	/**
	 * オブジェクト名を取得します。
	 *
	 * @return
	 *  オブジェクト名
	 */
	public String getObjectName()
	{
		return (objectName);
	}

	/**
	 * このオブジェクトが格納されているバケット名を設定します。
	 *
	 * @param bucketName
	 *  このオブジェクトが格納されているバケット名
	 *
	 */
	public void setBucketName(String bucketName)
	{
		this.bucketName = bucketName;
	}

	/**
	 * このオブジェクトが格納されているバケット名を取得します。
	 *
	 * @return
	 *  このオブジェクトが格納されているバケット名
	 */
	public String getBucketName()
	{
		return (bucketName);
	}

	/**
	 * HTTPヘッダを追加します。
	 *
	 * @param key
	 *  HTTPヘッダのキー
	 * @param value
	 *  HTTPヘッダの値
	 * @throws IllegalArgumentException
	 */
	public void addHeader(String key, Object value) throws IllegalArgumentException
	{
		if (key.startsWith(StorageHeadersImpl.NIFTY_USER_METADATA_PREFIX)) {
			if (key.substring(StorageHeadersImpl.NIFTY_USER_METADATA_PREFIX.length()).matches(".*[^0-9a-zA-Z]+.*")) {
				throw (new IllegalArgumentException("User meta data header key can contain alphanumeric characters."));
			}
		}

		metadata.put(key, value);
	}

	/**
	 * メタデータを追加します。
	 *
	 * @param key
	 *  メタデータのキー
	 * @param value
	 *  メタデータの値
	 */
	public void addUserMetadata(String key, String value)
	{
		userMetadata.put(key, value);
	}

	/**
	 * メタデータの取得
	 *
	 * @return
	 *  メタデータ
	 */
	public Map<String, String> getUserMetadata()
	{
		return (userMetadata);
	}

    /**
     * 生のメタデータ／ヘッダのマップを取得します。
     *
     * @return
     *  生のメタデータ／ヘッダのマップ
     */
	public Map<String, Object> getRawMetadata()
	{
		return (Collections.unmodifiableMap(metadata));
	}

	public Map<String, Object> getMetadata()
	{
		Map<String, Object> metadata = new TreeMap<String, Object>();
		metadata.putAll(getUserMetadata());
		metadata.putAll(getRawMetadata());
		return metadata;
	}

    /**
     * オブジェクトのコンテンツを設定します。
     *
     * @param content
     *   オブジェクトのコンテンツを含む入力ストリーム
     */
	public void setContent(InputStream content)
	{
		this.content = content;
	}

    /**
     * オブジェクトのコンテンツ取得します。
     *
     * @return
     *  オブジェクトのコンテンツを含む入力ストリーム
     */
	public InputStream getContent()
	{
		return (content);
	}

    /**
     * オブジェクトの最終更新日時を設定します。
     *
     * @param lastModified
     *  オブジェクトの最終更新日時
     *
     */
	public void setLastModified(Date lastModified)
	{
		metadata.put(StorageHeadersImpl.LAST_MODIFIED, lastModified);
	}

    /**
     * オブジェクトの最終更新日時を取得します。
     *
     * @return
     *  オブジェクトの最終更新日時
     *
     */
	public Date getLastModified()
	{
		return ((Date)metadata.get(StorageHeadersImpl.LAST_MODIFIED));
	}

    /**
     * オブジェクトのコンテンツ長を設定します。
     *
     * @param length
     *  オブジェクトのコンテンツ長(byte単位)
     *
     */
	public void setContentLength(long length)
	{
		metadata.put(StorageHeadersImpl.CONTENT_LENGTH, length);
	}

    /**
     * オブジェクトのコンテンツ長を取得します。
     *
     * @return オブジェクトのコンテンツ長
     *
     */
	public long getContentLength()
	{
		Long length = (Long)metadata.get(StorageHeadersImpl.CONTENT_LENGTH);

		if (length == null) {
			return (0);
		}

		return (length.longValue());
	}

    /**
     * オブジェクトのコンテンツタイプを設定します。
     *
     * @param contentType
     *  オブジェクトのコンテンツタイプ
     */
	public void setContentType(String contentType)
	{
		metadata.put(StorageHeadersImpl.CONTENT_TYPE, contentType);
	}

    /**
     * オブジェクトのコンテンツタイプを取得します。
     *
     * @return オブジェクトのコンテンツタイプ
     *
     */
	public String getContentType()
	{
		return ((String)metadata.get(StorageHeadersImpl.CONTENT_TYPE));
	}

    /**
     * オブジェクトの文字エンコーディングを設定します
     *
     * @param contentEncoding
     *  オブジェクトの文字エンコーディング
     *
     * @see <a
     *      href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.11"
     *      >http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.11</a>
     *
     */
	public void setContentEncoding(String contentEncoding)
	{
		metadata.put(StorageHeadersImpl.CONTENT_ENCODING, contentEncoding);
	}

    /**
     * オブジェクトの文字エンコーディングを取得します。
     *
     * @return オブジェクトの文字エンコーディング
     *
     */
	public String getContentEncoding()
	{
		return ((String)metadata.get(StorageHeadersImpl.CONTENT_ENCODING));
	}

    /**
     * オブジェクトのCache-Controlを設定します。
     *
     * @param cacheControl
     *  オブジェクトのCache-Controlの設定値
     */
	public void setCacheContro(String cacheControl)
	{
		metadata.put(StorageHeadersImpl.CACHE_CONTROL, cacheControl);
	}

    /**
     * オブジェクトのCache-Controlの設定値を取得します。
     *
     * @return オブジェクトのCache-Controlの設定値
     *
     */
	public String getCacheControl()
	{
		return ((String)metadata.get(StorageHeadersImpl.CACHE_CONTROL));
	}

    /**
     * オブジェクトのMD5ハッシュ値を設定します。
     *
     * @param md5Base64
     *	オブジェクトのMD5ハッシュ値
     *
     * @see NcsObject#getContentMD5()
     */
	public void setContentMD5(String md5Base64)
	{
		metadata.put(StorageHeadersImpl.CONTENT_MD5, md5Base64);
	}

    /**
     * オブジェクトのMD5ハッシュ値を取得します。
     *
     * @return オブジェクトのMD5ハッシュ値
     *
     */
	public String getContentMD5()
	{
		return ((String)metadata.get(StorageHeadersImpl.CONTENT_MD5));
	}

    /**
     * オブジェクトのContent-Dispositionを設定します。
     *
     * @param contentDisposition
     *	オブジェクトのContent-Dispositionの設定値
     *
     */
	public void setContentDisposition(String contentDisposition)
	{
		metadata.put(StorageHeadersImpl.CONTENT_DISPOSITION, contentDisposition);
	}

    /**
     * オブジェクトのContent-Dispositionの設定値を取得します
     *
     * @return オブジェクトのContent-Dispositionの設定値
     *
     * @see <a
     *      href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.5.1"
     *      >http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.5.1</a>
     *
     */
	public String getContentDisposition()
	{
		return ((String)metadata.get(StorageHeadersImpl.CONTENT_DISPOSITION));
	}

    /**
     * オブジェクトのETagを設定します。
     *
     * @param eTag
     *	オブジェクトのETag
     */
	public void setETag(String eTag)
	{
		metadata.put(StorageHeadersImpl.ETAG, eTag);
	}

    /**
     * オブジェクトのETagを取得します。
     *
     * @return
     *  オブジェクトのETag
     *
     */
	public String getETag()
	{
		return ((String)metadata.get(StorageHeadersImpl.ETAG));
	}

	@Override
	public String toString()
	{
		String bucket;
		if (bucketName == null) {
			bucket = "<Unknown>";
		} else {
			bucket = bucketName;
		}

		return (String.format("NcsObject [name=%s, bucket=%s]", objectName, bucket));
	}
}
