/*
 * Paraselene
 * Copyright (c) 2009  Akira Terasaki
 * このファイルは同梱されているLicense.txtに定めた条件に同意できる場合にのみ
 * 利用可能です。
 */
package paraselene.tag;

import java.io.*;
import java.net.*;
import java.util.*;
import paraselene.*;
import paraselene.tag.*;
import paraselene.mockup.*;

/**
 * HTMLタグの属性。
 * スレッドセーフです。
 */
public class Attribute implements Serializable {
	private static final long serialVersionUID = 2L;
	private String	name;
	private AttributeValuable[]	value = null;
	private Tag embed_tag = HTMLPart.getDummyTag();

	protected Attribute() {}

	synchronized void setAssignedTag( Tag t ) {
		if ( t == null )	t = HTMLPart.getDummyTag();
		embed_tag = t;
		if ( value != null ) {
			for ( int i = 0; i < value.length; i++ ) {
				value[i].setAssignedTag( t );
			}
		}
	}
	/**
	 * 複製の作成。
	 * @return 複製。
	 */
	public Attribute getReplica() {
		AttributeValuable[]	attr = new AttributeValuable[value.length];
		for ( int  i = 0; i < attr.length; i++ ) {
			attr[i] = (AttributeValuable)value[i].getValuableReplica();
		}
		return new Attribute( name, attr );
	}

	/**
	 * コンストラクタ。nは小文字に変換される。
	 * @param n 属性名。
	 * @param v 属性値。
	 */
	public Attribute( String n, String v ) {
		setName( n );
		set( v );
	}

	/**
	 * コンストラクタ。nは小文字に変換される。
	 * 値を持たない属性を作成します。
	 * @param n 属性名。
	 */
	public Attribute( String n ) {
		setName( n );
	}

	/**
	 * コンストラクタ。nは小文字に変換される。
	 * @param n 属性名。
	 * @param v 属性値。
	 */
	public Attribute( String n, Valuable v ) {
		setName( n );
		set( v );
	}

	/**
	 * コンストラクタ。nは小文字に変換される。
	 * @param n 属性名。
	 * @param v 属性値。
	 */
	public Attribute( String n, Valuable ... v ) {
		setName( n );
		set( v );
	}

	/**
	 * 属性名の設定。nは小文字に変換される。
	 * @param n 属性名。
	 */
	protected void setName( String n ) {
		name = n.toLowerCase( Locale.ENGLISH );
		embed_tag.setModify();
	}

	/**
	 * 属性名の取得。小文字で返す。
	 * return 属性名。
	 */
	public String getName() {
		return name;
	}

	/**
	 * 属性値の設定。
	 * @param v 属性値。
	 */
	public void set( String v ) {
		set( null, v );
	}

	/**
	 * 属性値の設定。
	 * @param dec URIデコード文字コード。
	 * @param v 属性値。
	 */
	public void set( String dec, String v ) {
		value = Converter.toAttributeValuable( getName(), v, dec );
		setAssignedTag( embed_tag );
		embed_tag.setModify();
	}

	/**
	 * 属性値の設定。
	 * @param v 属性値。
	 */
	public void set( Valuable ... v ) {
		set( null, v );
	}

	/**
	 * 属性値の設定。
	 * @param dec URIデコード文字コード。
	 * @param v 属性値。
	 */
	public void set( String dec, Valuable ... v ) {
		value = Converter.toAttributeValuable( getName(), v, dec );
		setAssignedTag( embed_tag );
		embed_tag.setModify();
	}

	/**
	 * 属性値の取得。
	 * @return 属性値。無ければnull。
	 */
	public AttributeValuable[] getAll() {
		return value;
	}

	/**
	 * 最初に存在する属性値の取得。
	 * @return 属性値。無ければnull。
	 */
	public AttributeValuable get() {
		AttributeValuable[]	ret = getAll();
		if ( ret == null )	return null;
		if ( ret.length < 1 )	return null;
		return ret[0];
	}

	/**
	 * 属性値の取得。文字列で返します。
	 * @return 属性値。無ければnull。
	 */
	public String getString() {
		return getValueString();
	}

	/**
	 * 文字列生成。
	 * @return 値を出力用に正規化したもの。
	 */
	protected String getValueString() {
		AttributeValuable[]	v = getAll();
		if ( v == null )	return null;
		if ( v.length < 1 )	return null;
		StringBuilder	buf = new StringBuilder( v[0].toString( HTMLPart.StringMode.ATTRIBUTE ) );
		for ( int  i = 1; i < v.length; i++ ) {
			buf = buf.append( "," );
			buf = buf.append( v[i].toString( HTMLPart.StringMode.ATTRIBUTE ) );
		}
		return buf.toString();
	}

	/**
	 * 文字列化。
	 * @param xml true:xhtmlである、false:htmlである。
	 * @return 文字列。
	 */
	public String toHtmlString( boolean xml ) {
		StringBuilder	buf = new StringBuilder( name );
		if ( getValueString() != null ) {
			buf = buf.append( "=" );
			buf = buf.append( "\"" );
			buf = buf.append( getValueString() );
			buf = buf.append( "\"" );
		}
		else if ( xml ) {
			buf = buf.append( "=" );
			buf = buf.append( "\"" );
			buf = buf.append( name );
			buf = buf.append( "\"" );
		}
		return buf.toString();
	}

	/**
	 * 文字列化。xxx=xxx形式で返します。
	 * @return 文字列。
	 */
	public String toString() {
		try {
			return toHtmlString ( false );
		}
		catch( Exception e ) {
			return e.toString();
		}
	}
}

