import java.awt.*;
import java.awt.event.*;
import java.util.*;

//キャンバスクラス	描画領域を担当する
//また、アプレットクラスの参照を持つ
public class BezierCurveCanvas extends Canvas{
	//メンバ
	BezierCurveApplet owner;
	Point mp = new Point();	//現在のマウスポインタの座標
	Image backbufi;			//バックバッファイメージ
	Graphics backbufg;		//バックバッファグラフィック
	Dimension d;
	int dim = 3;				//ベジェ曲線の次元
	int dimMAX = 10;			//次元の上限
	int thick = 1;				//ベジェ曲線の太さ
	int thickMAX = 10;			//太さの上限
	boolean isClose = false;	//開曲線か閉曲線か
	boolean isFill = false;		//塗りつぶしか否か
	boolean isHideHint = false;	//入力点や入力点を結ぶ線を隠すか
	boolean isDrawing = false;	//現在、制御点入力中か否か
	
	int modeflg = 0;			//モードフラグ、0=Draw 1=Edit
	int[] capturedPoint = {-1, -1};
								//編集時、制御点をつかんでいるか。
								//つかんでいないと-1、つかんでいるときは、そのポイントをしめす。
	
	Vector bc = new Vector();	//ベジェ曲線クラスを保持するVector
	IBezierCurve bbuf;			//ベジェ曲線入力バッファ
	int icount = 0;				//入力カウンタ
	
	
	//コンストラクタ
	public BezierCurveCanvas(BezierCurveApplet owner){
		
		this.owner = owner;
		
		//画面初期化
		setSize(640, 480);
		setBackground(Color.black);
		
		d = getSize();

		
		//イベントリスナ作成
		//	マウスイベントリスナ
		addMouseListener(new MouseListener() {
			//	クリックイベント
			public void mouseClicked(MouseEvent e) {
				//	描画モード
				if(modeflg == 0){
					if(icount == 0){		//始めの制御点入力なので、新しくオブジェクトを作る
						if(isClose){
							if(isFill)
								;//bc.add(new BezierCurveCloseFill(dim));
							else
								bc.add(new BezierCurveClose(dim, thick));
						}
						else{
							if(isFill)
								;//bc.add(new BezierCurveFill(dim));
							else
								bc.add(new BezierCurve(dim, thick ,isClose, isFill));
						}
						
						bbuf = (IBezierCurve)bc.get(bc.size()-1);
						bbuf.setHint(isHideHint);
						isDrawing = true;	//制御点入力開始ー
					}
					bbuf.setPoint(e.getPoint(), icount);	//制御点入力
					icount++;
					if(icount == dim && isClose){	//閉曲線の場合次元数が点の数なのでここできる
						bbuf.setPointEnd();
						icount = 0;
						isDrawing = false;	//制御点入力終了ー
					}
					if(icount == dim+1){	//最後の制御点入力なので、終了処理を入れる
						bbuf.setPointEnd();
						icount = 0;
						isDrawing = false;	//制御点入力終了ー
					}
				}
				//	編集モード
				if(modeflg == 1){
				}
				
				repaint();
			}
			public void mouseEntered(MouseEvent e) {;}
			public void mouseExited(MouseEvent e) {;}
			//	マウスプレスイベント 
			public void mousePressed(MouseEvent e) {
				//	描画モード
				if(modeflg == 0){
				}
				//	編集モード
				if(modeflg == 1){
					int i, j;
					mp = e.getPoint();
					for(i = 0; i < bc.size(); i++){
						bbuf = (IBezierCurve)bc.get(i);
						for(j = 0; j < bbuf.size(); j++){
							Point p = bbuf.getPoint(j);
							if(p.x-3 <= mp.x &&		//マウスで押したところが、制御点の内部かどうか
							   p.x+3 >= mp.x &&
							   p.y-3 <= mp.y &&
							   p.y+3 >= mp.y){
							   	capturedPoint[0]=i;//System.out.println("i "+i);
								capturedPoint[1]=j;//System.out.println("j "+j);
							 }
						}
					}
				}
			}
			//	マウスリリースイベント
			public void mouseReleased(MouseEvent e) {
				capturedPoint[0] = capturedPoint[1] = -1;
			}
	    });
		//	マウスモーションイベントリスナ
		addMouseMotionListener(new MouseMotionListener() {
			//	マウスドラッグイベント
			public void mouseDragged(MouseEvent e){
				if(capturedPoint[0] == -1) return;		//-1のときは制御点をつかんでいない
				bbuf = (IBezierCurve)bc.get(capturedPoint[0]);
				bbuf.setPoint(e.getPoint(), capturedPoint[1]);
				mp = e.getPoint();
				repaint();
			}
			public void mouseMoved(MouseEvent e){
				mp = e.getPoint();
				repaint();
			}
		});
		
	}
	
	//バックバッファイニシャライズ
	public void Init(){
		backbufi = createImage(d.width, d.height);
		backbufg = backbufi.getGraphics();
	}
	
	//ペイントメソッド	描画全般を担当
	public void paint(Graphics g){
		//ownerにmouse状態を通知する
		owner.setMPos(mp);
		
		//バックバッファに描きこむ
		//まず、いったんクリア
		backbufg.clearRect(0, 0, d.width, d.height);
		//全てのベジェ曲線を描画
		IBezierCurve bbuf2;
		for(int i=0; i<bc.size(); i++){
			bbuf2 =(IBezierCurve)bc.get(i);
			bbuf2.drawBezier(backbufg, Color.blue);
		}
		
		
		//バックバッファを描画
		g.drawImage(backbufi, 0, 0, this);
	}
	
	public void update(Graphics g){
		paint(g);
	}
	
	//以下、メニュー用アクセスメソッド
	//モードチェンジメソッド
	public int changeMode(){
		if(isDrawing)		//制御点入力中だったらモード変更しない
			return modeflg;
		else{//System.out.println(""+modeflg);
			modeflg = (modeflg+1)%2;
			return modeflg;
		}
	}
	
	//次元変更メソッド
	public void incDim(){
		if(dim < dimMAX)
			dim++;
	}
	public void decDim(){
		if(dim > 3)
			dim--;
	}
	
	//太さ変更メソッド
	public void incThick(){
		if(thick < thickMAX)
			thick++;
	}
	public void decThick(){
		if(thick > 1)
			thick--;
	}
	
	//開閉変更メソッド
	public boolean changeType(boolean b){
		return isClose = b;
	}
	
	//ヒントチェンジメソッド
	public void changeHint(){
		isHideHint = !isHideHint;
		for(int i=0; i<bc.size(); i++){
			bbuf =(IBezierCurve)bc.get(i);
			bbuf.setHint(isHideHint);
		}
		repaint();
	}
	
	//ベジェ曲線クリアメソッド ALL
	public void clearBezierAll(){
		if(isDrawing) return;
		bc.clear();
		repaint();
	}
	
	//ベジェ曲線クリアメソッド DelLast
	public void clearBezierLast(){
		if(isDrawing) return;
		bc.remove(bc.size()-1);
		repaint();
	}

}