import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;

//--------------------------------------------------
// マップキャンバスクラス
//--------------------------------------------------
class MapCanvas extends Canvas implements Runnable, MouseListener, MouseMotionListener, KeyListener{
	// 親アプレット
	MapEdit applet;

	//スレッド
	volatile Thread m_th;
	final private int m_wait = 33;	// SPF
	private long m_lastTime;

	//オフスクリーンのグラフィックス
	Graphics og;

	// 文字取り扱い用オフスクリーンイメージ
	// 会話の文やウィンドウ枠などのイメージ描画
	Image off_screen;

	// ピクセルデータ取り扱い用オフスクリーン
	// マップやキャラなどのイメージ描画
	OffScreen m_pix_off_screen;

	// オフスクリーンのピクセルデータ
	int[] GetOffPix(){ return m_pix_off_screen.GetPix(); }

	// 初期化時間
	double initTime;

	// 前回座標保持
	Point prev_select = new Point();
	int prev_selected_part;

	// 選択座標
	int select_x, select_y;

	// １フレームの処理時間
	static long FrameTime = 0;

	// フレーム数記憶
	static int SumFrameNum = 0;

	// インスタンス
	static MapCanvas m_instance;
	static MapCanvas GetInstance(){ return m_instance; }
	static void NewInstance( MapEdit applet ){ m_instance = new MapCanvas( applet ); }

	MapCanvas( MapEdit applet ){
		this.applet = applet;
	}

	//--------------------------------------------------
	// デバッグプリント
	//--------------------------------------------------
	void DebugPrint( String str ){
		System.out.println( str );
	}

	//--------------------------------------------------
	// スレッド処理
	//--------------------------------------------------
	//スタート（initの次に呼ばれる。最小化から復帰したときも呼ばれる。）
	public void start(){
		DebugPrint( "start()");
		if(m_th == null)
			m_th = new Thread(this);
		m_th.start();
	}
	//ストップ（ウインドウが消えると呼ばれる。最小化でも。）
	public void stop(){
		DebugPrint( "stop()");
		m_th = null;
	}
	public void run(){
		DebugPrint( "run()");
		m_lastTime = System.currentTimeMillis();

		// フォーカス取得
		requestFocus();

		Thread thisThread = Thread.currentThread();
		try{
			//ここがゲームループ
			while(m_th == thisThread){
				// フォーカス取得
				// requestFocus();

				// 歩行アニメ
				CharaManage.GetInstance().WalkAnime();
				PlayerManage.GetInstance().WalkAnime();

				// ゲーム処理
				Game.GetInstance().BasicAction();

				// キーボード処理（ゲームモードのみ）
				if( applet.GetGameMode() == MapEdit.GAME_MODE ){
					Game.GetInstance().BasicKeyAction();
				}

				// リペイント
				MyRepaint();

				//ちょっと休憩　フレーム調整
				sleepThread();

				SumFrameNum++;
			}
			m_th = null;
		}
		catch(Exception e){ }
		System.out.println("endrun()");
	}

	// 一定間隔で画面が更新されるように調整
	private final synchronized void sleepThread()
	{
		Thread.yield();
		//getToolkit().sync();
		final long k = System.currentTimeMillis();
		FrameTime = k - m_lastTime;
		final int w = (int)(m_wait - FrameTime);
		if (w > 0){
			try{
				Thread.sleep(w);
			} catch (InterruptedException e) {}
		}
		else{
			try{
				Thread.sleep(1);
			} catch (InterruptedException e) {}
		}
		m_lastTime = System.currentTimeMillis(); // k + w;
	}

	//--------------------------------------------------
	// 初期化
	//--------------------------------------------------
	public void Initialize(){
		// 初期化にかかる時間を計測
		long waitTime = System.currentTimeMillis();

		//マウス、
		// 編集モード , ゲームモードのみ
		if( MapManage.GetInstance().GetGameMode() == MapManage.EDIT_MODE ||
			MapManage.GetInstance().GetGameMode() == MapManage.GAME_MODE ){
			this.addMouseListener( this );
			this.addMouseMotionListener( this );
		}

		// キーイベント受付
		// ゲームモードのみ
		if( MapManage.GetInstance().GetGameMode() == MapManage.GAME_MODE ){
			this.addKeyListener( this );//キー入力リスナー
		}

		// ゲームモードはゲームクラス作成
		//if( MapManage.GetInstance().GetGameMode() == MapManage.GAME_MODE ){
			Game.GetInstance().Initialize();
		//}

		prev_select.x = 0;
		prev_select.y = 0;
		prev_selected_part = 0;

		// オフスクリーン関連
		Dimension d = getSize();

		// オフスクリーン作成
		if( MapManage.GetInstance().GetGameMode() == MapManage.GAME_MODE ){
			off_screen = createImage( MapManage.WIDTH, MapManage.HEIGHT );
		}else{
			off_screen = createImage( d.width, d.height );
		}
		og = off_screen.getGraphics();

		// メモリイメージ作成(マップ分だけ)
		m_pix_off_screen = new OffScreen( MapManage.WIDTH , MapManage.HEIGHT );

		// マップ描画（メモリイメージに）
		MapManage.GetInstance().DspMap( m_pix_off_screen.GetPix() );

		// キャラ描画（メモリイメージに）
		CharaManage.GetInstance().DrawCharaToMemory( m_pix_off_screen.GetPix() );

		// マップ描画（上層レイヤの通過フラグ２専用）
		MapManage.GetInstance().DspMapUp2( m_pix_off_screen.GetPix() );

		// ここまで
		initTime = System.currentTimeMillis() - waitTime;

		DebugPrint( "map_canvas()="+initTime);
	}

	//--------------------------------------------------
	// 描画
	//--------------------------------------------------
	public void update( Graphics g ){ paint(g); }
	public void paint( Graphics g ){

		Dimension d = getSize();

		// 白でクリア
		og.setColor( Color.white );
		og.fillRect( 0, 0, d.width, d.height );

		// グラフィックスセット
		MapManage.GetInstance().SetGraphics( og );
		CharaManage.GetInstance().SetGraphics( og );
		if( MapManage.GetInstance().GetGameMode() == MapManage.GAME_MODE ){
			Game.GetInstance().SetGraphics( og );
		}

		// オフスクリーンに、メモリイメージを描画
		og.drawImage( m_pix_off_screen.GetImage(), 0, 0, this );
		//og.drawImage( m_pix_off_screen.GetImage(), 0, 0, MapManage.WIDTH<<1, MapManage.HEIGHT<<1, this );

		// エディットモード用 マップ用キャラ描画
		MapManage.GetInstance().DrawChara();

		// 選択座標を枠で囲む
		if( MapManage.GetInstance().GetGameMode() == MapManage.EDIT_MODE ){
			og.setColor( Color.white );
			og.drawRect( (select_x - MapManage.GetInstance().GetNowIndex().x) * MapManage.CHIP_SIZE,
				(select_y - MapManage.GetInstance().GetNowIndex().y) * MapManage.CHIP_SIZE, MapManage.CHIP_SIZE - 1, MapManage.CHIP_SIZE - 1 );
		}

		// 文字列
		MapManage.GetInstance().DrawString();

		// ゲームモード
		if( MapManage.GetInstance().GetGameMode() == MapManage.GAME_MODE ){
			Game.GetInstance().BasicDraw();
		}

		og.drawString("右クリック選択座標：("+select_x+","+select_y+")", 100, 380 );

		// オフスクリーンを描画
		// ２倍にしてみる
		if( MapManage.GetInstance().GetGameMode() == MapManage.GAME_MODE ){
			g.drawImage( off_screen, 0, 0, MapManage.WIDTH<<1, MapManage.HEIGHT<<1, this );
		}else{
			g.drawImage( off_screen, 0, 0, this );
		}
	}

	//--------------------------------------------------
	// マウスクリックでチップセット
	//--------------------------------------------------
	public void mousePressed(MouseEvent e){
		// ゲームモード
		if( MapManage.GetInstance().GetGameMode() == MapManage.GAME_MODE ){
			//左クリックの場合
			if((e.getModifiers() & e.BUTTON1_MASK) != 0){
				int x = e.getX();
				int y = e.getY();
				// クリック処理
				// ２倍画面なら１しふと
				Game.GetInstance().ClickAction( x>>1, y>>1 );
				return;
			}
			// 右クリックの場合(いろいろテスト)
			else{
				// ループマップの場合
				if( applet.IsLoopMap() ){
					// 空へ
					if( Game.GetInstance().GetMapScaleState() == Game.NORMAL_SCALE_MAP ){
						Game.GetInstance().now_phase = Game.TO_SKY_PHASE;
						Game.GetInstance().SkyPhase = 1;
					}
					// 着陸
					else{
						Game.GetInstance().now_phase = Game.TO_SKY_PHASE;
						Game.GetInstance().SkyPhase = 4;
					}
				}
				/*
				// マップ切り替え
				if( Game.GetInstance().now_phase == Game.NORMAL_PHASE ){
					Game.GetInstance().SubPhase = 0;
					Game.GetInstance().now_phase = Game.CHANGE_MAP_PHASE;
				}
				*/

				// 空を飛んでみるテスト
				// Game.GetInstance().ToSky();
				return;
			}
		}

		ChipSet( e );
	}
	public void mouseClicked( MouseEvent e ){}

	// マウスリリース
	public void mouseReleased(MouseEvent e){
		int x = e.getX();
		int y = e.getY();
		Game.GetInstance().MouseReleaseAction( x, y );
	}

	public void mouseEntered(MouseEvent e){}
	public void mouseExited(MouseEvent e){}

	// クリックとドラッグでまとめる
	void ChipSet( MouseEvent e ){
		int x = e.getX();
		int y = e.getY();

		//左クリックの場合
		if((e.getModifiers() & e.BUTTON1_MASK) != 0){
			x /= MapManage.CHIP_SIZE;
			y /= MapManage.CHIP_SIZE;

			// その場所を塗りつぶし
			if( prev_select.x != x || prev_select.y != y || MapManage.GetInstance().GetSelectedPart() != prev_selected_part ){
				MapManage.GetInstance().SetChip( x, y );

				// 記憶しておく
				prev_select.x = x;
				prev_select.y = y;
				prev_selected_part = MapManage.GetInstance().GetSelectedPart();

				// 専用リペイント
				MyRepaint();

				repaint();
			}
		}
		//右クリックの場合
		else if((e.getModifiers() & e.BUTTON3_MASK) != 0){
			x /= MapManage.CHIP_SIZE;
			y /= MapManage.CHIP_SIZE;

			// 選択状態
			this.select_x = MapManage.GetInstance().GetNowIndex().x + x;
			this.select_y = MapManage.GetInstance().GetNowIndex().y + y;

			repaint();
		}
	}

	//MouseMotionListener
	//--------------------------------------------------
	// マウスドラッグでもクリックと同じでチップセット
	//--------------------------------------------------
	public void mouseDragged(MouseEvent e){
		// ゲームモード
		if( MapManage.GetInstance().GetGameMode() == MapManage.GAME_MODE ){
			//左クリックの場合
			if((e.getModifiers() & e.BUTTON1_MASK) != 0){
				int x = e.getX();
				int y = e.getY();
				// クリック処理
				Game.GetInstance().ClickAction( x>>1, y>>1 );
			}
		}
		// 編集モード
		else if( MapManage.GetInstance().GetGameMode() == MapManage.EDIT_MODE ){
			ChipSet( e );
		}
	}

	// マウス移動
	public void mouseMoved(MouseEvent e){
		// ゲームモードではマウスに合わせて枠移動
		if( MapManage.GetInstance().GetGameMode() == MapManage.GAME_MODE ){
			// 最初
			if( Game.GetInstance().now_phase == Game.NORMAL_PHASE ){
				int x = e.getX();
				int y = e.getY();

				x /= MapManage.CHIP_SIZE;
				y /= MapManage.CHIP_SIZE;

				// 選択状態
				Game.GetInstance().select_x = MapManage.GetInstance().GetNowIndex().x + x;
				Game.GetInstance().select_y = MapManage.GetInstance().GetNowIndex().y + y;

				repaint();
			}
			// キャラを選んだ状態、メニュー選択モード
			else if( Game.GetInstance().now_phase == Game.CHARA_SELECT_PHASE ){
				int x = e.getX();
				int y = e.getY();

				Game.GetInstance().MouseMoved( x, y );
				repaint();

			}
		}

	}

	//--------------------------------------------------
	// 外部操作用リペイント
	//--------------------------------------------------
	void MyRepaint(){
		// マップ描画（メモリイメージに）
		MapManage.GetInstance().DspMap( m_pix_off_screen.GetPix() );

		// カメラ座標を渡す
		CharaManage.GetInstance().SetCameraPoint( MapManage.GetInstance().GetNowIndex() );

		// キャラ描画
		CharaManage.GetInstance().DrawCharaToMemory( m_pix_off_screen.GetPix() );

		BattleManage.GetInstance().DrawWeaponToMemory( m_pix_off_screen );

		// マップ描画（上層レイヤの通過フラグ２専用）
		MapManage.GetInstance().DspMapUp2( m_pix_off_screen.GetPix() );

		// 会話ウィンドウ周り
		Game.GetInstance().BasicDrawForPixel( m_pix_off_screen.GetPix() );

		// フェードイン/アウト
		Game.GetInstance().DrawFade();

		// デバッグ情報ウィンドウ
		if( MapManage.GetInstance().GetGameMode() == MapManage.GAME_MODE ){
			Game.GetInstance().DrawDebugInfoWindow();
		}

		// ピクセル更新
		m_pix_off_screen.Renew();
	}

	//キーが押された瞬間(使わない)
	public void keyTyped(KeyEvent e){}

	//キーを押している時
	public void keyPressed(KeyEvent e){
		Game.GetInstance().KeyPressed( e );
	}

	//キーが放された瞬間
	public void keyReleased(KeyEvent e){
		Game.GetInstance().KeyReleased( e );
	}

}
