package org.opengion.hayabusa.taglib;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;											// 6.4.3.4 (2016/03/11)
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.opengion.hayabusa.common.HybsSystem;
import org.opengion.hayabusa.common.HybsSystemException;
import org.opengion.hayabusa.db.DBTableModel;
import org.opengion.hayabusa.html.ViewForm;
import org.opengion.hayabusa.html.ViewFormFactory;
import org.opengion.hayabusa.io.JsChartData;
import org.opengion.fukurou.util.ArraySet;						// 6.4.3.4 (2016/03/11)
import org.opengion.fukurou.util.ToString;
import static org.opengion.fukurou.util.StringUtil.nval ;

/**
 * JsChart は、JavascriptのjsChart用のｽｸﾘﾌﾟﾄを出力するクラスです。
 * 複数の JsChartData オブジェクトを合成することも、ここで行っています。
 * ChartJSを利用しているため、標準属性以外の項目をセットする場合はoptionAttributesで行ってください。
 * 例えばアニメーションをOFFにする場合はanimation:falseをセットします。
 * 
 * 出力されるスクリプトでは、idを指定しない場合はhybscanvas[tableId]が利用されます。
 * 複数のグラフを同一画面で出力する場合はidかtableIdを変えてください。
 * チャートオブジェクトはchart_[id]という名前で作成されるため、ajax等でコントロールが必要な場合は利用してください。
 * 
 * @og.formSample
 * ●形式：&lt;og:column chartType="…" ... /&gt;
 * ●body：あり(EVAL_BODY_BUFFERED:BODYを評価し、{$#064;XXXX} を解析します)
 * 
 * ●Tag定義：
 *  &lt;og:jsChart
 *      chartType       ○【TAG】ﾁｬｰﾄの種類を指定します[line/bar/horizontalBar/radar/polarArea/pie/doughnut](必須)。
 *      labelColumn       【TAG】ﾗﾍﾞﾙのｶﾗﾑ名を指定します(表示名称）(必須)。
 *      id                【TAG】canvasﾀｸﾞのidを指定します(初期値:hybscanvas)。
 *      height            【TAG】ﾁｬｰﾄの高さを指定します(初期値:400)。
 *      width             【TAG】ﾁｬｰﾄの幅を指定します(初期値:400)。
 *      title             【TAG】ﾀｲﾄﾙを指定します。
 *      titlePosition     【TAG】ﾀｲﾄﾙの表示位置[top/right/bottom/left]を指定します(初期値:top)。
 *      xlabel            【TAG】x軸のラベルを指定します。
 *      ylabel            【TAG】y軸のラベルを指定します。
 *      legendPosition    【TAG】凡例の表示位置[top/right/bottom/left]を指定します(初期値:top)。
 *      legendDisplay     【TAG】凡例を表示するか[true/false]を指定します。
 *      xscaleCallback    【TAG】x軸ｺｰﾙﾊﾞｯｸを指定します。
 *      yscaleCallback    【TAG】y軸ｺｰﾙﾊﾞｯｸを指定します。
 *      xscaleType        【TAG】x軸のｽｹｰﾙﾀｲﾌﾟ[category/time/linear]を指定します(初期値:category)。
 *      yscaleType        【TAG】y軸のｽｹｰﾙﾀｲﾌﾟ[linear/category]を指定します(初期値:linear)。
 *      xmax              【TAG】x軸の最大値を指定します(xscaleTypeがlinearの場合に有効)。
 *      xmin              【TAG】x軸の最小値を指定します(xscaleTypeがlinearの場合に有効)。
 *      xstepSize         【TAG】x軸のメモリ幅を指定します(xscaleTypeがlinearの場合に有効)。
 *      timeUnit          【TAG】x軸のﾀｲﾑの単位[year/quarter/month/week/day/hour/minute/second/millsecond]を指定します(xscaleTypeがtimeの場合に有効。指定しない場合は自動)。
 *      timeUnitStepSize  【TAG】x軸のﾀｲﾑの単位幅を指定します。(xscaleTypeがtimeの場合に有効)
 *      timeSetFormat     【TAG】x軸の設定するﾀｲﾑのﾌｫｰﾏｯﾄを指定します(xscaleTypeがtimeの場合に有効)。
 *      timeLblFormat     【TAG】x軸の表示するﾀｲﾑのﾌｫｰﾏｯﾄを指定します(xscaleTypeがtimeの場合に有効)。
 *      timeMax           【TAG】x軸のﾀｲﾑの最大値を指定します(xscaleTypeがtimeの場合に有効)。
 *      timeMin           【TAG】x軸のﾀｲﾑの最小値を指定します(xscaleTypeがtimeの場合に有効)。
 *      ycategoryList     【TAG】y軸のﾒﾓﾘﾘｽﾄをカンマ区切りで指定します(xscaleTypeがlinearの場合に有効)
 *      max               【TAG】y軸の最大値を指定します(xscaleTypeがlinearの場合に有効)。
 *      min               【TAG】y軸の最小値を指定します(xscaleTypeがlinearの場合に有効)。
 *      stepSize          【TAG】y軸のメモリ幅を指定します(xscaleTypeがlinearの場合に有効)。
 *      barWidthPer       【TAG】棒線の横幅を指定します(初期値:0.8, typeがbar,horizontalBarの場合に有効)。
 *      onClick           【TAG】ﾁｬｰﾄｸﾘｯｸ時のｲﾍﾞﾝﾄを指定します。
 *      tableid           【TAG】(通常使いません)sessionから所得する DBTableModelオブジェクトの ID
 *      scope             【TAG】キャッシュする場合のスコープ[request/page/session/applicaton]を指定します(初期値:session)
 *      optionAttributes  【TAG】その他ｵﾌﾟｼｮﾝを指定します。
 *      caseKey           【TAG】このタグ自体を利用するかどうかの条件キーを指定します(初期値:null)
 *      caseVal           【TAG】このタグ自体を利用するかどうかの条件値を指定します(初期値:null)
 *      caseNN            【TAG】指定の値が、null/ゼロ文字列 でない場合(Not Null=NN)は、このタグは使用されます(初期値:判定しない)
 *      caseNull          【TAG】指定の値が、null/ゼロ文字列 の場合は、このタグは使用されます(初期値:判定しない)
 *      caseIf            【TAG】指定の値が、true/TRUE文字列の場合は、このタグは使用されます(初期値:判定しない)
 *      debug             【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false)
 *  &gt;   ... Body ...
 *  &lt;/og:jsChart&gt;
 *
 * ●使用例
 *      &lt;og:jsChart
 *          chartType      = "[line/bar/horizontalBar/radar/polarArea/pie/doughnut]"
 *          labelColumn    = "LDATA"
 *          id             = "hybscanvas"
 *          height         = "400"
 *          width          = "400"
 *          title          = "タイトル"
 *          titlePosition  = "top"				[top/right/bottom/left]
 *          ylabel         = "給料"
 *          xlabel         = "名称"
 *          legendPosition = "right"			[top/right/bottom/left]
 *          legendDisplay  = "true"				[true/false]
 *          xsclaeCallback = "function(value){return value + ' 様';}"
 *          ysclaeCallback = "function(value){return value.toLocaleString();}"
 *          xscaleType     = "time"
 *          max            = "1000000"
 *          min            = "100000"
 *          stepSize       = "10000"
 *          barWidthPer    = "0.4"
 *      &gt;
 *          &lt;og:jsChartData ... /&gt;
 *      &lt;/og:jsChart&gt;
 *      
 * @og.group 画面表示
 * 
 * @version	5.9.17.2		2017/02/08
 * @author	T.OTA
 * @since	JDK7.0
 *
 */
public class JsChartTag extends CommonTagSupport {
	//* このプログラムのVERSION文字列を設定します。{@value} */
	private static final String		VERSION				= "6.7.5.0 (2017/03/10)";
	private static final long		serialVersionUID	= 675020170310L;

	/** chartType 引数に渡す事の出来る タイプ 折れ線 {@value} **/
	public static final String		CTYPE_LINE			= "line";
	/** chartType 引数に渡す事の出来る タイプ 棒線 {@value} **/
	public static final String		CTYPE_BAR			= "bar";
	/** chartType 引数に渡す事の出来る タイプ 横棒線 {@value} **/
	public static final String		CTYPE_HBAR			= "horizontalBar";
	/** chartType 引数に渡す事の出来る タイプ レイダー {@value} **/
	public static final String		CTYPE_RADAR			= "radar";
	/** chartType 引数に渡す事の出来る タイプ ポーラエリア {@value} **/
	public static final String		CTYPE_PA			= "polarArea";
	/** chartType 引数に渡す事の出来る タイプ 円 {@value} **/
	public static final String		CTYPE_PIE			= "pie";
	/** chartType 引数に渡す事の出来る タイプ ドーナツ {@value} **/
	public static final String		CTYPE_DOUGHNUT		= "doughnut";
	/** chartType 引数に渡す事の出来る タイプ リスト {@value} */
//	private static final String[]	CTYPE_LIST		= new String[] { CTYPE_LINE, CTYPE_BAR, CTYPE_HBAR, CTYPE_RADAR, CTYPE_PA, CTYPE_PIE, CTYPE_DOUGHNUT };

	private static final Set<String> CTYPE_SET = new ArraySet<>( CTYPE_LINE, CTYPE_BAR, CTYPE_HBAR, CTYPE_RADAR, CTYPE_PA, CTYPE_PIE, CTYPE_DOUGHNUT );

	/** chartType が円形のリスト */
	private static final String[]	CTYPE_CI		= new String[] { CTYPE_RADAR, CTYPE_PA, CTYPE_PIE, CTYPE_DOUGHNUT };
//	private static final String[]	TYPE_POSITION	= new String[] { "top", "right", "bottom", "left" };
//	private static final String[]	TYPE_TIMEUNIT	= new String[] { "year", "quarter", "month", "week", "day", "hour", "minute", "second", "millsecond" };
//	private static final String[]	TYPE_XSCALE		= new String[] { "category", "time", "linear" };
//	private static final String[]	TYPE_YSCALE		= new String[] { "linear", "category" };
//	private static final String[]	TYPE_BOOLEAN	= new String[] { "true", "false" };

	private static final Set<String> TYPE_POSITION	= new ArraySet<>( "top", "right", "bottom", "left" );
	private static final Set<String> TYPE_TIMEUNIT	= new ArraySet<>( "year", "quarter", "month", "week", "day", "hour", "minute", "second", "millsecond" );
	private static final Set<String> TYPE_XSCALE	= new ArraySet<>( "category", "time", "linear" );
	private static final Set<String> TYPE_YSCALE	= new ArraySet<>( "linear", "category" );
	private static final Set<String> TYPE_BOOLEAN	= new ArraySet<>( "true", "false" );

	private static final String 	CANVAS_NAME		= "hybscanvas";
	
	// 変数宣言
	private List<JsChartData>		jsChartData	;					// jsChartDataのﾘｽﾄ
	private transient DBTableModel	table		;					// DBTableModelｸﾗｽ

	private String	chartType			;							// ﾁｬｰﾄﾀｲﾌﾟ(必須)
	private String	labelColumn			;							// ﾗﾍﾞﾙｶﾗﾑ(必須)
	private String	id					;							// canvasﾀｸﾞのid
	private String	height				= "400";					// canvasﾀｸﾞのheight
	private String	width				= "400";					// canvasﾀｸﾞのwidth
	private String	title				;							// ﾀｲﾄﾙ
	private String	titlePosition		;							// ﾀｲﾄﾙ位置
	private String	xlabel				;							// x軸ﾗﾍﾞﾙ
	private String	ylabel				;							// y軸ﾗﾍﾞﾙ
	private String	legendPosition		;							// 凡例位置
	private String	legendDisplay		;							// 凡例表示ﾌﾗｸﾞ
	private String	xscaleCallback		;							// x軸のﾒﾓﾘ編集用ｺｰﾙﾊﾞｯｸ
	private String	yscaleCallback		;							// y軸のﾒﾓﾘ編集用ｺｰﾙﾊﾞｯｸ
	private String	xscaleType			;							// x軸のｽｹｰﾙﾀｲﾌﾟ
	private String	yscaleType			;							// y軸のｽｹｰﾙﾀｲﾌﾟ
	private String	xmax				;							// x軸の最大値(ﾘﾆｱｽｹｰﾙ用)
	private String	xmin				;							// x軸の最小値(ﾘﾆｱｽｹｰﾙ用)
	private String	xstepSize			;							// x軸のﾒﾓﾘ幅(ﾘﾆｱｽｹｰﾙ用)
	private String	timeUnit			;							// 時間の単位(ﾀｲﾑｽｹｰﾙ用)
	private String	timeUnitStepSize	;							// 時間のﾒﾓﾘ幅(ﾀｲﾑｽｹｰﾙ用)
	private String	timeSetFormat		;							// 時間の入力ﾌｫｰﾏｯﾄ(ﾀｲﾑｽｹｰﾙ用)
	private String	timeLblFormat		;							// 時間の表示ﾌｫｰﾏｯﾄ(ﾀｲﾑｽｹｰﾙ用)
	private String	timeMax				;							// 最大の時間(ﾀｲﾑｽｹｰﾙ用)
	private String	timeMin				;							// 最小の時間(ﾀｲﾑｽｹｰﾙ用)
	private String	ycategoryList		;							// y軸のｶﾃｺﾞﾘｰﾘｽﾄ(ｶﾃｺﾞﾘｰｽｹｰﾙ用)
	private String	max					;							// y軸の最大値(ﾘﾆｱｽｹｰﾙ用)
	private String	min					;							// y軸の最小値(ﾘﾆｱｽｹｰﾙ用)
	private String	stepSize			;							// y軸のﾒﾓﾘ幅(ﾘﾆｱｽｹｰﾙ用)
	private String	barWidthPer			= "0.8";					// 棒線の横幅(ﾊﾟｰｾﾝﾄ)
	private String	onClick				;							// ｸﾘｯｸｲﾍﾞﾝﾄ
	private String	tableId				= HybsSystem.TBL_MDL_KEY;	// ﾃｰﾌﾞﾙid
//	private String	scope				= "session";				// ｽｺｰﾌﾟ
	private String	optionAttributes	;							// ｵﾌﾟｼｮﾝ

	/**
	 * タグリブオブジェクトをリリースします。
	 * キャッシュされて再利用されるので、フィールドの初期設定を行います。
	 * 
	 */
	@Override
	protected void release2() {
		super.release2();
		chartType			= null;
		id					= null;
		height				= "400";
		width				= "400";
		labelColumn			= null;
		title				= null;
		titlePosition		= null;
		xlabel				= null;
		ylabel				= null;
		legendPosition		= null;
		legendDisplay		= null;
		xscaleCallback		= null;
		yscaleCallback		= null;
		xscaleType			= null;
		yscaleType			= null;
		xmax				= null;
		xmin				= null;
		xstepSize			= null;
		timeUnit			= null;
		timeUnitStepSize	= null;
		timeSetFormat		= null;
		timeLblFormat		= null;
		timeMax				= null;
		timeMin				= null;
		ycategoryList		= null;
		max					= null;
		min					= null;
		stepSize			= null;
		barWidthPer			= "0.8";
		onClick				= null;
		tableId				= HybsSystem.TBL_MDL_KEY;
//		scope				= "session";
		optionAttributes	= null;
	}

	/**
	 * Taglibの開始タグが見つかった時に処理する doStartTag() を オーバーライドします。
	 * 
	 * @og.rev 6.7.5.0 (2017/03/10) タグの使用を決める共通属性の追加
	 * 
	 * @return 後続処理の指示
	 */
	@Override
	public int doStartTag() {
		if( !useTag() ) { return SKIP_BODY ; }		// 6.7.5.0 (2017/03/10)

		// ﾁｪｯｸ処理の実行
		checkData();

//		// ｽｺｰﾌﾟの設定
//		super.setScope( scope );

		// ﾃｰﾌﾞﾙ情報の取得
		table = (DBTableModel)getObject( tableId );

		return EVAL_BODY_BUFFERED; // Bodyを評価する
	}

	/**
	 * ﾁｪｯｸ処理。
	 */
	private void checkData() {
		// xscaleTypeに「linear」、yscaleTypeに「category」を指定した場合は、エラー
		if( "linear".equals( xscaleType ) && "category".equals( yscaleType ) ) {
			final StringBuilder errMsg = new StringBuilder( BUFFER_MIDDLE )
				.append( "指定のｽｹｰﾙﾀｲﾌﾟの組み合わせは実行できません。" )
				.append( CR )
				.append( "xscaleType:" ).append( xscaleType ).append( " yscaleType:" ).append( yscaleType );

			throw new HybsSystemException( errMsg.toString() );
		}
	}

	/**
	 * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。
	 * 
	 * @og.rev 6.7.5.0 (2017/03/10) タグの使用を決める共通属性の追加
	 * 
	 * @return 後続処理の指示
	 */
	@Override
	public int doEndTag() {
		debugPrint();
		if( !useTag() ) { return EVAL_PAGE ; }			// 6.7.5.0 (2017/03/10)

		id = (id==null ? CANVAS_NAME + tableId : id );	// id指定なしの場合はCANVAS_NAME+tableId

		// jsChart出力
		jspPrint( jsChartOutput() );

		return EVAL_PAGE;
	}

	/**
	 * jsChart出力用
	 * jsChartTag と jsChartData を使用して、jsChart情報を出力します。
	 * 
	 * @return jsChert用文字列
	 */
	private String jsChartOutput() {
		final StringBuilder rtn = new StringBuilder( BUFFER_MIDDLE );

		// 各JavaScriptの変数名
		final String qd			= "qd_" + id;		//queryData
		final String cd			= "cd_" + id;		//chartData
		final String myChart	= "chart_"+id;
		final String lblClm		= labelColumn + id;

		// JSON形式でﾃｰﾌﾞﾙ情報を取得
		final ViewForm form = ViewFormFactory.newInstance( "JSON" );
		form.init( table );

		// canvasﾀｸﾞの設定
		rtn.append( "<canvas class=\"").append( CANVAS_NAME)
			.append( "\" id=\""			).append( id     )
			.append( "\" width=\""		).append( width  )
			.append( "\" height=\""		).append( height )
			.append( "\"><!-- --></canvas>" );

		rtn.append( "<script>" )
		// query情報の取得(JSON)
			.append( "var ").append( qd ).append(" = " ).append( form.create() );

		// jsChartDataﾀｸﾞの変数宣言
		for( int i=0; i<jsChartData.size(); i++ ) {
			rtn.append( " var " ).append( jsChartData.get( i ).getChartColumn() ).append( " = [];" );
		}
		rtn.append( "var " ).append( lblClm ).append( " = [];" );

		// query情報をjsChartDataの変数に入れ替え 
		rtn.append( "for(var i=0; i < ").append( qd ).append( ".DATA.length; i++){" );
		for( int i = 0; i < jsChartData.size(); i++ ) {
			final String chartColumn = jsChartData.get( i ).getChartColumn();

			// x軸がlinearｽｹｰﾙの場合
			if( "linear".equals( xscaleType ) ) {
				// {x:ﾗﾍﾞﾙ, y:値}の形式で値を設定
				rtn.append(  chartColumn ).append( "[i] = {x:" ).append( qd ).append( ".DATA[i]." )
					.append( labelColumn ).append( ",y:"       ).append( qd ).append( ".DATA[i]." )
					.append( chartColumn ).append( "};" );
			}
			else {
				// その他は値を設定
				rtn.append(  chartColumn ).append( "[i] = " ).append(qd).append( ".DATA[i]." )
					.append( chartColumn ).append( ";" );
			}
		}
		rtn.append(  lblClm      ).append( "[i] = ").append( qd ).append( ".DATA[i]." )
			.append( labelColumn ).append( ";" ).append( "}" );

		// y軸にｶﾃｺﾞﾘｰｽｹｰﾙを設定した場合
		if( "category".equals( yscaleType ) ) {
			rtn.append( "var ycateList = [];" );
			if( ycategoryList != null && ycategoryList.length() > 0 ) {
				// 「,」を「','」に変換して設定。(,前後の半角ｽﾍﾟｰｽは除去する)
				final String regex = " *, *";
				final Pattern pttn = Pattern.compile( regex );

				final Matcher mtch = pttn.matcher( ycategoryList );
				// y軸ｶﾃｺﾞﾘｰﾘｽﾄの設定
				rtn.append( "ycateList = ['" ).append( mtch.replaceAll( "','" ) ).append( "'];" );
			}
		}

		// jsChartDataの設定
		rtn.append( "var ").append( cd ).append(" = {" )
			.append( "labels:" ).append( lblClm );
		// y軸にｶﾃｺﾞﾘｰｽｹｰﾙを設定した場合
		if( "category".equals( yscaleType ) ) {
			rtn.append( ",yLabels:ycateList" );
		}
		rtn.append( ",datasets:[" );
		for( int i = 0; i < jsChartData.size(); i++ ) {
			if( i != 0 ) {
				rtn.append( "," );
			}
			rtn.append( jsChartData.get( i ).getParameter() );
		}
		rtn.append( "]};" );

		// jsChartの生成
		rtn.append(  "var "   ).append( myChart   ).append(" = new Chart(" ).append( id ).append( ",{" )
			.append( "type:'" ).append( chartType ).append( "'" )
			.append( ",data:" ).append( cd )
			.append( ",options:{" )
			.append( "responsive:false" );	// ﾚｽﾎﾟﾝｼﾌﾞ OFF
//		rtn.append( ",animation:false" );	// ｱﾆﾒｰｼｮﾝ OFF

		// ｸﾘｯｸｲﾍﾞﾝﾄの設定
		if( onClick != null && onClick.length() > 0 ) {
			rtn.append( ",onClick:function(event,obj){" ).append( onClick ).append( "}" );
		}

		// ﾀｲﾄﾙ属性の設定
		if( title != null && title.length() > 0 ) {
			rtn.append( ",title:{" ).append( "display:true" );
			setProp( rtn, ",text:'"    , title        , "'" );
			setProp( rtn, ",position:'", titlePosition, "'" );
			rtn.append( "}" );
		}

		// ﾒﾓﾘ属性の設定
		rtn.append( ",legend:{" );
		setProp( rtn, "display:"  , legendDisplay , "," );
		setProp( rtn, "position:'", legendPosition, "'" );
		rtn.append( "}" );

		// chartTypeの円形ﾁｪｯｸ
		final List<String> list = Arrays.asList( CTYPE_CI );
		if( list.contains( chartType ) ) {
			// 円形の場合はscale属性に値を設定
			rtn.append( ",scale: {ticks:{beginAtZero:true" );
			setProp( rtn, ",max:"     , max );
			setProp( rtn, ",min:"     , min );
			setProp( rtn, ",stepSize:", stepSize );
			rtn.append( "}}" );
		}
		else {
			// 円形以外の場合はscales属性に設定
			rtn.append( ",scales:{" );
			if( CTYPE_HBAR.equals( chartType ) ) {
				// 横棒線の場合はx軸の設定
				rtn.append( "xAxes" );
			}
			else {
				// それ以外はy軸の設定
				rtn.append( "yAxes" );
			}
			rtn.append( ":[{" );
			setProp( rtn, "type:'", yscaleType, "'," );
			// y軸にｶﾃｺﾞﾘｰｽｹｰﾙを設定した場合
			if( "category".equals( yscaleType )) {
				rtn.append( "position:'left'," );
			}
			if(ylabel != null && ylabel.length() > 0 ){
				rtn.append( "scaleLabel: {" )
					.append( "display: true," )
					.append( "labelString: '" ).append( ylabel ).append( "'" )
					.append( "}," );
			}
			rtn.append( "ticks:{beginAtZero:true" );
			setProp( rtn, ",max:"     , max );
			setProp( rtn, ",min:"     , min );
			setProp( rtn, ",stepSize:", stepSize );
			setProp( rtn, ",callback:", yscaleCallback );
			rtn.append( "}}]," );

			if( CTYPE_HBAR.equals( chartType ) ) {
				// 横棒線の場合はy軸の設定
				rtn.append( "yAxes" );
			}
			else {
				// それ以外はx軸の設定
				rtn.append( "xAxes" );
			}
			rtn.append( ":[{" );
			setProp( rtn, "type:'"             , xscaleType , "'," );
			setProp( rtn, "categoryPercentage:", barWidthPer, ","  );
			// x軸にﾘﾆｱｽｹｰﾙを設定した場合
			if( "linear".equals( xscaleType ) ) {
				rtn.append( "position:'bottom'," );
			}
			// ﾁｬｰﾄﾀｲﾌﾟが横棒線の場合
			if(  CTYPE_HBAR.equals( chartType ) ){
				rtn.append( "position:'left'," );
			}
			
			if(xlabel != null && xlabel.length() > 0 ){
				rtn.append(  "scaleLabel: {" )
					.append( "display: true," )
					.append( "labelString: '" ).append( xlabel ).append("'")
					.append( "}," );
			}
			rtn.append( "time:{" );
			setProp( rtn, "format:'", timeSetFormat, "'," );
			// timeLblFormatが指定されている場合、全てのdisplayFormatsにtimeLblFormatを設定する
			if( timeLblFormat != null && timeLblFormat.length() > 0 ) {
				rtn.append(  "displayFormats:{year:'" ).append( timeLblFormat )
					.append( "',quarter:'" ).append( timeLblFormat )
					.append( "',month:'"   ).append( timeLblFormat )
					.append( "',week:'"    ).append( timeLblFormat )
					.append( "',day:'"     ).append( timeLblFormat )
					.append( "',hour:'"    ).append( "',minute:'"      ).append( timeLblFormat )
											.append( "',second:'"      ).append( timeLblFormat )
											.append( "',millisecond:'" ).append( "'}," );
			}
			setProp( rtn, "max:'"        , timeMax , "'," );
			setProp( rtn, "min:'"        , timeMin , "'," );
			setProp( rtn, "unit:'"       , timeUnit, "'," );
			setProp( rtn, "unitStepSize:", timeUnitStepSize );
			rtn.append( "}," );

			rtn.append( "ticks:{" );
			setProp( rtn, "callback:", xscaleCallback, "," );
			// x軸にﾘﾆｱｽｹｰﾙを設定した場合
			if( "linear".equals( xscaleType ) ) {
				rtn.append( "beginAtZero:true," );
				setProp( rtn, "max:"     , xmax, "," );
				setProp( rtn, "min:"     , xmin, "," );
				setProp( rtn, "stepSize:", xstepSize );
			}
			rtn.append( "}}]" )
				.append( "}" );
		}
		setProp( rtn, ",", optionAttributes );

		rtn.append( "}});" )
			.append( "</script>" );

		return rtn.toString();
	}

	/**
	 * setに値が存在する場合、sbにstr + setの形で値を追加する。
	 * 
	 * @param sb	ベースとなるStringBuilder
	 * @param str	文字列１
	 * @param set	文字列２
	 */
	private void setProp( final StringBuilder sb, final String str, final String set ) {
		if( set != null && set.length() > 0 ) {
			sb.append( str ).append( set );
		}
	}

	/**
	 * setに値が存在する場合、sbにstr + set + endの形で値を追加する。
	 * 
	 * @param sb	ベースとなるStringBuilder
	 * @param str	文字列１
	 * @param set	文字列２
	 * @param end	文字列３
	 */
	private void setProp( final StringBuilder sb, final String str, final String set, final String end ) {
		if( set != null && set.length() > 0 ) {
			sb.append( str ).append( set ).append( end );
		}
	}

	/**
	 * ﾊﾟﾗﾒｰﾀﾁｪｯｸ用ﾒｿｯﾄﾞ。
	 * 
	 * @param trg		ターゲット
	 * @param set		使用可能なキーワードのSet
	 * @param trgStr	ターゲットの名称
	 */
//	private void checkPara( String trg, String[] list, String trgStr ) {
	private void checkPara( final String trg, final Set<String> set, final String trgStr ) {
//		if( trg != null && trg.length() > 0 && !check( trg, list ) ) {
		if( trg != null && trg.length() > 0 && !check( trg, set ) ) {
			final StringBuilder errMsg = new StringBuilder( BUFFER_MIDDLE )
				.append( "指定の" ).append( trgStr ).append( "は指定できません。" )
				.append( CR )
				.append( trgStr ).append( "=[" ).append( trg ).append( "]" )
				.append( CR );
			for( final String lst : set ) {
				errMsg.append( " | " );
				errMsg.append( lst );
			}
//			for( int i = 0; i < list.length; i++ ) {
//				errMsg.append( " | " );
//				errMsg.append( list[i] );
//			}
			throw new HybsSystemException( errMsg.toString() );
		}
	}

	/**
	 * 【TAG】ﾁｬｰﾄの種類を指定します[line/bar/horizontalBar/radar/polarArea/pie/doughnut](必須)。
	 *
	 * @og.tag
	 * 
	 * @param cType ﾁｬｰﾄﾀｲﾌﾟ [line/bar/horizontalBar/radar/polarArea/pie/doughnut]
	 */
	public void setChartType( final String cType ) {
		chartType = getRequestParameter( cType );

//		if( chartType != null && !check( chartType, CTYPE_LIST ) ) {
		if( chartType != null && !check( chartType, CTYPE_SET ) ) {
			final StringBuilder errMsg = new StringBuilder( BUFFER_MIDDLE )
				.append( "指定のチャートタイプは実行できません。"        ).append( CR )
				.append( "chartType=[" ).append( chartType ).append( "]" ).append( CR );
			for( final String lst : CTYPE_SET ) {
				errMsg.append( " | " ).append( lst );
			}
//			for( int i = 0; i < CTYPE_LIST.length; i++ ) {
//				errMsg.append( " | " );
//				errMsg.append( CTYPE_LIST[i] );
//			}
			throw new HybsSystemException( errMsg.toString() );
		}
	}

	/**
	 * 【TAG】canvasﾀｸﾞのidを指定します(初期値:hybscanvas)。
	 *
	 * @og.tag
	 * canvasﾀｸﾞのidに設定します。
	 * 
	 * @param id canvasﾀｸﾞのid
	 */
	@Override
	public void setId( final String id ) {
		this.id = nval( getRequestParameter( id ),this.id );

//		String temp = getRequestParameter( id );
//		if( temp != null && temp.length() > 0 ) {
//			this.id = temp;
//		}
	}

	/**
	 * 【TAG】ﾁｬｰﾄの高さを指定します(初期値:400)。
	 *
	 * @og.tag
	 * canvasﾀｸﾞの高さに設定します。
	 * 
	 * @param hei 設定する高さ
	 */
	public void setHeight( final String hei ) {
		height = nval( getRequestParameter( hei ),height );

//		String temp = getRequestParameter( hei );
//		if( temp != null && temp.length() > 0 ) {
//			height = temp;
//		}
	}

	/**
	 * 【TAG】ﾁｬｰﾄの幅を指定します(初期値:400)。
	 *
	 * @og.tag
	 * canvasﾀｸﾞの横幅を設定します。
	 * 
	 * @param wid 設定する横幅
	 */
	public void setWidth( final String wid ) {
		width = nval( getRequestParameter( wid ),width );

//		String temp = getRequestParameter( wid );
//		if( wid != null && wid.length() > 0 ) {
//			width = temp;
//		}
	}

	/**
	 * 【TAG】ﾗﾍﾞﾙのｶﾗﾑ名を指定します(表示名称）(必須)。
	 *
	 * @og.tag
	 * 
	 * @param lblclm ﾗﾍﾞﾙｶﾗﾑ
	 */
	public void setLabelColumn( final String lblclm ) {
		labelColumn = nval( getRequestParameter( lblclm ),labelColumn );
	}

	/**
	 * 【TAG】ﾀｲﾄﾙを指定します。
	 *
	 * @og.tag
	 * 
	 * @param title ﾀｲﾄﾙ
	 */
	public void setTitle( final String title ) {
		this.title = getRequestParameter( title );
	}

	/**
	 * 【TAG】ﾀｲﾄﾙの表示位置[top/right/bottom/left]を指定します(初期値:top)。
	 *
	 * @og.tag
	 * 
	 * @param titlePosition ﾀｲﾄﾙの表示位置
	 */
	public void setTitlePosition( final String titlePosition ) {
		this.titlePosition = getRequestParameter( titlePosition );

		checkPara( this.titlePosition, TYPE_POSITION, "titlePosition" );
	}

	/**
	 * 【TAG】x軸のラベルを指定します。
	 *
	 * @og.tag
	 * 
	 * @param xlabel x軸のラベル
	 */
	public void setXlabel( final String xlabel ) {
		this.xlabel = getRequestParameter( xlabel );
	}

	/**
	 * 【TAG】y軸のラベルを指定します。
	 *
	 * @og.tag
	 * 
	 * @param ylabel y軸のラベル
	 */
	public void setYlabel( final String ylabel ) {
		this.ylabel = getRequestParameter( ylabel );
	}

	/**
	 * 【TAG】凡例の表示位置[top/right/bottom/left]を指定します(初期値:top)。
	 *
	 * @og.tag
	 * 
	 * @param legendPosition 凡例の表示位置
	 */
	public void setLegendPosition( final String legendPosition ) {
		this.legendPosition = getRequestParameter( legendPosition );

		checkPara( this.legendPosition, TYPE_POSITION, "legendPosition" );
	}

	/**
	 * 【TAG】凡例を表示するか[true/false]を指定します。
	 *
	 * @og.tag
	 * 
	 * @param legendDisplay 凡例を表示するか [true/false]
	 */
	public void setLegendDisplay( final String legendDisplay ) {
		this.legendDisplay = getRequestParameter( legendDisplay );

		checkPara( this.legendDisplay, TYPE_BOOLEAN, "legendDisplay" );
	}

	/**
	 * 【TAG】x軸ｺｰﾙﾊﾞｯｸを指定します。
	 *
	 * @og.tag
	 * x軸のメモリ編集用スケールバックを設定します。
	 * 
	 * @param xscaleCallback x軸ｺｰﾙﾊﾞｯｸ
	 */
	public void setXscaleCallback( final String xscaleCallback ) {
		this.xscaleCallback = getRequestParameter( xscaleCallback );
	}

	/**
	 * 【TAG】y軸ｺｰﾙﾊﾞｯｸを指定します。
	 *
	 * @og.tag
	 * y軸のメモリ編集用スケールバックを設定します。
	 * 
	 * @param yscaleCallback y軸ｺｰﾙﾊﾞｯｸ
	 */
	public void setYscaleCallback( final String yscaleCallback ) {
		this.yscaleCallback = getRequestParameter( yscaleCallback );
	}

	/**
	 * 【TAG】x軸のｽｹｰﾙﾀｲﾌﾟ[category/time/linear]を指定します(初期値:category)。
	 *
	 * @og.tag
	 * 
	 * @param xscaleType x軸のｽｹｰﾙﾀｲﾌﾟ
	 */
	public void setXscaleType( final String xscaleType ) {
		this.xscaleType = getRequestParameter( xscaleType );

		checkPara( this.xscaleType, TYPE_XSCALE, "xscaleType" );
	}

	/**
	 * 【TAG】y軸のｽｹｰﾙﾀｲﾌﾟ[linear/category]を指定します(初期値:linear)。
	 *
	 * @og.tag
	 * 
	 * @param yscaleType y軸のｽｹｰﾙﾀｲﾌﾟ
	 */
	public void setYscaleType( final String yscaleType ) {
		this.yscaleType = getRequestParameter( yscaleType );

		checkPara( this.yscaleType, TYPE_YSCALE, "yscaleType" );
	}

	/**
	 * 【TAG】y軸のﾒﾓﾘﾘｽﾄをカンマ区切りで指定します(xscaleTypeがlinearの場合に有効)。
	 *
	 * @og.tag
	 * 
	 * @param ycategoryList y軸のﾒﾓﾘﾘｽﾄ
	 */
	public void setYcategoryList( final String ycategoryList ) {
		this.ycategoryList = getRequestParameter( ycategoryList );
	}

	/**
	 * 【TAG】x軸の最大値を指定します(xscaleTypeがlinearの場合に有効)。
	 *
	 * @og.tag
	 * 
	 * @param xmax x軸の最大値
	 */
	public void setXmax( final String xmax ) {
		this.xmax = getRequestParameter( xmax );
	}

	/**
	 * 【TAG】x軸の最小値を指定します(xscaleTypeがlinearの場合に有効)。
	 *
	 * @og.tag
	 * 
	 * @param xmin x軸の最小値
	 */
	public void setXmin( final String xmin ) {
		this.xmin = getRequestParameter( xmin );
	}

	/**
	 * 【TAG】x軸のメモリ幅を指定します(xscaleTypeがlinearの場合に有効)。
	 *
	 * @og.tag
	 * 
	 * @param xstepSize x軸のメモリ幅
	 */
	public void setXstepSize( final String xstepSize ) {
		this.xstepSize = getRequestParameter( xstepSize );
	}

	/**
	 * 【TAG】棒線の横幅を指定します(初期値:0.8, typeがbar,horizontalBarの場合に有効)。
	 *
	 * @og.tag
	 * 
	 * @param barWidthPer 棒線の横幅
	 */
	public void setBarWidthPer( final String barWidthPer ) {
		this.barWidthPer = getRequestParameter( barWidthPer );
	}

	/**
	 * jsChartData情報をﾘｽﾄに追加します。
	 * ﾘｽﾄが存在しない場合は、新しく作成します。
	 * 
	 * @param jsData jsChartData情報
	 */
//	public void addJsChartData( final JsChartData jsData ) {
	protected void addJsChartData( final JsChartData jsData ) {
		if( jsChartData == null ) {
			jsChartData = new ArrayList<JsChartData>();
		}
		jsChartData.add( jsData );
	}

	/**
	 * 【TAG】x軸のﾀｲﾑの単位[year/quarter/month/week/day/hour/minute/second/millsecond]を指定します。
	 *
	 * @og.tag
	 * (xscaleTypeがtimeの場合に有効。指定しない場合は自動)
	 * 
	 * @param timeUnit x軸のﾀｲﾑの単位
	 */
	public void setTimeUnit( final String timeUnit ) {
		this.timeUnit = getRequestParameter( timeUnit );

		checkPara( this.timeUnit, TYPE_TIMEUNIT, "timeUnit" );
	}

	/**
	 * 【TAG】x軸のﾀｲﾑの単位幅を指定します(xscaleTypeがtimeの場合に有効)。
	 *
	 * @og.tag
	 * 
	 * @param timeUnitStepSize x軸のﾀｲﾑの単位幅
	 */
	public void setTimeUnitStepSize( final String timeUnitStepSize ) {
		this.timeUnitStepSize = getRequestParameter( timeUnitStepSize );
	}

	/**
	 * 【TAG】x軸の設定するﾀｲﾑのﾌｫｰﾏｯﾄを指定します(xscaleTypeがtimeの場合に有効)。
	 *
	 * @og.tag
	 * 
	 * @param timeSetFormat x軸の設定するﾀｲﾑのﾌｫｰﾏｯﾄ
	 */
	public void setTimeSetFormat( final String timeSetFormat ) {
		this.timeSetFormat = getRequestParameter( timeSetFormat );
	}

	/**
	 * 【TAG】x軸の表示するﾀｲﾑのﾌｫｰﾏｯﾄを指定します(xscaleTypeがtimeの場合に有効)。
	 *
	 * @og.tag
	 * 
	 * @param timeLblFormat x軸の表示するﾀｲﾑのﾌｫｰﾏｯﾄ
	 */
	public void setTimeLblFormat( final String timeLblFormat ) {
		this.timeLblFormat = getRequestParameter( timeLblFormat );
	}

	/**
	 * 【TAG】x軸のﾀｲﾑの最大値を指定します(xscaleTypeがtimeの場合に有効)。
	 *
	 * @og.tag
	 * 
	 * @param timeMax x軸のﾀｲﾑの最大値
	 */
	public void setTimeMax( final String timeMax ) {
		this.timeMax = getRequestParameter( timeMax );
	}

	/**
	 * 【TAG】x軸のﾀｲﾑの最小値を指定します(xscaleTypeがtimeの場合に有効)。
	 *
	 * @og.tag
	 * 
	 * @param timeMin x軸のﾀｲﾑの最小値
	 */
	public void setTimeMin( final String timeMin ) {
		this.timeMin = getRequestParameter( timeMin );
	}

	/**
	 * 【TAG】y軸の最大値を指定します(xscaleTypeがlinearの場合に有効)。
	 *
	 * @og.tag
	 * 
	 * @param max メモリの最大値
	 */
	public void setMax( final String max ) {
		this.max = nval( getRequestParameter( max ) , this.max );
	}

	/**
	 * 【TAG】y軸の最小値を指定します(xscaleTypeがlinearの場合に有効)。
	 *
	 * @og.tag
	 * 
	 * @param min メモリの最小値
	 */
	public void setMin( final String min ) {
		this.min = nval( getRequestParameter( min ) , this.min );
	}

	/**
	 * 【TAG】y軸のメモリ幅を指定します(xscaleTypeがlinearの場合に有効)。
	 *
	 * @og.tag
	 * 
	 * @param stepSize y軸のメモリ幅
	 */
	public void setStepSize( final String stepSize ) {
		this.stepSize = nval( getRequestParameter( stepSize ) , this.stepSize );
	}

	/**
	 * 【TAG】ﾁｬｰﾄｸﾘｯｸ時のｲﾍﾞﾝﾄを指定します。
	 *
	 * @og.tag
	 * 下記の値が引数として渡されます。
	 * 
	 * event:ｲﾍﾞﾝﾄ情報 
	 * obj:ｸﾘｯｸされたｵﾌﾞｼﾞｪｸﾄの情報
	 * 
	 * @param click チャートクリック時のイベントを指定
	 */
	public void setOnClick( final String click ) {
		onClick = nval( getRequestParameter( click ),onClick );
	}

	/**
	 * 【TAG】(通常使いません)sessionから所得する DBTableModelオブジェクトの ID。
	 *
	 * @og.tag
	 * 
	 * @param tableId テーブルID
	 */
	public void setTableId( final String tableId ) {
		this.tableId = getRequestParameter( tableId );
	}

//	/**
//	 * 【TAG】キャッシュする場合のスコープ[request/page/session/applicaton]を指定します(初期値:session)
//	 *
//	 * @og.tag
//	 * 
//	 * @param scope ﾃｰﾌﾞﾙｽｺｰﾌﾟ
//	 */
//	public void setScope( final String scope ) {
//		this.scope = getRequestParameter( scope );
//	}

	/**
	 * 【TAG】オプション情報を指定します。
	 *
	 * @og.tag
	 *  
	 * @param attri オプションの値
	 */
	public void setOptionAttributes( final String attri ) {
		optionAttributes = nval( getRequestParameter( attri ),optionAttributes );
	}

	/**
	 * このオブジェクトの文字列表現を返します。
	 * 基本的にデバッグ目的に使用します。
	 * 
	 * @return このクラスの文字列表現
	 */
	@Override
	public String toString() {
		// JSON形式でﾃｰﾌﾞﾙ情報を取得
		final ViewForm form = ViewFormFactory.newInstance( "JSON" );
		form.init( table );

		// jsChartDataのﾊﾟﾗﾒｰﾀ情報
		final StringBuilder sb = new StringBuilder( BUFFER_MIDDLE );
		for( int i = 0; i < jsChartData.size(); i++ ) {
			sb.append( " jsChartData" ).append( i ).append( ":" ).append( jsChartData.get( i ).getParameter() );
		}

//		return org.opengion.fukurou.util.ToString.title( this.getClass().getName() )
		return ToString.title( this.getClass().getName() )
			.println( "VERSION"				, VERSION				)
			.println( "id"					, id					)
			.println( "tableId"				, tableId				)
//			.println( "scope"				, scope					)
			.println( "chartType"			, chartType				)
			.println( "width"				, width					)
			.println( "height"				, height				)
			.println( "max"					, max					)
			.println( "min"					, min					)
			.println( "stepSize"			, stepSize				)
			.println( "barWidthPer"			, barWidthPer			)
			.println( "timeUnit"			, timeUnit				)
			.println( "timeUnitStepSize"	, timeUnitStepSize		)
			.println( "timeLblFormat"		, timeLblFormat			)
			.println( "timeSetFormat"		, timeSetFormat			)
			.println( "timeMax"				, timeMax				)
			.println( "timeMin"				, timeMin				)
			.println( "title"				, title					)
			.println( "titlePosition"		, titlePosition			)
			.println( "xlabel"				, xlabel				)
			.println( "ylabel"				, ylabel				)
			.println( "legendPosition"		, legendPosition		)
			.println( "legendDisplay"		, legendDisplay			)
			.println( "yscaleCallback"		, yscaleCallback		)
			.println( "xscaleCallback"		, xscaleCallback		)
			.println( "xscaleType"			, xscaleType			)
			.println( "xmax"				, xmax					)
			.println( "xmin"				, xmin					)
			.println( "xstepSize"			, xstepSize				)
			.println( "yscaleType"			, yscaleType			)
			.println( "ycategoryList"		, ycategoryList			)
			.println( "optionAttributes"	, optionAttributes		)
			.println( "JSON"				, form.create()			)
			.println( "jsChartDataPara"		, sb.toString()			)
			.fixForm().toString();
	}
}
