package jp.ac.kyutech.mns.ist;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Shape;
import java.awt.geom.GeneralPath;
import java.awt.geom.Point2D;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Hashtable;
import java.util.NoSuchElementException;
import java.util.StringTokenizer;
import java.util.Vector;

import jp.ac.kyutech.mns.ist.filter.Event_onSS;
import jp.ac.kyutech.mns.ist.play.TimePlayable;
import jp.ac.kyutech.mns.ist.util.FileReadWriter;
import jp.ac.kyutech.mns.ist.util.Rammer;
import edu.umd.cs.piccolo.PNode;
import edu.umd.cs.piccolo.activities.PActivity;
import edu.umd.cs.piccolo.nodes.PPath;
import edu.umd.cs.piccolo.util.PBounds;

/**
 * 生徒の筆記（1ストローク）モデル
 * @author miuramo
 *
 */
public class ShortStroke extends PPath implements Serializable, Runnable , TimePlayable {
	private static final long serialVersionUID = 5928762332664417016L;

	//TODO: 筆記解析をするならtrue
	public transient static boolean doAssess = false;

	public float[] sx;
	public float[] sy;
	public short[] penpress;
	public float width;
	public int color;
	public int penid;//ペンのID
	public int paperid;//シートのID
	public long time;
	public int sbackid;

	public transient long id;
	public transient ArrayList<Point2D> tempPts;

	public transient PNode ink;
	public transient Point2D startp;
	public transient Shape full;

	transient Event_onSS event_onss = null;
	
	public String toCsv(){
		SimpleDateFormat sdf = new SimpleDateFormat("\"yyyy/MM/dd HH:mm:ss\"");
		StringBuffer sb = new StringBuffer();
		sb.append(penid);
		sb.append(",");
		sb.append(paperid);
		sb.append(",");
		sb.append(String.valueOf(time));
		sb.append(",");
		sb.append(sdf.format(time));
		sb.append(",");
		sb.append(sx.length);
		sb.append(",");
		for(int i=0;i<sx.length;i++){
			sb.append(sx[i]);
			sb.append(",");
			sb.append(sy[i]);
			sb.append(",");
		}
		String s = sb.toString();
		return s.substring(0,s.length()-1);
	}

	public transient int interval;
	public transient Thread playthread;
	public transient boolean playing;

	//for playing
	public transient ArrayList<Shape> shapel;
	public transient PBounds bounds;

	static Hashtable<Float, BasicStroke> penStrokeHash;
	static Hashtable<Integer, Color> colorHash;

	static {
		penStrokeHash = new Hashtable<Float, BasicStroke>();
		colorHash = new Hashtable<Integer, Color>();
	}

	public static BasicStroke getCachedBasicStroke(float f){ //f=太さ
		if (penStrokeHash.containsKey(f)){
			return penStrokeHash.get(f);
		} else {
			BasicStroke bs = new BasicStroke(
					f/2, BasicStroke.CAP_ROUND,
					BasicStroke.JOIN_ROUND, 90.0f);
			penStrokeHash.put(f, bs);
			return bs;
		}
	}
	public static Color getColor(int f){
		if (colorHash.containsKey(f)){
			return colorHash.get(f);
		} else {
			Color opaqueC = new Color(f);
			Color cl = new Color(opaqueC.getRed(),
					opaqueC.getGreen(), opaqueC.getBlue(), 245); //TODO:ここで筆記の透明度を設定．以前は95
			colorHash.put(f, cl);
			return cl;
		}
	}

	// 新規作成
	public ShortStroke() {
		this(0, (new Color(0,0,90)).getRGB(), 2, new Date().getTime());
	}
	public ShortStroke(int _penid, int _color, int _width, long _time){
		penid = _penid;
		color = _color;
		width = _width;
		time = _time;

		playing = false;
		tempPts = new ArrayList<Point2D>();

		if (doAssess) {
			setPickable(true);
			addEventOnSS();
		}
	}
	public void addEventOnSS() {
		if (event_onss == null){
			event_onss = new Event_onSS(this);
		}
		addInputEventListener(event_onss);
		
	}


	public Color getColor(){
		return ShortStroke.getColor(color);
	}
	public void setColor(Color c){
		setStrokePaint(c);
		//元のデータも書き換える
		color = c.getRGB();
	}
	public void animateToFlushColor(Color flushcolor, long duration, long startwait){
		PActivity a1 = this.animateToStrokeColor(flushcolor, duration);
		PActivity a2 = this.animateToStrokeColor(getColor(), duration);
		a1.setStartTime(System.currentTimeMillis()+startwait);
		a2.startAfter(a1);
	}

	public Point2D getPenPoint(int pos) {
		return new Point2D.Float(sx[pos], sy[pos]);
	}

	public Point2D getFirstPoint() {
		return new Point2D.Float(sx[0], sy[0]);
	}

	public Point2D getLastPoint() {
		return new Point2D.Float(sx[sx.length - 1], sy[sy.length - 1]);
	}

	public synchronized void run() {
		playing = true;
		reset();
		ink.addChild(this);
		moveTo(sx[0], sy[0]);
		for (int i = 1; i < sx.length; i++) {
			lineTo(sx[i], sy[i]);
			ink.repaintFrom(getBoundsReference(), this);
			try {
				Thread.sleep(interval);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			if (!playing)
				return;
		}
		// removeFromParent();
		// ink.addChild(this);
		// ink.repaintFrom(getBoundsReference(), this);

		// if (SnailServer.server.recognizeCB.isSelected())
		// note.recognize(this);
		// note.student.afterAddDBStroke(note, this);
		stop();
	}


	public void suspend() {
		synchronized (playthread) {
			try {
				playthread.wait(); // プロセスを休止する
			} catch (InterruptedException e) {
			}
		}
	}

	public synchronized void resume() {
		playthread.notify();
	}

	public void stop() {
		if (playing)
			playing = false;
		if (playthread != null)
			playthread = null;
		// ink.repaint();
	}

	public synchronized PPath genStroke(String protocol, float inkscale) {
		return genStroke_old(protocol, inkscale);
		// return genStroke_besier(protocol);
	}

	// public PPath getStroke(){
	// if (stroke!=null) return stroke;
	// else return rebuildStroke();
	// }

	public synchronized PPath genStroke_besier(String protocol, float inkscale) {
		StringTokenizer st = new StringTokenizer(protocol);
		Vector<double[]> v = new Vector<double[]>();

		int c = st.countTokens();
		int p = 0;
		sx = new float[c / 2];
		sy = new float[c / 2];

		float tsx = (float) (Integer.parseInt(st.nextToken(), 36) * inkscale);
		float tsy = (float) (Integer.parseInt(st.nextToken(), 36) * inkscale);
		float ttx, tty; // previous values;
		sx[p] = tsx;
		sy[p] = tsy;
		// System.out.println("tsx: "+ tsx + " tsy: "+tsy);
		double[] t = new double[2];
		t[0] = tsx;
		t[1] = tsy;
		v.add(t);
		ttx = tsx;
		tty = tsy;
		while (st.hasMoreElements()) {
			p++;
			float x = (float) (Integer.parseInt(st.nextToken(), 36) * inkscale);
			float y = (float) (Integer.parseInt(st.nextToken(), 36) * inkscale);
			sx[p] = x;
			sy[p] = y;
			if (x != ttx && y != tty) {
				double[] tt = new double[2];
				tt[0] = x;
				tt[1] = y;
				v.add(tt);
			}
		}
		//		FitCurves fc = new FitCurves();
		//		try {
		//			fc.getBezier(v, 4.0);
		//		} catch (ArrayIndexOutOfBoundsException aioobe) {
		//			genStroke_old(protocol, inkscale);
		//		}
		return this;
	}

	public synchronized PPath genStroke_old(String protocol, float inkscale) {
		try {
			StringTokenizer st = new StringTokenizer(protocol);
			time = new Date().getTime();
			// System.out.println(time);

			int c = st.countTokens();
			int p = 0;
			sx = new float[c / 2];
			sy = new float[c / 2];
			// stroke = new MyPPath(this);
			reset();
			float tsx = (float) (Integer.parseInt(st.nextToken(), 36) * inkscale);
			float tsy = (float) (Integer.parseInt(st.nextToken(), 36) * inkscale);
			moveTo((float) tsx, (float) tsy);
			sx[p] = tsx;
			sy[p] = tsy;
			while (st.hasMoreElements()) {
				p++;
				float x = (float) (Integer.parseInt(st.nextToken(), 36) * inkscale);
				float y = (float) (Integer.parseInt(st.nextToken(), 36) * inkscale);
				lineTo((float) x, (float) y);
				sx[p] = x;
				sy[p] = y;
			}
			return this;
		} catch (NoSuchElementException ex) {
			System.out.println(ex.toString());
			return null;
		}
	}

	public synchronized PPath rebuildStroke_old() {
		// stroke = new MyPPath(this);

		reset();
		if (sx.length == 0 || sy.length == 0) {
			System.out.println("長さ0のストロークデータ " + time);
			return this;
		}
		moveTo((float) sx[0], (float) sy[0]);
		for (int i = 0; i < sx.length; i++) {
			lineTo((float) sx[i], (float) sy[i]);
		}
		full = new GeneralPath(this.getPathReference()); // 最後までの筆記を記録

//		removeAllChildren();
//		for(int i=0;i<sx.length;i++){
//			PPath a = PPath.createEllipse(sx[i]-0.3f, sy[i]-0.3f, 0.3f, 0.3f);
//			a.setPaint(getColor(3000000));
//			a.setStrokePaint(getColor(3000000));
//			addChild(a);
//		}
		return this;
		
//		return this;
	}
	public void calcMetrics(){
		if (dist < 0){ //初期値は-1なので。はじめてかどうかのチェック
			lengthInPixel();		
			maxspeedInPixel();
			varspeedInPixel();		
			angle();		
			ramer();
			log();
		}
	}
	public void exportBySieve(){ //TODO:
		calcMetrics();
		FileReadWriter.buffer.add(var_ramer+","+num_choten+","+num_choten2+","+ramer+","+penid+","+time+","+ppd+","+pts+","+dist);
		/*
		 * FileReadWriter.buffer.add(id+","+time+","+sbackid+","+penid+","+paperid+","+
				sx.length+","+length+","+avgspeed+","+varspeed+","+varspeed2+","+maxspeed+","+timediff+","+timed+","+
			num_choten+","+num_choten2+","+numrammer);//研究用
		 */		
		//		FileReadWriter.buffer.add(timed+","+num_choten+","+num_choten2+","+numrammer+","+
		//											varspeed+","+varspeed2+","+avgspeed+","+avgspeed2);//分析1用



		//		FileReadWriter.buffer.add(num_choten+","+varspeed+","+avgspeed);//分析2-1用
		//				FileReadWriter.buffer.add(num_choten2+","+varspeed2+","+avgspeed2);//分析2-2用
		//						FileReadWriter.buffer.add(numrammer+","+varspeed+","+avgspeed);//分析2-3用
		//							FileReadWriter.buffer.add(numrammer+","+varspeed2+","+avgspeed2);//分析2-4用
		//
		//System.out.println(penid+" "+paperid+" count "+sx.length+" len "+length+" avg "+avgspeed+" var "+varspeed+" max "+maxspeed+" td "+timediff);
		//太さと色を設定
	}
	public void exportBySieveAverage(){ //TODO:
		calcMetrics();
		/*
		 * FileReadWriter.buffer.add(id+","+time+","+sbackid+","+penid+","+paperid+","+
				sx.length+","+length+","+avgspeed+","+varspeed+","+varspeed2+","+maxspeed+","+timediff+","+timed+","+
			num_choten+","+num_choten2+","+numrammer);//研究用
		 */		
		//		FileReadWriter.buffer.add(timed+","+num_choten+","+num_choten2+","+numrammer+","+
		//											varspeed+","+varspeed2+","+avgspeed+","+avgspeed2);//分析1用



		//		FileReadWriter.buffer.add(num_choten+","+varspeed+","+avgspeed);//分析2-1用
		//				FileReadWriter.buffer.add(num_choten2+","+varspeed2+","+avgspeed2);//分析2-2用
		//						FileReadWriter.buffer.add(numrammer+","+varspeed+","+avgspeed);//分析2-3用
		//							FileReadWriter.buffer.add(numrammer+","+varspeed2+","+avgspeed2);//分析2-4用
		//
		//System.out.println(penid+" "+paperid+" count "+sx.length+" len "+length+" avg "+avgspeed+" var "+varspeed+" max "+maxspeed+" td "+timediff);
		//太さと色を設定
	}

	public synchronized PPath rebuildStroke() {
		setStroke(getCachedBasicStroke(width));
		setStrokePaint(getColor(color));

//			float h = (float)(avgspeed/3);
//			if (h>1.0) h=1.0f;
//			float b = (float)(Math.log(varspeed+0.01)+0.2);
//			if (b>1.0) b=1.0f;
//			int hh = (int)(h*205)+50;
//			if (hh>255) hh=255;
			//		setStrokePaint(new Color(Color.HSBtoRGB(h, 0.7f, 0.7f)));
			//		if (hh>60) setStrokePaint(new Color(hh,hh,hh));
			//		else setStrokePaint(new Color(255-hh*2,0,0));
		return rebuildStroke_old();
		// return rebuildStroke_besier();
	}

	public synchronized PPath rebuildStroke_besier() { // bezier version
		// float ttx2 = -1, tty2 = 0;
		float ttx1 = 0, tty1 = 0;
		Vector<double[]> v = new Vector<double[]>();
		for (int i = 0; i < sx.length; i++) {
			float x = sx[i];
			float y = sy[i];
			if (x != ttx1 && y != tty1) {
				double[] tt = new double[2];
				double[] tmid = new double[2];
				if (ttx1 != 0 && tty1 != 0) {
					tmid[0] = (x + ttx1) / 2.0;
					tmid[1] = (y + tty1) / 2.0;
					v.add(tmid);
				}
				tt[0] = x;
				tt[1] = y;
				v.add(tt);
			}
			ttx1 = x;
			tty1 = y;
		}
		//		FitCurves fc = new FitCurves();
		//		fc.getBezier(v, 4.0);
		// ((MyPPath)stroke).setSS(this);
		return this;
	}

	//自分の最後と、otherの最初の距離をみる
	public float distance(ShortStroke other){
		if (sx.length==0) return 99999f;
		float tx = sx[sx.length-1];
		float ty = sy[sy.length-1];
		if (other.sx.length==0) return 99999f;
		float ox = other.sx[0];
		float oy = other.sy[0];
		return (float) Math.sqrt((ox-tx)*(ox-tx)+(oy-ty)*(oy-ty));

	}
	public void move(float dx, float dy){//移動
		for(int i=0;i<sx.length;i++){
			sx[i] = sx[i]+dx;
		}
		for(int i=0;i<sy.length;i++){
			sy[i] = sy[i]+dy;
		}

		rebuildStroke();
	}

	public void addPoint(Point2D p) {
		tempPts.add(p);
	}
	public void applyTempPtsToAry(){
		sx = new float[tempPts.size()];
		sy = new float[tempPts.size()];
		penpress = new short[tempPts.size()]; 
		for(int i=0;i<tempPts.size();i++){
			sx[i] = (float)tempPts.get(i).getX();
			sy[i] = (float)tempPts.get(i).getY();
			penpress[i] = 127;
		}
	}
	/**
	 * 生徒PDAからの生筆記データからDB用データを生成
	 *
	 * @param sx X座標配列
	 * @param sy Y座標配列
	 * @return DB格納用バイトデータ
	 */
	public byte[] getXYBytes() {
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		BufferedOutputStream bos;
		DataOutputStream dos;
		try {
			bos = new BufferedOutputStream(baos);
			dos = new DataOutputStream(bos);

			dos.writeInt(sx.length);
			for (int i = 0; i < sx.length; i++) {
				dos.writeFloat(sx[i]);
			}
			for (int i = 0; i < sy.length; i++) {
				dos.writeFloat(sy[i]);
			}
			dos.close();
			bos.close();
			baos.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return baos.toByteArray();
	}
	public byte[] getPseudoPPBytes() {
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		BufferedOutputStream bos;
		DataOutputStream dos;
		try {
			bos = new BufferedOutputStream(baos);
			dos = new DataOutputStream(bos);

			dos.writeInt(sx.length);
			for (int i = 0; i < sx.length; i++) {
				dos.writeShort(128);
			}
			dos.close();
			bos.close();
			baos.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return baos.toByteArray();
	}
	public void debugPrint() {
//		System.out.println("SSDebug "+penid+" "+paperid+" "+new Date(time));
	}

	public ShortStroke clone(){
		ShortStroke newss = new ShortStroke();
		newss.sx = new float[this.sx.length];
		newss.sy = new float[this.sy.length];
		for(int i=0;i<this.sx.length;i++){
			newss.sx[i] = this.sx[i];
		}
		for(int i=0;i<this.sy.length;i++){
			newss.sy[i] = this.sy[i];
		}
		if (this.penpress != null){
			newss.penpress = new short[this.penpress.length];
			for(int i=0;i<this.penpress.length;i++){
				newss.penpress[i] = this.penpress[i];
			}
		}
		newss.time = this.time;
		newss.penid = this.penid;
		newss.color = this.color;
		newss.width = this.width;
		newss.paperid = this.paperid;
		newss.id = this.id;
		return newss;

	}

	public void play(int _interval, PNode _ink, PNode _redink, Note n) {
		if (playing) return;
		// this.prepareStrokeList(_ink);
		// for(TimePlayPath tpp: strokelist){
		// // tpp.snip.setTransparency(0.0f);
		// tpp.snip.setVisible(false);
		// }
		ink = _ink;
		// redink = _redink;
		// note = n;
		interval = _interval;
		playthread = new Thread(this);

		playthread.start();
		try {
			playthread.join();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	// 現在の形状をリストに追加
	public void restoreShape() {
		if (shapel == null) {
			shapel = new ArrayList<Shape>();
		}
		Shape shape = this.getPathReference();
		shapel.add(new GeneralPath(shape));
	}

	// リセット
	public void resetShapes() {
		if (full == null) {
			rebuildStroke();
		}
		if (shapel == null) {
			shapel = new ArrayList<Shape>();
		}
		setPathTo(full);
		shapel.clear();
	}

	// 形状を保存
	public void prepareShapes() {
		if (shapel == null) {
			shapel = new ArrayList<Shape>();
		}
		shapel.clear();
		GeneralPath gp = new GeneralPath();
		gp.moveTo(sx[0], sy[0]);
		shapel.add(new GeneralPath(gp));
		for (int i = 1; i < sx.length; i++) {
			gp.lineTo(sx[i], sy[i]);
			shapel.add(new GeneralPath(gp));
		}
	}

	public int getSteps() {
		return sx.length;
	}
	//TODO:
	public transient double[] speedary;
	public transient double[] speedary2;
	public transient double dist = -1;
	public transient double length2;
	public transient double avgspeed;
	public transient double avgspeed2;
	public transient double varspeed;
	public transient double varspeed2;
	public transient double maxspeed;
	public transient ShortStroke previous;
	public transient long timediff;
	public transient long timed;
	public transient double[] angleary ;
	public transient double[] angleary2 ;
	public transient double[] angleary3 ;
	public transient int num_choten = 0;//90度以上の点の数
	public transient int num_choten2 = 0;//90度以上の点の数 ノイズ除去ver
	public transient double sumangle, avgangle;
	public transient double varangle;
	public transient int ramer;
	public transient double choten1_var;
	public transient double choten1_avg;
	public transient double choten2_var;	
	public transient double choten2_avg;
	public transient int kukan2;
	public transient double var_oreten;
	public transient double var_ramer;
	public transient double ramerthre;
	public transient double ppd, pps,ppr;
	public transient double pts, dbltime;
	
	public int pos; //水井筆記のpos
	public String tag;

	public void print_metrics2(){
		String a[] = new String[]{"var_ramer","ppd","pts","length", "current_begin"};
		for(String fn: a){
			Field f = null;
			try {
				f = ShortStroke.class.getField(fn);
			} catch (NoSuchFieldException e) {
				e.printStackTrace();
			} catch (SecurityException e) {
				e.printStackTrace();
			}
			
			try {
				System.out.println(fn+" : "+f.get(this));
			} catch (IllegalArgumentException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			}
		}
		System.out.println("");
	}
	public void print_metrics(){
		ShortStroke clone = this.clone();
		clone.calcMetrics();
		String a[] = new String[]{"ramerthre","varspeed2","numrammer","var_ramer", "length"};
		for(String fn: a){
			Field f = null;
			try {
				f = ShortStroke.class.getField(fn);
			} catch (NoSuchFieldException e) {
				e.printStackTrace();
			} catch (SecurityException e) {
				e.printStackTrace();
			}
			
			try {
				System.out.println(fn+" : "+f.get(clone));
			} catch (IllegalArgumentException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			}
		}
		System.out.println("size : "+clone.sx.length);
		for(double d: clone.speedary) System.out.print(d+" ");
		System.out.println("");
	}
	private void log() {
		var_oreten = varspeed /( Math.log10(num_choten2+2));
		var_ramer = varspeed / (Math.log10(ramer+2));
		ppd = sx.length/dist;
		pps = sx.length/(ramerthre*5);
		ppr = sx.length/(ramer+1);
		pts = sx.length;
		dbltime = (double)(time - 1360901083972L)/1000;
//		System.out.println("Math.log10 = "+Math.log10(numrammer+2));
	}

	private void ramer() {
		float minx=Float.MAX_VALUE,maxx=Float.MIN_VALUE,miny=Float.MAX_VALUE,maxy=Float.MIN_VALUE;
		for(int i=0;i<sx.length;i++){
			if (sx[i] < minx) minx = sx[i];
			if (sx[i] > maxx) maxx = sx[i];
			if (sy[i] < miny) miny = sy[i];
			if (sy[i] > maxy) maxy = sy[i];
		}
		double w = maxx-minx;
		double h = maxy-miny;
		ramerthre = (w > h) ? w/5 : h/5; 
		ramer = Rammer.getRammerPoints(sx, sy, (float)ramerthre).size()-2;
	}

	private void angle() {
		if (sx.length > 2) {
			angleary = new double[sx.length-2];
			num_choten = 0;
			//1または２か所の合計で80以上曲がっている折れ点の数を数える。
			double prev_angle = -1.0;
			boolean isprev_choten = false;
			for(int i=0;i<sx.length-2;i++){
				double cos = getAngle(new Point2D.Float(sx[i],sy[i]), new Point2D.Float(sx[i+1],sy[i+1]), new Point2D.Float(sx[i+2],sy[i+2]));
				angleary[i] = cos;
				if (cos > -0.17) {
					num_choten++;
					isprev_choten = true;
				}
				else if ((cos + prev_angle > -1.53) && isprev_choten==false) {//(cos > -0.8) && (prev_angle > -0.8)
					num_choten++;
					isprev_choten = true;
				} else {
					isprev_choten = false;
				}
				sumangle += cos;
				prev_angle = cos;
			}
		}	
		//　初めの二つの角度について除外
		if(sx.length > 4){
			angleary2 = new double[sx.length-4];
			double prev_angle2 = -1.0;
			boolean isprev_choten2 = false;
			num_choten2 = 0;
			for(int i=0;i<sx.length-4;i++){
				double cos2 = getAngle(new Point2D.Float(sx[i+2],sy[i+2]), new Point2D.Float(sx[i+3],sy[i+3]), new Point2D.Float(sx[i+4],sy[i+4]));
				angleary2[i] = cos2;
				if (cos2 > -0.17) {
					num_choten2++;
					isprev_choten2 = true;
				}
				else if ((cos2 + prev_angle2 > -1.53) && isprev_choten2==false) {//(cos > -0.8) && (prev_angle > -0.8)
					num_choten2++;
					isprev_choten2 = true;
				} else {
					isprev_choten2 = false;
				}
				prev_angle2 = cos2;
			}
			//折れ点の数をノイズ分ひく
			if(angleary2.length > 0){
				if(angleary2[angleary2.length-1] > -0.17  && speedary[speedary.length-1] < 1.0){
					num_choten2--;
				}
			}	
			if(angleary2.length > 1){
				if(angleary2[angleary2.length-2] > -0.17  && (speedary[speedary.length-1]+speedary[speedary.length-2]) < 2.0){
					num_choten2--;
				}
			}
		}	
	}

	public void setPreviousSS(ShortStroke pre){
		if (pre == null) return;
		if (pre.penid != this.penid) return;
		if (pre.paperid != this.paperid) return; 
		if (pre.id == this.id-1) {
			previous = pre;
			timediff = this.time - previous.time;
			long pretime = ((previous.sx.length-1)*1000)/75;
			timed =  timediff - pretime;
		}
	}
	//筆記のパスの長さ（これをgetSteps()で割ったら平均速度になる）
	public double lengthInPixel(){
		double len = 0;
		double len2 = 0;
		if (sx.length>1){
			speedary = new double[sx.length-1];							
			for(int i=1;i<sx.length;i++){
				speedary[i-1] = Math.sqrt((sx[i]-sx[i-1])*(sx[i]-sx[i-1])+(sy[i]-sy[i-1])*(sy[i]-sy[i-1]));
				len = len + speedary[i-1];
				//	System.out.println(i+"len1 :"+speedary[i-1]);		
			}
		}
//		System.out.println("");
		if (sx.length > 3) {
			speedary2 = new double[sx.length-3];
			for(int i=3;i<sx.length;i++){
				speedary2[i-3] = Math.sqrt((sx[i]-sx[i-1])*(sx[i]-sx[i-1])+(sy[i]-sy[i-1])*(sy[i]-sy[i-1]));
				//System.out.println("speedary : "+speedary[i-1]);			
				len2 = len2 + speedary2[i-3];
				//System.out.println(i+"len2 :"+speedary2[i-3]);
			}
			kukan2 = speedary2.length;
		}
//		System.out.println("");
		if (sx.length > 4 ) {
			for(int i=0;i<sx.length;i++){
			}
//			System.out.println("");
			angleary3 = new double[sx.length-4];
			//			num_choten = 0;
			//1または２か所の合計で90以上曲がっている折れ点の数を数える。　但し初めの二つの角度については除外
			for(int i=0;i<sx.length-4;i++){
				double cos = getAngle(new Point2D.Float(sx[i+2],sy[i+2]), new Point2D.Float(sx[i+3],sy[i+3]), new Point2D.Float(sx[i+4],sy[i+4]));
				angleary3[i] = cos;
			}	
//			System.out.println("同じ"+angleary3.length+speedary.length+sx.length);
			if(angleary3.length > 1){

				if(angleary3[angleary3.length-1] > -0.17  && speedary[speedary.length-1] < 1.0){
//					System.out.println("ts");
					len2 = len2 - speedary2[speedary2.length-1];
					kukan2 = kukan2 - 1;
				}
			}	
			if(angleary3.length > 2){
				if(angleary3[angleary3.length-2] > -0.17  && (speedary[speedary.length-1]+speedary[speedary.length-2]) < 2.0){			
					len2 = len2 - speedary2[speedary2.length-1] - speedary2[speedary2.length-2];
					kukan2 = kukan2 - 2;					
				}	
			}
		}	
		dist = len;
		length2 = len2;
		return len;
	}

	public double maxspeedInPixel(){ //最大瞬間速度
		double len = 0;
		double tmp = 0;
		if (sx.length >1){
			if (speedary == null) lengthInPixel();
			for(int i=0;i<speedary.length;i++){
				tmp = speedary[i];
				if (len < tmp) len = tmp;		
			}
		}
		maxspeed = len;
		return len;
	}

	public double varspeedInPixel(){//速度の分散
		double var = 0;
		double var2 = 0;

		if (sx.length >1){
			if (speedary == null) lengthInPixel();
			avgspeed = dist/speedary.length; //平均速度
			for(int i=0;i<speedary.length;i++){
				double tmp = speedary[i]-avgspeed;
				var = var + (tmp*tmp);
			}
			var = var / speedary.length;
			varspeed = var;
		}
		if (sx.length >3){

			if (speedary2 == null) lengthInPixel();
			avgspeed2 = length2/kukan2;//平均速度
			for(int i=0;i<speedary2.length;i++){
				double tmp2 = speedary2[i]-avgspeed2;
				var2 = var2 + (tmp2*tmp2);
			}
			var2 = var2 / kukan2;
			varspeed2 = var2;
		}
		return var;
	}

	//なす角のcosを求める．1なら反復，-1なら直進
	public static double getAngle(Point2D m1, Point2D m2, Point2D m3){
		double a = m1.distance(m2);
		double b = m2.distance(m3);
		double c = m3.distance(m1);
		double cosC = (a*a+b*b-c*c)/(2*a*b);
		//          System.out.println("a "+a+"  b "+b+"  c "+c+"  cosC "+cosC);
		return cosC;
	}

	/**
	 * 途中までの線を構築する
	 */
	public void showSubpath(int pos) {
		reset();
		setPathTo(shapel.get(pos));
	}

	public String getDateTime() {
		SimpleDateFormat sdf = new SimpleDateFormat("\"yyyy/MM/dd HH:mm:ss\"");
		return sdf.format(time);
	}
	//ストローク終了時刻とストローク開始時刻の差
	public String toCsvTeinei() {
		
		return null;
	}
	
	public long current_begin;
	public double current_begin_duration;
	public int sec10size;
	public int sec30size;
	public int sec60size;
	
}



/*
 * for(int i=0;i<sx.length;i++){ float x = sx[i]; float y = sy[i]; if (x !=
 * ttx1 && y != tty1){ if (((tty1-tty2)*(x-ttx1))!=((ttx1-ttx2)*(y-tty1))){
 * double[] tt = new double[2]; tt[0] = x; tt[1] = y; v.add(tt); } ttx2 = ttx1;
 * tty2 = tty1; } ttx1 = x; tty1 = y; }
 */

