package org.opengion.hayabusa.taglib;

import org.opengion.hayabusa.common.HybsSystemException;
import org.opengion.hayabusa.io.JsChartData;

import java.util.Set;											// 6.4.3.4 (2016/03/11)
import org.opengion.fukurou.util.ArraySet;						// 6.4.3.4 (2016/03/11)
import org.opengion.fukurou.util.ToString;
import org.opengion.fukurou.util.ColorMap;						// 6.7.7.0 (2017/03/31)
import static org.opengion.fukurou.util.StringUtil.nval ;

/**
 * 設定された値をJsChartDataに設定し、
 * JsChartTagのJsChartDataリストに追加するタグです。
 * 
 * @og.formSample
 * ●形式：&lt;og:jsChartData chartColumn="…" … /&gt;
 * ●body:なし
 * 
 * ●Tag定義：
 * &lt;og:jsChartData
 *      chartColumn     ○【TAG】ﾁｬｰﾄのｶﾗﾑ名を指定します(必須)。
 *      label             【TAG】凡例の値を指定します。
 *      fill              【TAG】線下を塗りつぶすかどうか[true/false]を指定します(初期値:false)。
 *      tension           【TAG】線の伸張を指定します。0で直線になります(初期値:0.4)。
 *      borderColor       【TAG】線の色を指定します。
 *      colorNo           【TAG】線の色(borderColor)をColorMapの色番号で指定します。
 *      borderWidth       【TAG】線の幅を指定します。
 *      backgroundColor   【TAG】ﾃﾞｰﾀの背景色を指定します。
 *      pointStyle        【TAG】点のスタイル(circle,triangle,rect,rectRot,cross,crossRot,star,line,dash)を指定します。 // 6.8.5.0 (2018/01/09)
 *      pointRadius       【TAG】点の大きさを指定します。																// 6.8.5.0 (2018/01/09)
 *      showLine          【TAG】ラインを表示するかどうか[true/false]を指定します(初期値:null)。						// 6.8.5.0 (2018/01/09)
 *      optionAttributes  【TAG】その他ｵﾌﾟｼｮﾝを指定します。
 *      caseKey           【TAG】このタグ自体を利用するかどうかの条件キーを指定します(初期値:null)
 *      caseVal           【TAG】このタグ自体を利用するかどうかの条件値を指定します(初期値:null)
 *      caseNN            【TAG】指定の値が、null/ゼロ文字列 でない場合(Not Null=NN)は、このタグは使用されます(初期値:判定しない)
 *      caseNull          【TAG】指定の値が、null/ゼロ文字列 の場合は、このタグは使用されます(初期値:判定しない)
 *      caseIf            【TAG】指定の値が、true/TRUE文字列の場合は、このタグは使用されます(初期値:判定しない)
 *  &gt; />
 * 
 * ●使用例
 * &lt;og:jsChart...&gt;
 *     &lt;og:jsChartData
 *         chartColumn ="CLM1"
 *         label       ="ラベル"
 *         fill        ="true"
 *         tension     ="0"
 *         borderColor ="rbga(150,150,150,0.7)"
 *         borderWidth ="2"
 *     /&gt;>
 * &lt/og:jsChart&gt;
 * 
 * @og.group 画面表示
 * 
 * @version	5.9.17.2		2017/02/08
 * @author	T.OTA
 * @since	JDK7.0
 * 
 */
public class JsChartDataTag extends CommonTagSupport {
	//* このプログラムのVERSION文字列を設定します。{@VALUE} */
	private static final String VERSION = "6.9.9.2 (2018/09/18)" ;
	private static final long serialVersionUID = 699220180918L ;

	private static final Set<String> TYPE_BOOLEAN = new ArraySet<>( "true", "false" );

	// 変数宣言
	private String	chartColumn			;
	private String	label				;
	private String	fill				= "false";
	private String	tension				= "0.4";
	private String	borderColor			;
	private String	borderWidth			;
	private String	backgroundColor		;
	private String	pointStyle			;	// 6.8.5.0 (2018/01/09) 点のスタイル
	private String	pointRadius			;	// 6.8.5.0 (2018/01/09) 点の大きさ
	private String	showLine			;	// 6.8.5.0 (2018/01/09) ラインを表示するかどうか
	private String	optionAttributes	;

	/**
	 * デフォルトコンストラクター
	 *
	 * @og.rev 6.9.7.0 (2018/05/14) PMD Each class should declare at least one constructor
	 */
	public JsChartDataTag() { super(); }		// これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。

	/**
	 * Taglibの終了タグが見つかった時に処理する doEndTag() を オーバーライドします。
	 * 
	 * @og.rev 6.7.6.0 (2017/03/17) タグの使用を決める共通属性の追加
	 * @og.rev 6.7.7.0 (2017/03/31) backgroundColor が未設定の場合は、borderColor を使用します。
	 * @og.rev 6.8.5.0 (2018/01/09) pointStyle , pointRadius , showLine 属性の追加。
	 * 
	 * @return 後続処理の指示
	 */
	@Override
	public int doEndTag() {
		debugPrint();
		if( !useTag() ) { return EVAL_PAGE ; }			// 6.7.6.0 (2017/03/17)

		final JsChartTag jsChartTag = (JsChartTag) findAncestorWithClass( this, JsChartTag.class );

		if( jsChartTag == null ) {
			final String errMsg = "jsChart タグが見つかりませんでした。";
			throw new HybsSystemException( errMsg );
		}

		// 6.7.7.0 (2017/03/31) 各種初期設定を行います。
		if( borderColor == null || borderColor.isEmpty() ) {
			final int size = jsChartTag.getJsChartDataSize();	// 登録順に色番号を設定します。
			final String[] cols = ColorMap.getColorKeys();
			borderColor = cols[size % cols.length];
		}
		if( backgroundColor == null || backgroundColor.isEmpty() ) {
			backgroundColor = borderColor;
		}

		final JsChartData jsData = new JsChartData();	// 6.7.7.0 (2017/03/31) ローカル変数化
		jsData.setChartColumn(		chartColumn			);
		jsData.setLabel(			label				);
		jsData.setFill(				fill				);
		jsData.setTension(			tension				);
		jsData.setBorderColor(		borderColor			);
		jsData.setBorderWidth(		borderWidth			);
		jsData.setBackgroundColor(	backgroundColor		);
		jsData.setPointStyle(		pointStyle			);	// 6.8.5.0 (2018/01/09)
		jsData.setPointRadius(		pointRadius			);	// 6.8.5.0 (2018/01/09)
		jsData.setShowLine(			showLine			);	// 6.8.5.0 (2018/01/09)
		jsData.setOptionAttributes(	optionAttributes	);

		jsChartTag.addJsChartData( jsData );

		return EVAL_PAGE;
	}

	/**
	 * タグリブオブジェクトをリリースします。
	 * キャッシュされて再利用されるので、フィールドの初期設定を行います。
	 * 
	 * @og.rev 6.7.7.0 (2017/03/31) jsDataのローカル変数化。
	 * @og.rev 6.8.5.0 (2018/01/09) pointStyle , pointRadius , showLine 属性の追加。
	 */
	@Override
	protected void release2() {
		super.release2();
		chartColumn			= null;
		label				= null;
		fill				= "false";
		tension				= "0.4";
		borderColor			= null;
		borderWidth			= null;
		backgroundColor		= null;
		pointStyle			= null;		// 6.8.5.0 (2018/01/09) 点のスタイル
		pointRadius			= null;		// 6.8.5.0 (2018/01/09) 点のスタイル
		showLine			= null;		// 6.8.5.0 (2018/01/09) ラインを表示するかどうか
		optionAttributes	= null;
	}

	/**
	 * 【TAG】ﾁｬｰﾄのｶﾗﾑ名を指定します(必須)。
	 *
	 * @og.tag
	 * 
	 * @param clm ﾁｬｰﾄのｶﾗﾑ名
	 */
	public void setChartColumn( final String clm ) {
		chartColumn = nval( getRequestParameter( clm ),chartColumn );
	}

	/**
	 * 【TAG】凡例の値を指定します。
	 *
	 * @og.tag
	 * 
	 * @param lbl 凡例
	 */
	public void setLabel( final String lbl ) {
		label = nval( getRequestParameter( lbl ),label );
	}

	/**
	 * 【TAG】線下を塗りつぶすかどうか[true/false]を指定します(初期値:false)。
	 *
	 * @og.tag
	 * フィル(線より下の塗りつぶし) を設定します。
	 * 
	 * @param fill 塗りつぶすかどうか [true/false]
	 */
	public void setFill( final String fill ) {
		this.fill = nval( getRequestParameter( fill ) , this.fill );

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

	/**
	 * 【TAG】線の伸張を指定します。0で直線になります(初期値:0.4)。
	 *
	 * @og.tag
	 * 伸張 を設定します。
	 *
	 * @param tension 線の伸張
	 */
	public void setTension( final String tension ) {
		this.tension = nval( getRequestParameter( tension ),this.tension );
	}

	/**
	 * 【TAG】線の色を指定します。
	 *
	 * @og.tag
	 * borderColor = "BLUE" とすると、すべての線の色を指定できます。
	 * 配列で指定すると、データの順番に適用されます。
	 * 例：borderColor = "['#ffaaaa','#ffffaa','#aaffaa','#aaaaff','#aaaaff']"
	 * 
	 * 色の代わりに、ColorMapの色番号を指定した場合でも、borderColor が優先されます。
	 * どちらも指定しない場合は、JsChartTagに登録した順番に色コードで指定されます。
	 * 
	 * @param color 線の色
	 * @see		#setColorNo(String)
	 */
	public void setBorderColor( final String color ) {
		borderColor = nval( getRequestParameter( color ),borderColor );
	}

	/**
	 * 【TAG】線の色(borderColor)をColorMapの色番号で指定します。
	 *
	 * @og.tag
	 * 色の代わりに、ColorMapの色番号を指定した場合でも、borderColor が優先されます。
	 * この引数は、色に変換後、borderColor に設定されます。
	 *
	 * @og.rev 6.7.7.0 (2017/03/31) ColorMapの色番号で指定
	 * 
	 * @param colorNo 線の色の番号
	 * @see		ColorMap#getColorKeys()
	 */
	public void setColorNo( final String colorNo ) {
		if( borderColor == null ) {		// borderColor が、未設定の場合のみ、色番号を利用する。
			final String colNo = nval( getRequestParameter( colorNo ),null );
			if( colNo != null ) {
				try {
					final int no = Integer.parseInt( colNo );
					final String[] cols = ColorMap.getColorKeys();
					borderColor = cols[no % cols.length];
				}
				catch( final NumberFormatException ex ) {
					final String errMsg = "colorNo を数値に変換できません。colorNo=" + colNo ;
					throw new HybsSystemException( errMsg,ex );
				}
			}
		}
	}

	/**
	 * 【TAG】線の幅を指定します。
	 *
	 * @og.tag
	 * 
	 * @param width 線の幅
	 */
	public void setBorderWidth( final String width ) {
		borderWidth = nval( getRequestParameter( width ),borderWidth );
	}

	/**
	 * 【TAG】ﾃﾞｰﾀの背景色を指定します。
	 *
	 * @og.tag
	 * backgroundColor = "BLUE" とすると、すべての背景色を指定できます。
	 * 配列で指定すると、データの順番に適用されます。
	 * 例：backgroundColor = "['#ffaaaa','#ffffaa','#aaffaa','#aaaaff','#aaaaff']"
	 * 
	 * 特殊ｷｰﾜｰﾄﾞとして、"PASTEL" を指定することで、パステルカラーの色ｺｰﾄﾞを指定できます。
	 * 
	 * 背景色を指定しない場合、線の色(borderColor)を使用します。
	 *
	 * @og.rev 6.9.9.2 (2018/09/18) パステルカラーの色文字列のｶﾝﾏ区切り文字列
	 * 
	 * @param bgColor 背景色
	 * @see		#setBorderColor(String)
	 */
	public void setBackgroundColor( final String bgColor ) {
		backgroundColor = nval( getRequestParameter( bgColor ),backgroundColor );

		if( "PASTEL".equalsIgnoreCase( backgroundColor ) ) {
			// ※ 処理速度はともかく、簡単で判り易いので、こちらの方法で、CSV文字列を、作成します。
			backgroundColor = "['" + String.join( "','", ColorMap.getPastelColorKeys() ) + "']";

	//		6.9.9.2 (2018/09/18) パステルカラーの色文字列のｶﾝﾏ区切り文字列
	//		final String[] PSTL_KEYS = ColorMap.getPastelColorKeys();
	//		final StringJoiner sj = new StringJoiner( "','", "['", "']" );
	//		for( int i=0; i<PSTL_KEYS.length; i++ ) {
	//			sj.add( PSTL_KEYS[i] );
	//		}
	//		backgroundColor = sj.toString();				// パステルカラーを存在する分だけ CSV文字列で返す。
		}
	}

	/**
	 * 【TAG】点のスタイルを指定します。
	 *
	 * @og.tag
	 * jsChartTag で、usePointStyle = "true" をセットした場合に有効になります。
	 * 点のスタイルは、circle,triangle,rect,rectRot,cross,crossRot,star,line,dash が、
	 * 
	 * @og.rev 6.8.5.0 (2018/01/09) 新規追加
	 * 
	 * @param ptStyle 点のスタイルを指定します。
	 */
	public void setPointStyle( final String ptStyle ) {
		pointStyle = nval( getRequestParameter( ptStyle ),pointStyle );
	}

	/**
	 * 【TAG】点の大きさを指定します。
	 *
	 * @og.tag
	 * jsChartTag で、usePointStyle = "true" をセットした場合に有効になります。
	 * 
	 * @og.rev 6.8.5.0 (2018/01/09) 新規追加
	 * 
	 * @param ptRadius 点の大きさを指定します。
	 */
	public void setPointRadius( final String ptRadius ) {
		pointRadius = nval( getRequestParameter( ptRadius ),pointRadius );
	}

	/**
	 * 【TAG】ラインを表示するかどうか[true/false]を指定します(初期値:null)。
	 *
	 * @og.tag
	 * jsChartTag で、usePointStyle = "true" をセットした場合に有効になります。
	 * 初期値(null)は、showLine 属性を設定しませんが、chartJS 自体の初期値が true
	 * なので、表示されます。
	 * 
	 * @og.rev 6.8.5.0 (2018/01/09) 新規追加
	 * 
	 * @param show ラインを表示するかどうか [true:表示する/false:表示しない]
	 */
	public void setShowLine( final String show ) {
		showLine = nval( getRequestParameter( show ),showLine );
	}

	/**
	 * 【TAG】その他ｵﾌﾟｼｮﾝを指定します。
	 *
	 * @og.tag
	 * 
	 * @param attri その他ｵﾌﾟｼｮﾝ
	 */
	public void setOptionAttributes( final String attri ) {
		optionAttributes = nval( getRequestParameter( attri ),optionAttributes );
	}

	/**
	 * ﾊﾟﾗﾒｰﾀﾁｪｯｸ用ﾒｿｯﾄﾞ。
	 * 
	 * @param trg チェック対象
	 * @param set 設定可能なリスト
	 * @param trgStr チェック対象の文字列(ｴﾗｰ表示用)
	 */
	private void checkPara( final String trg, final Set<String> set, final String trgStr ) {
		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( " | " )
					.append( lst );
			}
			throw new HybsSystemException( errMsg.toString() );
		}
	}

	/**
	 * このオブジェクトの文字列表現を返します。
	 * 基本的にデバッグ目的に使用します。
	 * 
	 * @return このクラスの文字列表現
	 */
	@Override
	public String toString() {
		return ToString.title( this.getClass().getName() )
			.println( "VERSIION"			, VERSION			)
			.println( "chartColumn"			, chartColumn		)
			.println( "label"				, label				)
			.println( "fill"				, fill				)
			.println( "tension"				, tension			)
			.println( "borderColor"			, borderColor		)
			.println( "borderWidth"			, borderWidth		)
			.println( "backgroundColor"		, backgroundColor	)
			.println( "optionAttributes"	, optionAttributes	)
			.fixForm().toString();
	}
}
