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

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


/**
 * スタイルシート宣言。
 */
public class Property implements Serializable {
	private static final long serialVersionUID = 2L;
	/**
	 * !importantの文字列。
	 */
	public static final String	IMPORTANT = "!important";
	private String	name;
	private CSSValuable[]	value;
	private boolean	important_f;
	private Tag	embed_tag = HTMLPart.getDummyTag();

	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 Property getReplica() {
		CSSValuable[]	rep = new CSSValuable[value.length];
		for ( int i = 0; i < rep.length; i++ ) {
			rep[i] = (CSSValuable)value[i].getReplica();
		}
		return new Property( important_f, name, rep );
	}

	/**
	 * 宣言部の解析。
	 * @param str 宣言文字列。
	 * @param dec URLがあった場合のデコード文字コード。
	 */
	public static Property[] create( String str, String dec ) {
		str = str.trim();
		ArrayList<Property>	ret = new ArrayList<Property>();
		String[]	line = CSSParser.split( str, ';' );
		for ( int i = 0; i < line.length; i++ ) {
			String[]	part = CSSParser.split( line[i], ':' );
			ret.add( new Property( part[0].trim(), part[1].trim(), dec ) );
		}
		return ret.toArray( new Property[0] );
	}

	private Property() {}
	/**
	 * コンストラクタ。nは小文字に変換される。
	 * @param important true:important指定、false:importantではない。
	 * @param n 属性名。
	 * @param v 属性値。
	 * @param dec URLがあった場合のデコード文字コード。
	 */
	public Property( boolean important, String n, String v, String dec ) {
		setImportant( important );
		setName( n );
		set( v, dec );
	}

	/**
	 * コンストラクタ。nは小文字に変換される。
	 * importantは指定されません。
	 * @param n 属性名。
	 * @param v 属性値。
	 * @param dec URLがあった場合のデコード文字コード。
	 */
	public Property( String n, String v, String dec ) {
		this( false, n, v, dec );
	}

	/**
	 * コンストラクタ。nは小文字に変換される。
	 * @param important true:important指定、false:importantではない。
	 * @param n 属性名。
	 * @param v 属性値。
	 */
	public Property( boolean important, String n, CSSValuable ... v ) {
		setImportant( important );
		setName( n );
		set( v );
	}

	/**
	 * コンストラクタ。nは小文字に変換される。
	 * importantは指定されません。
	 * @param n 属性名。
	 * @param v 属性値。
	 */
	public Property( String n, CSSValuable ... v ) {
		this( false, n, v );
	}

	/**
	 * important宣言の設定。
	 * @param important true:important指定、false:importantではない。
	 */
	public void setImportant( boolean important ) {
		important_f = important;
		embed_tag.setModify();
	}

	/**
	 * important宣言の取得。
	 * @return true:important指定、false:importantではない。
	 */
	public boolean isImportant() {
		return important_f;
	}

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

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

	/**
	 * 属性値の設定。
	 * @param v 属性値。
	 * @param dec URLがあった場合のデコード文字コード。
	 */
	public void set( String v, String dec ) {
		if ( v == null ) {
			value = null;
			embed_tag.setModify();
			return;
		}
		String[]	str = CSSParser.split( CSSParser.split( v, ';' )[0], ' ' );
		ArrayList<CSSValuable>	list = new ArrayList<CSSValuable>();
		for ( int i = 0; i < str.length; i++ ) {
			str[i] = str[i].trim();
			if ( str[i].isEmpty() )	continue;
			if ( "!".equals( str[i] ) ) {
				if ( i < str.length - 1 ) {
					str[i + 1] = "!" + str[i + 1];
				}
				continue;
			}
			if ( IMPORTANT.equals( str[i] ) ) {
				setImportant( true );
				continue;
			}
			list.add( Converter.toCSSValuable( str[i], dec ) );
		}
		set( list.toArray( new CSSValuable[0] ) );
		embed_tag.setModify();
	}

	/**
	 * 属性値の設定。
	 * @param v 属性値。
	 */
	public void set( CSSValuable ... v ) {
		value = Converter.toCSSValuable( v );
		embed_tag.setModify();
	}

	/**
	 * 属性値の取得。
	 * @return 属性値。
	 */
	public CSSValuable[] get() {
		return value;
	}

	/**
	 * 属性値の取得。文字列を配列の形で返します。
	 * @return 属性値。
	 */
	private String[] getStringArray() {
		CSSValuable[]	t = get();
		if ( t == null )	return null;
		if ( t.length == 0 )	return null;
		String[]	ret = new String[t.length];
		for ( int i = 0; i < ret.length; i++ ) {
			ret[i] = t[i].toString( HTMLPart.StringMode.CSS );
		}
		return ret;
	}

	/**
	 * 属性値の取得。文字列で返します。
	 * 複数の値を持っている場合、スペース区切りで連結されます。
	 * @return 属性値。
	 */
	public String getString() {
		String[]	s = getStringArray();
		if ( s == null )	return null;
		StringBuilder	buf = new StringBuilder( s[0] );
		for ( int i = 1; i < s.length; i++ ) {
			buf = buf.append( " " );
			buf = buf.append( s[i] );
		}
		return buf.toString();
	}

	/**
	 * 文字列化。
	 * @return 文字列。
	 */
	public String toHtmlString() {
		StringBuilder	buf = new StringBuilder( name );
		buf = buf.append( ":" );
		buf = buf.append( getString() );
		buf = buf.append( ";" );
		return buf.toString();
	}

	/**
	 * 文字列化。
	 * @return 文字列。
	 */
	public String toString() {
		return toHtmlString();
	}
}

