package jp.ac.kyutech.mns.ist.util;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.TreeMap;


public class Rammer {

	public TreeMap<Integer, Point2D> tempMap;// メンバ変数
	public ArrayList<Point2D> inip;
	public TreeMap<Integer, Double> distance;

	public int numlen;
	double THRE;
	
	public static ArrayList<Point2D> getRammerPoints(float[] sx, float[] sy, float thre){
		ArrayList<Point2D> srcpts = new ArrayList<Point2D>();
		for(int i=0;i<sx.length;i++){
			srcpts.add(new Point2D.Float(sx[i],sy[i]));
		}
		return getRammerPoints(srcpts, thre);
	}
	public static ArrayList<Point2D> getRammerPoints(ArrayList<Point2D> pts, float thre){
		ArrayList<Point2D> ramerpoints = new ArrayList<Point2D>();
		if (pts.size()<2) {
			return ramerpoints;
		}
		TreeMap<Integer, Point2D> tempMap = new TreeMap<Integer, Point2D>();// TreeMapの受け皿を作る，最初と最後の座標情報を入れておく↓
		tempMap.put(0, pts.get(0));
		tempMap.put(pts.size() - 1, pts.get(pts.size() - 1));

		Rammer ml = new Rammer(pts,tempMap, thre); // TreeMapとPoint2Dの取得正規化座標列を入れる

		for (int i : tempMap.keySet() /*= 0; i < tempMap.size() - 1; i++*/) { // tempMapに格納された特徴点マップをラマ—に入れる。
			ramerpoints.add(tempMap.get(i));
		}
		return ramerpoints;
	}

	public Rammer(ArrayList<Point2D> inip, TreeMap<Integer, Point2D> tempMap, float thre) {
		this.tempMap = tempMap;
		this.inip = inip;
		numlen = inip.size();
		THRE = thre;//TODO 閾値(2.0~10.0) 文字サイズ小
//		THRE = 9.0;//文字サイズ大
		selectPoint(0, numlen - 1);// オブジェクトを生成時に処理を一気にやらせる。
	}

	public void selectPoint(int i, int end) {// iとendの値のポイントについて距離が高いものをtreetempに入れる

		double thresholddist = THRE;//TODO 閾値(2.0~10.0)
		double tempdist;
		double oldtempdist = 0.0;
		int index = -1;
		boolean flag = false; // 高いものがあったかどうかのフラッグ
		Point2D tempP;

		for (int j = i + 1; j < end; j++) {// 引数の2点間だけループ

			tempP = getSuisen(inip.get(i), inip.get(end), inip.get(j));

			tempdist = inip.get(j).distance(tempP);

			if (tempdist > oldtempdist && tempdist > thresholddist) {// 過去の距離と閾値の比較
				index = j; // インデックス変更
				oldtempdist = tempdist;
				flag = true;
			}

		}
		// 一番距離が遠いものがあればTreeMapに代入する
		if (flag = true && index != -1) {
			tempMap.put(index, inip.get(index));

			flag = false;
			if (index != i + 1)
				selectPoint(i, index);
			if (index != end - 1)
				selectPoint(index, end);
		}

	}

	//垂線との交点をもとめるメソッド(n1p-n2p の線分に，pの点から下ろす)
	public Point2D getSuisen(Point2D n1p, Point2D n2p, Point2D p) {
		double a, b, c, py; // 線分を，ax + by = c の形式に変換
		c = n1p.getX() * n2p.getY() - n2p.getX() * n1p.getY();
		b = n2p.getX() - n1p.getX();
		a = n1p.getY() - n2p.getY();
		py = n1p.getY(); // 水平線のときは，線分を構成するどちらかの点のy座標．
		Point2D tempFP = calcfootPoint(a, b, c, py, p);
		double len_1_2 = n1p.distance(n2p);
		double len_1_fp = n1p.distance(tempFP);
		double len_2_fp = n2p.distance(tempFP);
		if (len_1_2 < len_1_fp)
			return n2p;
		else if (len_1_2 < len_2_fp)
			return n1p;
		else
			return tempFP;
	}

	public Point2D.Double calcfootPoint(double la, double lb, double lc,
			double lpy, Point2D p) {
		double x, y;
		if (la == 0) {// 水平線の時
			x = p.getX();
			y = lpy;
		} else {
			double ld = lb * p.getX() - la * p.getY();
			double bumbo = la * la + lb * lb;
			x = (lb * ld - la * lc) / bumbo;
			y = (lb * x - ld) / la;
		}
		return new Point2D.Double(x, y);
	}

}