package jp.ac.kyutech.mns.ist.play;

import java.awt.Toolkit;
import java.awt.geom.Point2D;
import java.util.ArrayList;

import jp.ac.kyutech.mns.ist.ShortStroke;
import edu.umd.cs.piccolo.nodes.PPath;

/**
 * タイムスライダによる，筆記のなめらかな再生を行うためのクラス
 * 
 * TimePlaySliderが使用する．
 * 
 * @see TimePlaySlider
 * 
 * @author miuramo
 *
 */
public class SSManager {
	ArrayList<SSRange> rangelist;

	float pos = 0;

	int end;

	Point2D penpos = new Point2D.Float();

	public SSManager(Iterable<ShortStroke> ssh) {
		rangelist = new ArrayList<SSRange>();
		int p = 0;
		Point2D preendp = null;
		for (TimePlayable ms : ssh) {
			if (preendp != null) {
				TimePlayMove tpm = new TimePlayMove(preendp, ms.getFirstPoint());
				int e = p + tpm.getSteps();
				add(p, e, tpm);
				p = e;
			}
			int e = p + ms.getSteps();
			add(p, e, ms);
			p = e;
			ms.setVisible(false);
			preendp = ms.getLastPoint();
		}
		TimePlayMove tpm = new TimePlayMove(preendp, preendp);
		int e = p + tpm.getSteps();
		add(p, e, tpm);
		p = e;
		end = p - 1;
	}

	/**
	 * デバッグ用
	 *
	 */
	@Deprecated
	public void showSSManager() {
		// for(SSRange r:rangelist){
		// System.out.println(r.begin+" - "+r.end+" index "+r.index);
		// }
	}

	public void setVisible(boolean mode, int begin, int finish) {
		SSRange rbegin = get(begin);
		SSRange rfinish = get(finish);
		if (mode) {// 右方向（正時間方向）
			rbegin.obj.setVisible(true);
			rbegin.obj.resetShapes();
			rfinish.obj.prepareShapes();
			rfinish.obj.showSubpath(finish - rfinish.begin);
			penpos = rfinish.obj.getPenPoint(finish - rfinish.begin);
			for (int i = rbegin.index + 1; i < rfinish.index; i++) {
				rangelist.get(i).obj.setVisible(true);
			}
		} else {// 左方向（逆時間方向）
			rfinish.obj.setVisible(false);
			rfinish.obj.resetShapes();
			rbegin.obj.setVisible(true);
			rbegin.obj.prepareShapes();
			rbegin.obj.showSubpath(begin - rbegin.begin);
			penpos = rbegin.obj.getPenPoint(begin - rbegin.begin);
			for (int i = rbegin.index + 1; i < rfinish.index; i++) {
				rangelist.get(i).obj.setVisible(false);
			}
		}
	}

	public void setPlayPosition(float fps) { // fps = future position
		if (fps < 0 || end < fps) {
			Toolkit.getDefaultToolkit().beep();
			return;
		}
		// if (fps == end) return;
		if (fps < pos) {
			// System.out.println("back fps "+fps+" < pos "+pos);
			setVisible(false, (int) fps, (int) pos);
			pos = fps;
			// System.out.println("backward");
		} else if (pos < fps) {
			// System.out.println("forward pos "+pos+" < fps "+fps);
			setVisible(true, (int) pos, (int) fps);
			pos = fps;
		}
		// if (!fromSlider) pathslider.setValue(fps);
	}

	public void setPenOffset(PPath pen) {
		pen.setOffset(penpos);
	}

	public void add(int b, int e, TimePlayable ob) {
		SSRange r = new SSRange(b, e, ob);
		r.index = rangelist.size();
		rangelist.add(r);
	}

	/**
	 * 時刻インデックスに対応する 範囲オブジェクトSSRange　を返す
	 * @param p 時刻インデックス
	 * @return 範囲オブジェクト
	 */
	public SSRange get(int p) {
		return find(p, rangelist.get(0), rangelist.get(rangelist.size() - 1));
	}

	/**
	 * 時刻インデックスに対応する 範囲オブジェクトSSRange　を探して返す
	 * @param p 時刻インデックス
	 * @param s 探索開始SSRange
	 * @param e 探索終了SSRange
	 * @return 時刻インデックスに対応する範囲オブジェクト
	 */
	public SSRange find(int p, SSRange s, SSRange e) {
		if (s.isRange(p) == 0)
			return s;
		if (e.isRange(p) == 0)
			return e;
		int m = (s.index + e.index) / 2;
		SSRange mr = rangelist.get(m);
		int cons = mr.isRange(p);
		if (cons == 0)
			return mr;
		else if (cons < 0)
			return find(p, s, mr);
		else
			return find(p, mr, e);
	}
}