package org.opengion.hayabusa.taglib;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
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.html.ViewJsonParam;
import org.opengion.hayabusa.io.JsChartData;
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】ﾁｬｰﾄの種類を指定します。(必須)
 *      id                【TAG】canvasﾀｸﾞのidを指定します。(初期値:hybscanvas)
 *      height            【TAG】ﾁｬｰﾄの高さを指定します。(初期値:400)
 *      width             【TAG】ﾁｬｰﾄの幅を指定します。(初期値:400)
 *      labelColumn       【TAG】ﾗﾍﾞﾙのｶﾗﾑ名を指定します。（表示名称）
 *      title             【TAG】ﾀｲﾄﾙを指定します。
 *      titlePosition     【TAG】ﾀｲﾄﾙの表示位置[top/right/bottom/left]を指定します。(初期値:top)
 *      ylabel            【TAG】x軸のラベルを指定します。
 *      xlabel            【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)
 *      xscaleTimeType    【TAG】x軸の型[string/int]を指定します。xscaleTypeにtimeを指定した場合に利用します。(初期値:string) 
 *      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の場合に有効)
 *      yscaleType        【TAG】y軸のｽｹｰﾙﾀｲﾌﾟ[linear/category]を指定します。(初期値:linear)
 *      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)
 *      widthEventColumn  【TAG】横幅を動機に設定するｶﾗﾑのIDを指定します。
 *      heightEventColumn 【TAG】縦幅を動的に設定するｶﾗﾑのIDを指定します。
 *      minEventColumn    【TAG】minを動的に設定するｶﾗﾑのIDを指定します。 
 *      maxEventColumn    【TAG】maxを動的に設定するｶﾗﾑのIDを指定します。 
 *      optionAttributes  【TAG】その他ｵﾌﾟｼｮﾝを指定します。
 *  &gt;   ... Body ...
 *  &lt;/og:jsChart&gt;
 * ●使用例
 *      &lt;og:jsChart
 *          chartType      = "bar"
 *          labelColumn    = "LDATA"
 *          id             = "canvasid"
 *          height         = "500"
 *          width          = "800"
 *          labelColumn    = "LCLM"
 *          title          = "タイトル"
 *          titlePosition  = "bottom"
 *          ylabel         = "給料"
 *          xlabel         = "名称"
 *          legendPosition = "right"
 *          legendDisplay  = "true"
 *          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
 * @og.rev 5.9.19.0		2017/04/07	T.OTA 61200-170316-02	ﾁｬｰﾄｻｲｽﾞ・max・minの動的変更対応
 * 
 * @author	T.OTA
 * @since	JDK7.0
 *
 */
public class JsChartTag extends CommonTagSupport {
	//* このプログラムのVERSION文字列を設定します。{@value} */
	private static final String		VERSION				= "5.9.17.2 (2017/02/07)";
	private static final long		serialVersionUID	= 1631345224410617801L;
	/** chartType 引数に渡す事の出来る アクション 折れ線 **/
	public static final String		CTYPE_LINE			= "line";
	/** chartType 引数に渡す事の出来る アクション 棒線 **/
	public static final String		CTYPE_BAR			= "bar";
	/** chartType 引数に渡す事の出来る アクション 横棒線 **/
	public static final String		CTYPE_HBAR			= "horizontalBar";
	/** chartType 引数に渡す事の出来る アクション レイダー **/
	public static final String		CTYPE_RADAR			= "radar";
	/** chartType 引数に渡す事の出来る アクション ポーラエリア **/
	public static final String		CTYPE_PA			= "polarArea";
	/** chartType 引数に渡す事の出来る アクション 円 **/
	public static final String		CTYPE_PIE			= "pie";
	/** chartType 引数に渡す事の出来る アクション ドーナツ **/
	public static final String		CTYPE_DOUGHNUT		= "doughnut";
	/** chartType 引数に渡す事の出来る アクション リスト */
	private static final String[]	CTYPE_LIST			= new String[] { 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 String 	CANVAS_NAME			= "hybscanvas";
	
	// 変数宣言
	private String					id					= null;																						// canvasﾀｸﾞのid
	private String					height				= "400";																								// canvasﾀｸﾞのheight
	private String					width				= "400";																								// canvasﾀｸﾞのwidth
	private String					chartType			= null;																								// ﾁｬｰﾄﾀｲﾌﾟ
	private String					labelColumn			= null;																								// ﾗﾍﾞﾙｶﾗﾑ
	private String					ylabel				= null;																								// y軸ﾗﾍﾞﾙ
	private String					xlabel				= null;																								// x軸ﾗﾍﾞﾙ
//	private String					scope				= "session";																							// ｽｺｰﾌﾟ
	private String					tableId				= HybsSystem.TBL_MDL_KEY;																				// ﾃｰﾌﾞﾙid
	private List<JsChartData>		jsChartData			= null;																								// jsChartDataのﾘｽﾄ
	private transient DBTableModel	table				= null;																								// DBTableModelｸﾗｽ
	private String					onClick				= null;																								// ｸﾘｯｸｲﾍﾞﾝﾄ
	private String					title				= null;																								// ﾀｲﾄﾙ
	private String					titlePosition		= null;																								// ﾀｲﾄﾙ位置
	private String					legendPosition		= null;																								// 凡例位置
	private String					legendDisplay		= null;																								// 凡例表示ﾌﾗｸﾞ
	private String					barWidthPer			= null;																								// 棒線の横幅(ﾊﾟｰｾﾝﾄ)
	private String					xscaleCallback		= null;																								// x軸のﾒﾓﾘ編集用ｺｰﾙﾊﾞｯｸ
	private String					yscaleCallback		= null;																								// y軸のﾒﾓﾘ編集用ｺｰﾙﾊﾞｯｸ
	private String					xscaleType			= null;																								// x軸のｽｹｰﾙﾀｲﾌﾟ
	private String					xmax				= null;																								// x軸の最大値(ﾘﾆｱｽｹｰﾙ用)
	private String					xmin				= null;																								// x軸の最小値(ﾘﾆｱｽｹｰﾙ用)
	private String					xstepSize			= null;																								// x軸のﾒﾓﾘ幅(ﾘﾆｱｽｹｰﾙ用)
	private String					yscaleType			= null;																								// y軸のｽｹｰﾙﾀｲﾌﾟ
	private String					ycategoryList		= null;																								// y軸のｶﾃｺﾞﾘｰﾘｽﾄ(ｶﾃｺﾞﾘｰｽｹｰﾙ用)
	private String					max					= null;																								// y軸の最大値(ﾘﾆｱｽｹｰﾙ用)
	private String					min					= null;																								// y軸の最小値(ﾘﾆｱｽｹｰﾙ用)
	private String					stepSize			= null;																								// y軸のﾒﾓﾘ幅(ﾘﾆｱｽｹｰﾙ用)
	private String					timeUnit			= null;																								// 時間の単位(ﾀｲﾑｽｹｰﾙ用)
	private String					timeUnitStepSize	= null;																								// 時間のﾒﾓﾘ幅(ﾀｲﾑｽｹｰﾙ用)
	private String					timeSetFormat		= null;																								// 時間の入力ﾌｫｰﾏｯﾄ(ﾀｲﾑｽｹｰﾙ用)
	private String					timeLblFormat		= null;																								// 時間の表示ﾌｫｰﾏｯﾄ(ﾀｲﾑｽｹｰﾙ用)
	private String					timeMax				= null;																								// 最大の時間(ﾀｲﾑｽｹｰﾙ用)
	private String					timeMin				= null;																								// 最小の時間(ﾀｲﾑｽｹｰﾙ用)
	private String					widthEventColumn	= null;																								// 横幅の動的参照ｶﾗﾑ	2017/03/28 ADD
	private String					heightEventColumn	= null;																								// 縦幅の動的参照ｶﾗﾑ	2017/03/28 ADD
	private String					minEventColumn		= null;																								// 最小値の動的参照ｶﾗﾑ	2017/03/28 ADD
	private String					maxEventColumn		= null;																								// 最大値の動的参照ｶﾗﾑ	2017/03/28 ADD
	private boolean useRenderer			;							// 5.9.20.1 (2017/05/12) useRenderer 追加(6.7.7.0)
	private String					optionAttributes	= null;																								// ｵﾌﾟｼｮﾝ
	
	// 5.10.3.2 (2018/09/28)
	private static final String TYPE_STRING			= "string";
	private static final String TYPE_INT			= "int";
	private static final String[] XSCALEDATATYPE_LIST = new String[] {TYPE_STRING, TYPE_INT};
	private String					xscaleTimeType		= TYPE_STRING;

	/**
	 * タグリブオブジェクトをリリースします。
	 * キャッシュされて再利用されるので、フィールドの初期設定を行います。
	 * 
	 * @og.rev 5.9.19.0 (2017/04/07) T.OTA 61200-170316-02	ﾁｬｰﾄｻｲｽﾞ・max・minの動的変更対応
	 * @og.rev 5.9.20.1 (2017/05/12) useRenderer追加
	 * @og.rev 5.10.3.2 (2018/09/28) xscaleTimeType追加
	 */
	@Override
	protected void release2() {
		super.release2();
		id = null;
		height = "400";
		width = "400";
		chartType = null;
		labelColumn = null;
//		scope = "session";
		tableId = HybsSystem.TBL_MDL_KEY;
		jsChartData = null;
		table = null;
		optionAttributes = null;
		onClick = null;
		title = null;
		titlePosition = null;
		xlabel = null;
		ylabel = null;
		legendPosition = null;
		legendDisplay = null;
		barWidthPer = null;
		xscaleCallback = null;
		yscaleCallback = null;
		xscaleType = null;
		yscaleType = null;
		ycategoryList = null;
		max = null;
		min = null;
		stepSize = null;
		timeUnit = null;
		timeUnitStepSize = null;
		timeSetFormat = null;
		timeLblFormat = null;
		timeMax = null;
		timeMin = null;
		xmax = null;
		xmin = null;
		xstepSize = null;
		widthEventColumn = null;		// 5.9.19.0	
		heightEventColumn = null;		// 5.9.19.0	
		maxEventColumn = null;			// 5.9.19.0	
		minEventColumn = null;			// 5.9.19.0	
		useRenderer			= false;	// 5.9.20.1 (2017/05/12) useRenderer 追加(6.7.9.0)
		xscaleTimeType = TYPE_STRING;	// 5.10.3.2 (2018/09/28)
	}

	/**
	 * Taglibの開始タグが見つかった時に処理する doStartTag() を オーバーライドします。
	 * 
	 * @og.rev 5.9.20.1 (2017/05/12) タグの使用を決める共通属性の追加(6.7.5.0)
	 * 
	 * @return 後続処理の指示
	 */
	@Override
	public int doStartTag() {
		if( !useTag() ) { return SKIP_BODY ; }		// 5.9.20.1 (2017/05/12)
		
		// ﾁｪｯｸ処理の実行
		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 ) ) {
			StringBuilder errMsg = new StringBuilder( HybsSystem.BUFFER_MIDDLE );
			errMsg.append( "指定のｽｹｰﾙﾀｲﾌﾟの組み合わせは実行できません。" );
			errMsg.append( HybsSystem.CR );
			errMsg.append( "xscaleType:" ).append( xscaleType ).append( " yscaleType:" ).append( yscaleType );
			throw new HybsSystemException( errMsg.toString() );
		}
	}

	/**
	 * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。
	 * 
	 * @return 後続処理の指示
	 */
	@Override
	public int doEndTag() {
		debugPrint();

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

		return EVAL_PAGE;
	}

	/**
	 * jsChart出力用
	 * jsChartTag と jsChartData を使用して、jsChart情報を出力します。
	 * 
	 * @og.rev 5.9.19.0 (2017/04/07) T.OTA 61200-170316-02	ﾁｬｰﾄｻｲｽﾞ・max・minの動的変更対応
	 * @og.rev 5.9.20.1 (2017/05/12) useRenderer対応
	 * @og.rev 5.9.27.0 	2017/12/01	T.OTA 61200-170831-04	max,minの小数点対応 
	 * @og.rev 5.10.3.2 (2018/09/28) のxscaleType対応
	 * 
	 * @return jsChert用文字列
	 */
	private String jsChartOutput() {
		StringBuilder rtn = new StringBuilder( HybsSystem.BUFFER_MIDDLE );
		
		// 各JavaScriptの変数名
		String qd = "qd_" + id; //queryData
		String cd = "cd_" + id; //chartData
		String myChart = "chart_"+id;
		String lblClm = labelColumn + id;
		

		// JSON形式でﾃｰﾌﾞﾙ情報を取得
		ViewForm form = ViewFormFactory.newInstance( "JSON" );
		form.init( table );
		
		// 5.9.20.1 (2017/05/12) form にパラメータMapを与えるようにする
		final ConcurrentMap<String,String> cMap = new ConcurrentHashMap<String,String>();
		if( useRenderer ) {
			cMap.put( ViewJsonParam.JSON_RENDERER_KEY , "true" );
		}
		if( !cMap.isEmpty() ) {
			form.setParam( cMap );
		}

		// 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)
		rtn.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++ ) {
			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( ";" );
			}
		}
		// 5.10.3.2 (2018/09/28)
//		rtn.append( lblClm ).append( "[i] = ").append( qd ).append( ".DATA[i]." ).append( labelColumn ).append( ";" );
		rtn.append( lblClm ).append( "[i] = ");
		// xscaleTimeTypeがint場合は数値型を設定
		if("time".equals(this.xscaleType) && TYPE_INT.equals(this.xscaleTimeType)) {
			rtn.append("Number(");
		}
		rtn.append( qd ).append( ".DATA[i]." ).append( labelColumn );
		// xscaleTimeTypeがint場合は数値型を設定
		if("time".equals(this.xscaleType) && TYPE_INT.equals(this.xscaleTimeType)) {
			rtn.append(")");
		}
		rtn.append( ";" );


		rtn.append( "}" );

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

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

		// jsChartDataの設定
		rtn.append( "var ").append( cd ).append(" = {" );
		rtn.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( ",{" );
		rtn.append( "type:'" ).append( chartType ).append( "'" );
		rtn.append( ",data:").append(cd);
		rtn.append( ",options:{" );
		rtn.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:{" );
			rtn.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の円形ﾁｪｯｸ
		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: {" );
				rtn.append( "display: true," );
				rtn.append( "labelString: '").append( ylabel ).append("'");
				rtn.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: {" );
				rtn.append( "display: true," );
				rtn.append( "labelString: '").append( xlabel ).append("'");
				rtn.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( "}}]" );

			rtn.append( "}" );
		}
		setProp( rtn, ",", optionAttributes );

		rtn.append( "}});" );
		
		// ｲﾍﾞﾝﾄ設定用 5.9.19.0
		// 5.9.27.0 (2017/12/01) MODIFY ｲﾍﾞﾝﾄにkeyupを追加
		// widthEventColumn設定
		if( widthEventColumn != null && widthEventColumn.length() > 0){
			rtn.append( "$(document).delegate('#").append( widthEventColumn ).append( "','mouseup keyup',function(){")
				.append( "var width = $(this).val();")
				.append( "$('#" ).append( id ).append( "').attr('width',width);")
				.append( myChart ).append( ".chart.width=width;")
				.append( myChart ).append( ".update();")
				.append( "} );")
				.append( "$(function( ){")
				.append( "var chartWidth = $('#" ).append( id ).append("').attr('width');")
				.append( "$('#").append( widthEventColumn ).append( "').val(chartWidth);")		// 初期値を設定
				.append( "});");
		}
		// heightEventColumn設定
		if( heightEventColumn != null && heightEventColumn.length() > 0){
			rtn.append( "$(document).delegate('#").append( heightEventColumn ).append( "','mouseup keyup',function(){")
				.append( "var height = $(this).val();")
				.append( "$('#" ).append( id ).append( "').attr('height',height);")
				.append( myChart ).append( ".chart.height=height;")
				.append( myChart ).append( ".update();")
				.append( "} );")
				.append( "$(function( ){")
				.append( "var chartHeight = $('#" ).append( id ).append("').attr('height');")
				.append( "$('#").append( heightEventColumn ).append( "').val(chartHeight);")	// 初期値を設定
				.append( "});");
		}
		// minEventColumn設定
		if( minEventColumn != null && minEventColumn.length() > 0){
			rtn.append( "$(document).delegate('#").append( minEventColumn ).append( "','mouseup keyup',function(){")
				// 5.9.27.0 (2017/12/01) MODIFY IntからFloat型に変更
				// .append( "var min = parseInt($(this).val());")
				.append( "var min = parseFloat($(this).val());")
				.append( myChart ).append( ".options.scales.yAxes[0].ticks.min = min;")
				.append( myChart ).append( ".update();")
				.append( "} );")
				.append( "$(function( ){")
				.append( "var chartMin = ").append( myChart ).append( ".scales['y-axis-0'].min;")
				.append( "$('#").append( minEventColumn ).append( "').val(chartMin);")			// 初期値を設定
				.append( "});");
		}
		// maxEventColumn設定
		if( maxEventColumn != null && maxEventColumn.length() > 0){
			rtn.append( "$(document).delegate('#").append( maxEventColumn ).append( "','mouseup keyup',function(){")
				// 5.9.27.0 (2017/12/01) MODIFY IntからFloat型に変更
				// .append( "var max = parseInt($(this).val());")
				.append( "var max = parseFloat($(this).val());")
				.append( myChart ).append( ".options.scales.yAxes[0].ticks.max = max;")
				.append( myChart ).append( ".update();")
				.append( "} );")
				.append( "$(function(){")		
				.append( "var chartMax = ").append( myChart ).append( ".scales['y-axis-0'].max;")
				.append( "$('#").append( maxEventColumn ).append( "').val(chartMax);")			// 初期値を設定
				.append("});");
		}
		
		rtn.append( "</script>" );

		return rtn.toString();
	}

	/**
	 * setに値が存在する場合,
	 * sbにstr + setの形で値を追加する。
	 * 
	 * @param sb
	 * @param str
	 * @param set
	 */
	private void setProp( StringBuilder sb, String str, String set ) {
		if( set != null && set.length() > 0 ) {
			sb.append( str ).append( set );
		}
	}

	/**
	 * setに値が存在する場合,
	 * sbにstr + set + endの形で値を追加する。
	 * 
	 * @param sb
	 * @param str
	 * @param set
	 * @param end
	 */
	private void setProp( StringBuilder sb, String str, String set, String end ) {
		if( set != null && set.length() > 0 ) {
			sb.append( str ).append( set ).append( end );
		}
	}

	/**
	 * id を設定します。
	 * canvasﾀｸﾞのidに設定します。
	 * 
	 * @param id
	 */
	public void setId( String id ) {
		String temp = getRequestParameter( id );
		if( temp != null && temp.length() > 0 ) {
			this.id = temp;
		}
	}

	/**
	 * 高さ を設定します。
	 * canvasﾀｸﾞの高さに設定します。
	 * 
	 * @param hei
	 */
	public void setHeight( final String hei ) {
		String temp = getRequestParameter( hei );
		if( temp != null && temp.length() > 0 ) {
			height = temp;
		}
	}

	/**
	 * 横幅 を設定します。
	 * canvasﾀｸﾞの横幅を設定します。
	 * 
	 * @param wid
	 */
	public void setWidth( final String wid ) {
		String temp = getRequestParameter( wid );
		if( wid != null && wid.length() > 0 ) {
			width = temp;
		}
	}

	/**
	 * ﾁｬｰﾄﾀｲﾌﾟ を設定します。
	 * 
	 * @param cType
	 */
	public void setChartType( final String cType ) {
		chartType = getRequestParameter( cType );

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

	/**
	 * ﾗﾍﾞﾙｶﾗﾑを指定します。
	 * 
	 * @param labelColumn ﾗﾍﾞﾙｶﾗﾑ
	 */
	public void setLabelColumn( String labelColumn ) {
		this.labelColumn = getRequestParameter( labelColumn );
	}

//	/**
//	 * ﾃｰﾌﾞﾙｽｺｰﾌﾟを指定します。
//	 * 
//	 * @param scope ﾃｰﾌﾞﾙｽｺｰﾌﾟ
//	 */
//	public void setScope( String scope ) {
//		this.scope = getRequestParameter( scope );
//	}

	/**
	 * ﾃｰﾌﾞﾙIDを指定します。
	 * 
	 * @param tableId テーブルID
	 */
	public void setTableId( String tableId ) {
		this.tableId = getRequestParameter( tableId );
	}

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

	/**
	 * メモリの最大値を指定します。
	 * 
	 * @param max メモリの最大値
	 */
	public void setMax( String max ) {
		this.max = getRequestParameter( max );
	}

	/**
	 * メモリの最小値を指定します。
	 * 
	 * @param min メモリの最小値
	 */
	public void setMin( String min ) {
		this.min = getRequestParameter( min );
	}

	/**
	 * メモリ幅を設定します。
	 * 
	 * @param stepSize
	 */
	public void setStepSize( String stepSize ) {
		this.stepSize = getRequestParameter( stepSize );
	}

	/**
	 * 時間の単位を設定します。
	 * 
	 * @param timeUnit
	 */
	public void setTimeUnit( String timeUnit ) {
		this.timeUnit = getRequestParameter( timeUnit );

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

	/**
	 * 時間のメモリ幅を設定します。
	 * 
	 * @param timeUnitStepSize
	 */
	public void setTimeUnitStepSize( String timeUnitStepSize ) {
		this.timeUnitStepSize = getRequestParameter( timeUnitStepSize );
	}

	/**
	 * 時間の入力フォーマットを設定します。
	 * 
	 * @param timeSetFormat
	 */
	public void setTimeSetFormat( String timeSetFormat ) {
		this.timeSetFormat = getRequestParameter( timeSetFormat );
	}

	/**
	 * 時間の表示フォーマットを設定します。
	 * 
	 * @param timeLblFormat
	 */
	public void setTimeLblFormat( String timeLblFormat ) {
		this.timeLblFormat = getRequestParameter( timeLblFormat );
	}

	/**
	 * 時間の最大値を設定します。
	 * 
	 * @param timeMax
	 */
	public void setTimeMax( String timeMax ) {
		this.timeMax = getRequestParameter( timeMax );
	}

	/**
	 * 時間の最小値を設定します。
	 * 
	 * @param timeMin
	 */
	public void setTimeMin( String timeMin ) {
		this.timeMin = getRequestParameter( timeMin );
	}

	/**
	 * タイトルを設定します。
	 * 
	 * @param title
	 */
	public void setTitle( String title ) {
		this.title = getRequestParameter( title );
	}

	/**
	 * タイトル位置を設定します。
	 * 
	 * @param titlePosition
	 */
	public void setTitlePosition( String titlePosition ) {
		this.titlePosition = getRequestParameter( titlePosition );

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

	/**
	 * 凡例位置を設定します。
	 * 
	 * @param legendPosition
	 */
	public void setLegendPosition( String legendPosition ) {
		this.legendPosition = getRequestParameter( legendPosition );

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

	/**
	 * 凡例の表示制御を設定します。
	 * 
	 * @param legendDisplay
	 */
	public void setLegendDisplay( String legendDisplay ) {
		this.legendDisplay = getRequestParameter( legendDisplay );

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

	/**
	 * x軸のメモリ編集用スケールバックを設定します。
	 * 
	 * @param xscaleCallback
	 */
	public void setXscaleCallback( String xscaleCallback ) {
		this.xscaleCallback = getRequestParameter( xscaleCallback );
	}

	/**
	 * y軸のメモリ編集用スケールバックを設定します。
	 * 
	 * @param yscaleCallback
	 */
	public void setYscaleCallback( String yscaleCallback ) {
		this.yscaleCallback = getRequestParameter( yscaleCallback );
	}

	/**
	 * x軸のスケールタイプを設定します。
	 * 
	 * @og.tag
	 * timeとした場合はxscaleTimeTypeの設定も確認してください。
	 * 
	 * @param xscaleType
	 */
	public void setXscaleType( String xscaleType ) {
		this.xscaleType = getRequestParameter( xscaleType );

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

	/**
	 * y軸のスケールタイプを設定します。
	 * 
	 * @param yscaleType
	 */
	public void setYscaleType( String yscaleType ) {
		this.yscaleType = getRequestParameter( yscaleType );

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

	/**
	 * y軸のカテゴリー一覧を設定します。
	 * 
	 * @param ycategoryList
	 */
	public void setYcategoryList( String ycategoryList ) {
		this.ycategoryList = getRequestParameter( ycategoryList );
	}

	/**
	 * x軸の最大値を設定します。
	 * 
	 * @param xmax
	 */
	public void setXmax( String xmax ) {
		this.xmax = getRequestParameter( xmax );
	}

	/**
	 * x軸の最小値を設定します。
	 * 
	 * @param xmin
	 */
	public void setXmin( String xmin ) {
		this.xmin = getRequestParameter( xmin );
	}

	/**
	 * x軸のメモリ幅を設定します。
	 * 
	 * @param xstepSize
	 */
	public void setXstepSize( String xstepSize ) {
		this.xstepSize = getRequestParameter( xstepSize );
	}

	/**
	 * 棒線の横幅を設定します。
	 * 
	 * @param barWidthPer
	 */
	public void setBarWidthPer( String barWidthPer ) {
		this.barWidthPer = getRequestParameter( barWidthPer );
	}

	/**
	 * y軸のラベルを設定します。
	 * 
	 * @param ylabel
	 */
	public void setYlabel( String ylabel ) {
		this.ylabel = getRequestParameter( ylabel );
	}

	/**
	 * x軸のラベルを設定します。
	 * 
	 * @param xlabel
	 */
	public void setXlabel( String xlabel ) {
		this.xlabel = getRequestParameter( xlabel );
	}
	/**
	 * 横幅の動的設定カラムを設定します。
	 * 
	 * @og.rev 5.9.19.0 (2017/04/07) 追加
	 * @param widthEventColumn
	 */
	public void setWidthEventColumn( String widthEventColumn ) {
		this.widthEventColumn = getRequestParameter( widthEventColumn );
	}
	
	/**
	 * 縦幅の動的設定カラムを設定します。
	 * 
	 * @og.rev 5.9.19.0 (2017/04/07) 追加
	 * @param heightEventColumn
	 */
	public void setHeightEventColumn( String heightEventColumn ) {
		this.heightEventColumn = getRequestParameter( heightEventColumn );
	}
	
	/**
	 * minの動的設定カラムを設定します。
	 * 
	 * @og.rev 5.9.19.0 (2017/04/07) 追加
	 * @param minEventColumn
	 */
	public void setMinEventColumn( String minEventColumn ) {
		this.minEventColumn = getRequestParameter( minEventColumn );
	}
	
	/**
	 * maxの動的設定カラムを設定します。
	 * 
	 * @og.rev 5.9.19.0 (2017/04/07) 追加
	 * @param maxEventColumn
	 */
	public void setMaxEventColumn( String maxEventColumn ) {
		this.maxEventColumn = getRequestParameter( maxEventColumn );
	}
	
	/**
	 * 【TAG】JSON出力で、値出力にレンデラを利用するかどうかを指定します。
	 *
	 * @og.tag
	 * JSONのデータのレンデラー変換を行うかどうか。
	 * 指定しない場合は使用しない(false)です。
	 * 
	 * @og.rev 5.9.20.1 (2017/05/12) useRenderer 追加(6.7.9.0)
	 *
	 * @param	usernd レンデラーを利用するかどうか
	 */
	public void setUseRenderer( final String usernd ) {
		this.useRenderer = nval( getRequestParameter( usernd ) , this.useRenderer );
	}

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

	/**
	 * 【TAG】x軸のデータ型を指定します。
	 *
	 * @ot.tag
	 * X軸のデータを文字列として扱うか、数値として扱うかを指定します。(string/int)
	 * Xが時間軸の場合に数値(UNIX時間)として扱う事で時間に沿ったスケールとなります。
	 * 
	 * @og.rev 5.10.3.2 (2018/09/28) 新規追加
	 *
	 * @param xtt string/int
	 */
	public void setXscaleTimeType( final String xtt) {
		this.xscaleTimeType = nval( getRequestParameter( xtt ), this.xscaleTimeType ).toLowerCase();
		checkPara(xtt, XSCALEDATATYPE_LIST, "xscaleTimeType");
	}

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

	/**
	 * ﾊﾟﾗﾒｰﾀﾁｪｯｸ用ﾒｿｯﾄﾞ
	 * 
	 * @param trg
	 * @param list
	 * @param trgStr
	 */
	private void checkPara( String trg, String[] list, String trgStr ) {
		if( trg != null && trg.length() > 0 && !check( trg, list ) ) {
			StringBuilder errMsg = new StringBuilder( HybsSystem.BUFFER_MIDDLE );
			errMsg.append( "指定の" ).append( trgStr ).append( "は指定できません。" );
			errMsg.append( HybsSystem.CR );
			errMsg.append( trgStr ).append( "=[" ).append( trg ).append( "]" );
			errMsg.append( HybsSystem.CR );
			for( int i = 0; i < list.length; i++ ) {
				errMsg.append( " | " );
				errMsg.append( list[i] );
			}
			throw new HybsSystemException( errMsg.toString() );
		}
	}

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

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

		// 2017/03/28 widthEventColumn,heightEventColumn,minEventColumn,maxEventColumnを追加
		return org.opengion.fukurou.util.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( "widthEventColumn", widthEventColumn )
			.println( "heightEventColumn", heightEventColumn )
			.println( "minEventColumn", minEventColumn )
			.println( "maxEventColumn", maxEventColumn )
			.println( "optionAttributes", optionAttributes )
			.println( "JSON", form.create() )
			.println( "jsChartDataPara", sb.toString() ).fixForm().toString();
	}
}
