/*
 * The MIT License
 *
 * Copyright 2013 Dra0211.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package kinugasa.ui;

import java.awt.Graphics2D;
import kinugasa.contents.sound.Sound;
import kinugasa.object.BasicSprite;
import kinugasa.object.MovingModel;
import kinugasa.object.VectorF;
import kinugasa.util.TimeCounter;

/**
 * kinugasa : TextLabel : 一行のテキストを表示するスプライトの実装です.
 * <br>
 * 
 * <br>
 * ラベルは１行のテキストとタイムカウンタを保有しており、テキストの最初から１文字ずつ順番に表示することができます.<br>
 * <br>
 * 表示文字数は表示の度に設定されているタイムカウンタを利用して判定され、設定されてる遅延時間経過後に表示文字数を１文字
 * 追加します.<Br>
 * 
 * ラベルの文字列や下地の描画はLabelModel内で行われます.<br>
 * <br>
 *
 * @version 1.0.0 - 2012/07/16_14:11:53.<br>
 * @author Dra0211<br>
 */
public class TextLabel extends BasicSprite {

	private static final long serialVersionUID = 5968313475051994644L;
	/** ラベルに表示するテキスト. */
	private StringBuilder text;
	/** 表示される文字数. */
	private int idx;
	/** 表示遅延用のカウンタ. */
	private TimeCounter timeCounter;
	/** 表示モデル. */
	private LabelModel labelModel;
	/** 1文字表示されるたびに再生できるサウンドファイルです. */
	private Sound sound = null;

	/**
	 * 新しいラベルを作成します.
	 * このコンストラクタでは、すべての文字が表示されます(idx==text.length())<br>
	 * また、ラベルのサイズは1,1になります.<br>
	 * その他スプライトのプロパティはスプライトのデフォルト値が適用されます.<br>
	 * 
	 * @param x X座標.<br>
	 * @param y Y座標.<br>
	 * @param text 表示するテキスト.<Br>
	 * @param lm 表示モデル.<br>
	 */
	public TextLabel(float x, float y,
			String text, LabelModel lm) {
		super(x, y, 1, 1);
		this.text = new StringBuilder(text);
		this.idx = text.length();
		this.timeCounter = TimeCounter.TRUE;
		this.labelModel = lm;
		int w = (int) ((lm.getFont().getSize() * 0.66f + 4) * text.length());
		int h = lm.getFont().getSize() + 2;
		setSize(w, h);
	}

	/**
	 * 新しいラベルを作成します.
	 * このコンストラクタでは、すべての文字が表示されます(idx==text.length())<br>
	 * また、ラベルのサイズは1,1になります.<br>
	 * その他スプライトのプロパティはスプライトのデフォルト値が適用されます.<br>
	 * 
	 * @param x X座標.<br>
	 * @param y Y座標.<br>
	 * @param text 表示するテキスト.<Br>
	 * @param tc タイムカウンタ.使用しない場合はTimeCounter.FALSE_MODELを指定する.TimeCounter.TRUE_MODELが最速の
	 * 描画モデル（１フレームに１文字追加）となり、それ以上の速度は１フレームに２文字以上のテキストを可視化する
	 * 専用のLabelModelを定義する必要がある.<br>
	 * @param lm 表示モデル.<br>
	 */
	public TextLabel(float x, float y,
			String text, TimeCounter tc, LabelModel lm) {
		super(x, y, 1, 1);
		this.text = new StringBuilder(text);
		this.idx = text.length();
		this.timeCounter = tc;
		this.labelModel = lm;
		int w = (int) ((lm.getFont().getSize() * 0.66f + 4) * text.length());
		int h = lm.getFont().getSize() + 2;
		setSize(w, h);

	}

	/**
	 * 新しいラベルを作成します.
	 * ラベルのサイズは1,1になります.<br>
	 * その他スプライトのプロパティはスプライトのデフォルト値が適用されます.<br>
	 * 
	 * @param x X座標.<br>
	 * @param y Y座標.<br>
	 * @param text 表示するテキスト.<Br>
	 * @param idx 表示する文字数.<br>
	 * @param tc タイムカウンタ.使用しない場合はTimeCounter.FALSE_MODELを指定する.TimeCounter.TRUE_MODELが最速の
	 * 描画モデル（１フレームに１文字追加）となり、それ以上の速度は１フレームに２文字以上のテキストを可視化する
	 * 専用のLabelModelを定義する必要がある.<br>
	 * @param lm 表示モデル.<br>
	 */
	public TextLabel(float x, float y,
			String text, int idx, TimeCounter tc, LabelModel lm) {
		super(x, y, 1, 1);
		this.text = new StringBuilder(text);
		this.idx = idx;
		this.timeCounter = tc;
		this.labelModel = lm;
		int w = (int) ((lm.getFont().getSize() * 0.66f + 4) * text.length());
		int h = lm.getFont().getSize() + 2;
		setSize(w, h);

	}

	/**
	 * 新しいラベルを作成します.
	 * 
	 * @param x X座標.<br>
	 * @param y Y座標.<br>
	 * @param w 幅.<br>
	 * @param h 高さ.<br>
	 * @param vector
	 * @param text 表示するテキスト.<Br>
	 * @param movingModel 移動モデル.<br>
	 * @param tc タイムカウンタ.使用しない場合はTimeCounter.FALSE_MODELを指定する.TimeCounter.TRUE_MODELが最速の
	 * 描画モデル（１フレームに１文字追加）となり、それ以上の速度は１フレームに２文字以上のテキストを可視化する
	 * 専用のLabelModelを定義する必要がある.<br>
	 * @param lm 表示モデル.<br>
	 */
	public TextLabel(float x, float y, float w, float h,
			VectorF vector, MovingModel movingModel,
			String text, TimeCounter tc, LabelModel lm) {
		super(x, y, w, h, vector, movingModel);
		this.text = new StringBuilder(text);
		this.idx = text.length();
		this.timeCounter = tc;
		this.labelModel = lm;
	}

	/**
	 * 新しいラベルを作成します.
	 * 
	 * @param x X座標.<br>
	 * @param y Y座標.<br>
	 * @param w 幅.<br>
	 * @param h 高さ.<br>
	 * @param vector
	 * @param text 表示するテキスト.<Br>
	 * @param idx 表示する文字数.<br>
	 * @param movingModel 移動モデル.<br>
	 * @param tc タイムカウンタ.使用しない場合はTimeCounter.FALSE_MODELを指定する.TimeCounter.TRUE_MODELが最速の
	 * 描画モデル（１フレームに１文字追加）となり、それ以上の速度は１フレームに２文字以上のテキストを可視化する
	 * 専用のLabelModelを定義する必要がある.<br>
	 * @param lm 表示モデル.<br>
	 */
	public TextLabel(float x, float y, float w, float h,
			VectorF vector, MovingModel movingModel,
			String text, int idx, TimeCounter tc, LabelModel lm) {
		super(x, y, w, h, vector, movingModel);
		this.text = new StringBuilder(text);
		this.idx = idx;
		this.timeCounter = tc;
		this.labelModel = lm;
	}

	/**
	 * ラベルを描画します.
	 * 実際の描画はラベルモデルが行います.<br>
	 * 
	 * @param g 書き込むグラフィックスコンテキスト.<br>
	 */
	@Override
	public void draw(Graphics2D g) {
		if (!isVisible() || !isExist()) {
			return;
		}
		labelModel.drawText(g, this);
	}

	public void draw(Graphics2D g, LabelModel model) {
		if (!isVisible() || !isExist()) {
			return;
		}
		model.drawText(g, this);
	}

	/**
	 * ラベルのテキストを更新します.
	 * 
	 * @param text 新しいテキスト.<br>
	 */
	public void setText(String text) {
		setText(text, true);
	}

	public void setText(String text, boolean allout) {
		this.text.replace(0, this.text.length(), text);
		if (idx > text.length()) {
			idx = text.length();
		}
		if (allout) {
			allChar();
		}
	}

	/**
	 * このラベルのテキストをStringとして取得します.
	 * このメソッドは新しいStringを返します.<br>
	 * 
	 * @return ラベルのテキスト.<br>
	 */
	public String getText() {
		return text.toString();
	}

	/**
	 * このラベルのテキストの実装を返します.
	 * このメソッドは参照を返します.<br>
	 * 
	 * @return ラベルのテキスト.<br>
	 */
	public StringBuilder getStringBuilder() {
		return text;
	}

	/**
	 * このラベルのテキストの表示中の部分文字列を取得します.
	 * 全てのラベルモデルでは、通常、このメソッドを使用し取得した文字列を表示すべきです.<br.
	 * 
	 * @return 表示中の文字列.このラベルに設定されている文字列の0からidxまでの部分文字列.<Br>
	 */
	public String getVisibleText() {
		return text.substring(0, idx);
	}

	/**
	 * 文字表示時間に使用されるタイムカウンタを設定します.
	 * 
	 * @param timeCounter カウンタ.<br>
	 */
	public void setTimeCounter(TimeCounter timeCounter) {
		this.timeCounter = timeCounter;
	}

	/**
	 * 文字表示時間に使用されるタイムカウンタを取得します.
	 * 
	 * @return timeCounter カウンタ.<br>
	 */
	public TimeCounter getTimeCounter() {
		return timeCounter;
	}

	/**
	 * ラベルモデルを設定します.
	 * 
	 * @param labelModel ラベルモデル.<br>
	 */
	public void setLabelModel(LabelModel labelModel) {
		this.labelModel = labelModel;
	}

	/**
	 * ラベルモデルを取得します.
	 * 
	 * @return ラベルモデル.<br>
	 */
	public LabelModel getLabelModel() {
		return labelModel;
	}

	/**
	 * このラベルが全ての文字列を表示しているかを調べます.
	 * 
	 * @return 全ての文字列が可視化されている場合はtrueを返す.<br>
	 */
	public boolean isAllTextVisible() {
		return idx == text.length();
	}

	/**
	 * 表示領域を拡大し、次の文字を可視化します.
	 * テキストがすべて表示されている場合は何も行いません.<br>
	 */
	public void nextChar() {
		if (text.charAt(idx) != ' ' && text.charAt(idx) != '　') {
			if (sound != null) {
				if (!sound.isLoaded()) {
					sound.load();
				}
				sound.again();
			}
		}
		idx = isAllTextVisible() ? text.length() : idx + 1;
	}

	/**
	 * 表示領域を縮小し、前の文字までを可視化します.
	 * テキストが文字も表示されていない場合は何も行いません.<br>
	 */
	public void prevChar() {
		idx = idx == 0 ? 0 : idx - 1;
	}

	/**
	 * 全ての文字を可視化します.
	 */
	public void allChar() {
		idx = text.length();
	}

	/**
	 * 全ての文字を不可視にします.
	 */
	public void resetIdx() {
		idx = 0;
	}

	/**
	 * 1文字表示されるたびに再生されるサウンドを設定します.
	 * サウンドはnullを許容します。<br>
	 *
	 * @param sound サウンドファイルを送信します。<br>
	 */
	public void setSound(Sound sound) {
		this.sound = sound;
	}

	/**
	 * 1文字表示されるたびに再生されるサウンドを取得します.
	 * サウンドはnullを許容します。設定されていない場合はnullを返します。<br>
	 *
	 * @return このラベルに設定されているサウンドファイルを返します。設定されていない場合はnullを返します。<br>
	 */
	public Sound getSound() {
		return sound;
	}

	@Override
	public TextLabel clone() {
		TextLabel tl = (TextLabel) super.clone();
		tl.text = new StringBuilder(text);
		tl.timeCounter = this.timeCounter.clone();
		tl.labelModel = this.labelModel.clone();
		return tl;
	}
}
