import java.awt.*;
import java.applet.*;
import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.awt.image.*;
import java.util.StringTokenizer;

//--------------------------------------------------
// キャラ管理クラス
//--------------------------------------------------
class CharaManage extends BasicManage{
	//--------------------------------------------------
	// 定数
	//--------------------------------------------------
	// キャラ最大数
	final byte CHARA_MAX = 99;

	// キャライメージ最大数
	final byte CHARA_IMAGE_MAX = 99;

	// 最大でか画像数
	final byte BIG_IMAGE_MAX_NUM = 10;

	// でか画像の幅
	final short BIG_IMAGE_WIDTH = 288;
	final short BIG_IMAGE_HEIGHT = 256;

	// キャラの幅
	final byte CHARA_WIDTH = 24;
	final byte CHARA_HEIGHT = 32;

	// 中央への補正値
	static final byte CENTER_OFFSET_X = -4;
	static final byte CENTER_OFFSET_Y = -16;

	// キャラアニメ数
	static final byte ANIME_NUM = 3;
	// 一枚あたりのキャラ数
	final byte ONE_CHARA_NUM = 8;

	//--------------------------------------------------
	// メンバ
	//--------------------------------------------------
	// でかキャラチップ
	private Image BigCharaImage[];

	// それぞれのキャライメージ
	CharaImage chara_image[];

	// キャラ
	Chara chara[];

	// カメラ座標
	Point camera = new Point();

	// キャラ登場数
	int CharaNum;

	// イベントテーブル用文字列バッファ
	StringBuffer sb[];

	// イベントテーブルの行数
	int EventLineNum;

	// イメージファイル履歴
	String file_history[] = new String[ BIG_IMAGE_MAX_NUM ];

	// 履歴インデックス
	int history_index = 0;

	// キャラ表示用 ソートリスト
	Chara sort_chara[] = new Chara[ CHARA_MAX + PlayerManage.GetInstance().m_player_num ];
	// 全登場キャラ数
	int m_all_chara_num;

	// インスタンス
	static CharaManage m_instance;
	static CharaManage GetInstance(){ return m_instance; }
	static void NewInstance( MapEdit applet ){ m_instance = new CharaManage( applet ); }

	//--------------------------------------------------
	// コンストラクタ
	//--------------------------------------------------
	CharaManage( MapEdit applet ){
		this.applet = applet;
	}

	//--------------------------------------------------
	// 初期化
	//--------------------------------------------------
	void Initialize(){
		// キャラ用でか画像32個
		BigCharaImage = new Image[ 32 ];

		// キャラ画像50個生成
		chara_image = new CharaImage[ CHARA_IMAGE_MAX ];

		// キャラ99体
		chara = new Chara[ CHARA_MAX ];

		// イベントリストは最大100行
		sb = new StringBuffer[ CHARA_MAX+1 ];

		// 変数初期化
		Reset();
	}

	//--------------------------------------------------
	// リセット(マップ再読み込み用)
	//--------------------------------------------------
	void Reset(){
		int i;

		// ファイル履歴も消去
		for( i = 0; i < history_index; i++ ){
			file_history[ i ] = "";
		}

		history_index = 0;
		CharaNum = 0;
		EventLineNum = 0;
	}

	//--------------------------------------------------
	// キャラ画像読み込み
	//--------------------------------------------------
	void LoadCharaImage( String file, int no, MediaTracker mediaT ){
		BigCharaImage[ no ] = applet.getImage( applet.getDocumentBase(), file );
		mediaT.addImage( BigCharaImage[ no ], 0 );
	}

	//--------------------------------------------------
	// グラフィックスセット
	//--------------------------------------------------
	void SetGraphics( Graphics g ){
		this.g = g;
	}

	//--------------------------------------------------
	// キャラ作成
	//--------------------------------------------------
	void MakeChara(){
		int i, j, k, id;

		DebugPrint( "MakeChara()" );

		// でかキャライメージをピクセル分解して、それぞれのキャラを作成
		for( i = 0; i < history_index; i++ ){
			int[] CharaPixels = new int[ BIG_IMAGE_WIDTH * BIG_IMAGE_HEIGHT ];
			PixelGrabber pg = new PixelGrabber( BigCharaImage[ i ], 0, 0, BIG_IMAGE_WIDTH, BIG_IMAGE_HEIGHT, CharaPixels, 0, BIG_IMAGE_WIDTH );
			try{
				pg.grabPixels();
			}catch( InterruptedException e ){
				System.err.println("Error");
			}

			// でかチップ１枚につきキャラ８体
			for( id = 0; id < ONE_CHARA_NUM; id++ ){
				// コンストラクタ
				chara_image[ ONE_CHARA_NUM*i+id ] = new CharaImage();

				// 透過色の指定 最初の1pixel
				chara_image[ ONE_CHARA_NUM*i+id ].AlphaColor = CharaPixels[ 0 ];

				// 作成
				// 方向４、アニメ３
				for( j = 0; j < DIR_NUM; j++ ){
					for( k = 0; k < ANIME_NUM; k++ ){
						MakeChipImageByBigImage( chara_image[ ONE_CHARA_NUM * i + id ].chip_image[ j ][ k ], CharaPixels,
							CHARA_WIDTH, CHARA_HEIGHT,
							( CHARA_WIDTH * k ) + ( CHARA_WIDTH * ANIME_NUM )*( id % (ONE_CHARA_NUM/2) ),	// x
							( CHARA_HEIGHT * j ) + ( CHARA_HEIGHT * DIR_NUM ) * ( id / (ONE_CHARA_NUM/2) ),	// y
							BIG_IMAGE_WIDTH );
					}
				}
			}
		}

		// キャラのイメージセット
		for( i = 0; i < CharaNum; i++ ){
			// イメージIDを取得
			// でかID×8＋ちびID
			int id2 = chara[i].BigImageID * ONE_CHARA_NUM + chara[i].image_id;
			chara[ i ].SetImage( chara_image[ id2 ] );
		}
	}


	//--------------------------------------------------
	// キャラ検索 引数はワールド座標
	//--------------------------------------------------
	Chara SearchChara( int x, int y ){
		int i;

		// 検索
		for( i = 0; i < CharaNum; i++ ){
			// HIT
			if( chara[i].px / MapManage.CHIP_SIZE == x &&
				chara[i].py / MapManage.CHIP_SIZE == y ){
				return chara[i];
			}
		}
		return null;
	}

	//--------------------------------------------------
	// キャラ検索 引数はワールド座標 + イベント開始方法
	//--------------------------------------------------
	Chara SearchChara( int x, int y, int way ){
		int i;

		// 検索
		for( i = 0; i < CharaNum; i++ ){
			// HIT
			if( chara[i].px / MapManage.CHIP_SIZE == x &&
				chara[i].py / MapManage.CHIP_SIZE == y &&
				chara[ i ].GetEventWay() == way ){
				return chara[i];
			}
		}
		return null;
	}

	//--------------------------------------------------
	// 歩行アニメ
	//--------------------------------------------------
	void WalkAnime(){
		int i;

		for( i = 0; i < CharaNum; i++ ){
			chara[i].RenewAnime();
		}
	}

	// 見かけの座標変換
	int ToDspScreenX( int x ){
		x = ToScreenX( x );
		if( x >= MapManage.GetInstance().m_total_width - MapManage.CHIP_SIZE ){
			x -= MapManage.GetInstance().m_total_width;
		}else if( x <= - (MapManage.GetInstance().m_total_width - MapManage.WIDTH) ){
			x += MapManage.GetInstance().m_total_width;
		}
		return x;
	}
	int ToDspScreenY( int y ){
		y = ToScreenY( y );
		if( y >= MapManage.GetInstance().m_total_height - MapManage.CHIP_SIZE ){
			y -= MapManage.GetInstance().m_total_height;
		}else if( y <= - (MapManage.GetInstance().m_total_height - MapManage.HEIGHT) ){
			y += MapManage.GetInstance().m_total_height;
		}
		return y;
	}
	//--------------------------------------------------
	// 描画
	//--------------------------------------------------
	void DrawCharaToMemory( int OffPix[] ){
		int i;
		int x,y;

		// 縮小モードならキャラを消す
		if( Game.GetInstance().GetMapScaleState() != Game.NORMAL_SCALE_MAP ){
			return;
		}

		// 見かけ上の座標（ループマップ対策
		int dsp_x, dsp_y;

		// Y座標の小さいものから表示
		// 単純選択ソートでおｋ
		// int sort_list[] = new int[ CharaNum ];
		Chara temp;

		// どうせ毎フレーム来るから１ステップだけにしとく。
		for( i = 0; i < m_all_chara_num - 1; i++ ){
			if( ToDspScreenY( sort_chara[ i ].py ) > ToDspScreenY( sort_chara[ i + 1 ].py ) ){
				temp = sort_chara[ i + 1 ];
				sort_chara[ i + 1 ] = sort_chara[ i ];
				sort_chara[ i ] = temp;
			}
			// Y座標が同じなら優先度を見て交換
			else if( ToDspScreenY( sort_chara[ i ].py ) == ToDspScreenY( sort_chara[ i + 1 ].py ) &&
						sort_chara[ i ].priority > sort_chara[ i + 1 ].priority ){
				temp = sort_chara[ i + 1 ];
				sort_chara[ i + 1 ] = sort_chara[ i ];
				sort_chara[ i ] = temp;
				//DebugPrint("("+i+"<->"+(i+1)+")" + MapCanvas.SumFrameNum );
			}
		}

		for( i = 0; i < m_all_chara_num; i++ ){
			// 座標変換
			// マップループ対策　見かけ上の座標を変換
			if( applet.IsLoopMap() ){
				dsp_x = ToDspScreenX( sort_chara[ i ].px );
				dsp_y = ToDspScreenY( sort_chara[ i ].py );
			}else{
				dsp_x = ToScreenX( sort_chara[ i ].px );
				dsp_y = ToScreenY( sort_chara[ i ].py );
			}
			dsp_x += CENTER_OFFSET_X;
			dsp_y += CENTER_OFFSET_Y;

			drawChipImageToMemory( OffPix, sort_chara[i].GetChipImage(), dsp_x, dsp_y,
				sort_chara[i].GetAlphaColor(), MapManage.WIDTH, MapManage.HEIGHT );
		}

		// バトルモードの場合、キャラの上にHPメータ表示
		if( Game.GetInstance().GetNowPhase() == Game.BATTLE_PHASE ){
			DrawHpMeter();
		}
	}

	//--------------------------------------------------
	//  HPメーター描画
	//--------------------------------------------------
	void DrawHpMeter(){
		int i;
		// 見かけ上の座標（ループマップ対策
		int dsp_x, dsp_y;
		int color;

		for( i = 0; i < m_all_chara_num; i++ ){
			// 座標変換
			// マップループ対策　見かけ上の座標を変換
			if( applet.IsLoopMap() ){
				dsp_x = ToDspScreenX( sort_chara[ i ].px );
				dsp_y = ToDspScreenY( sort_chara[ i ].py );
			}else{
				dsp_x = ToScreenX( sort_chara[ i ].px );
				dsp_y = ToScreenY( sort_chara[ i ].py );
			}
			dsp_x += CENTER_OFFSET_X;
			dsp_y += CENTER_OFFSET_Y;

			Game.GetInstance().fillRectToMemory( MapCanvas.GetInstance().GetOffPix(), dsp_x, dsp_y, 24, 2, 0xFF000000 );

			// 元気は緑
			if( sort_chara[ i ].m_hp > 10 ){
				color = 0xff00ff00;
			}
			// ピンチは赤
			else{
				color = 0xffff0000;
			}

			Game.GetInstance().fillRectToMemory( MapCanvas.GetInstance().GetOffPix(), dsp_x, dsp_y, sort_chara[ i ].m_hp, 2, color );
		}
	}

	//--------------------------------------------------
	//  メモリイメージに描画
	//--------------------------------------------------
	void drawChipImageToMemory( int []off, ChipImage chip_image, int x, int y, int aplha_color, int off_width, int off_height ){
		int xx, yy, yyy;
		int point;
		for( yy = 0; yy < CHARA_HEIGHT; yy++ ){
			yyy = (yy+y)*off_width;
			for( xx = 0; xx < CHARA_WIDTH; xx++ ){
				// 領域外なら書き込まない
				if( x + xx < 0 || x + xx > off_width ){ continue; }
				if( y + yy < 0 || y + yy > off_height ){ continue; }

				// 書き込む場所
				point = x + xx + yyy;
				if( point >= 0 && point < off_width * off_height ){
					// 透過色ならスキップ
					if( chip_image.pix[ xx + yy*CHARA_WIDTH ] == aplha_color ) continue;

					off[ point ] = chip_image.pix[ xx + yy*CHARA_WIDTH ];
					//off[ x + xx + (yy+y)*MapManage.WIDTH ] = 0xFFFF0000;
				}
			}
		}
	}

	// カメラの座標セット
	void SetCameraPoint( Point p ){
		this.camera.x = p.x;
		this.camera.y = p.y;
	}

	//--------------------------------------------------
	// イベントリスト読み込み
	//--------------------------------------------------
	void LoadEventList( String file ){
		int i, j;
		DebugPrint( file );

		try{
			InputStream is = new URL( applet.getDocumentBase(), file ).openStream();

			// テキストだからリーダーを使う
			BufferedReader br = new BufferedReader( new InputStreamReader( is ) );

			// ライン格納
			String line;

			DebugPrint( "event_load_start" );

			// 一行ずつ読み込む
			int line_num = 0;
			while( ( line = br.readLine() ) != null ){
				// バッファに追加していく（StringBufferは軽いはず…）
				sb[line_num] = new StringBuffer();
				sb[line_num].append( line );
				line_num++;
			}
			is.close();

			EventLineNum = line_num;

			// 解析してキャラ配置
			AnalyzeEventTable();

		}catch( IOException e ){
			// イベントリストがない時もありえる
			DebugPrint( "load_fail" );
		}

		// 主人公配置

		// 全登場キャラ（主人公と合わせる）
		m_all_chara_num = CharaNum + PlayerManage.GetInstance().m_player_num;

		// ソートリストに登録
		for( i = 0; i < CharaNum; i++ ){
			sort_chara[ i ] = chara[ i ];
		}
		for( i = 0; i < PlayerManage.GetInstance().m_player_num; i++ ){
			sort_chara[ i + CharaNum ] = PlayerManage.GetInstance().GetPlayerInstance( i );
		}

		// 先に完全ソートしとく
		Chara temp;
		for( i = 0; i < m_all_chara_num - 1; i++ ){
			for( j = i + 1; j < m_all_chara_num; j++ ){
				if( sort_chara[ i ].py > sort_chara[ j ].py ){
					temp = sort_chara[ j ];
					sort_chara[ j ] = sort_chara[ i ];
					sort_chara[ i ] = temp;
				}
				// Y座標が同じなら優先度を見て交換
				else if( sort_chara[ i ].py == sort_chara[ j ].py &&
							sort_chara[ i ].priority > sort_chara[ j ].priority ){
					temp = sort_chara[ j ];
					sort_chara[ j ] = sort_chara[ i ];
					sort_chara[ i ] = temp;
					//DebugPrint("("+i+"<->"+(i+1)+")" + MapCanvas.SumFrameNum );
				}
			}
		}
	}

	//--------------------------------------------------
	// イベントテーブル解析
	//--------------------------------------------------
	void AnalyzeEventTable(){
		int i, j;
		int big_chip_id;

		boolean new_flag;

		// トークン分割用クラス
		StringTokenizer st;

		history_index = 0;
		for( i = 0; i < EventLineNum; i++ ){
			st = new StringTokenizer( sb[i].toString(), "<>" );

			// チップセットファイル名取得
			String file = st.nextToken();

			// ファイル利用履歴確認
			new_flag = true;
			big_chip_id = history_index;	// とりあえずIDは最新に
			for( j = 0; j < history_index; j++ ){
				// 登録済み
				if( file.equals( file_history[ j ] ) ){
					new_flag = false;
					big_chip_id = j;	// ID更新（前のもの）
					break;
				}
			}

			// 画像の対応は後回しにしてキャラを作成しておく
			chara[ i ] = new Chara();

			// でかちっぷIDセット
			chara[ i ].SetBigImageID( big_chip_id );

			// イメージID
			chara[ i ].SetImageID( Integer.parseInt( st.nextToken() ) );

			// 座標
			int x = Integer.parseInt( st.nextToken() );
			int y = Integer.parseInt( st.nextToken() );
			chara[ i ].SetPoint( x * MapManage.CHIP_SIZE, y * MapManage.CHIP_SIZE );

			// 方向
			chara[ i ].SetDir( Integer.parseInt( st.nextToken() ) );

			// 対応イベント
			if( st.hasMoreTokens() ){
				chara[ i ].SetEvent( st.nextToken() );
			}

			// イベント開始方法
			if( st.hasMoreTokens() ){
				chara[ i ].SetEventWay( Integer.parseInt( st.nextToken() ) );
			}

			// 通行フラグ
			if( file.equals("null.gif") ){
				chara[ i ].SetMoveFlag( true );
			}else{
				chara[ i ].SetMoveFlag( false );
			}

			// 新しいでかチップファイルのようなら登録
			if( new_flag ){
				file_history[ history_index ] = new String( file );
				history_index++;
				DebugPrint(file);
			}
		}

		CharaNum = EventLineNum;
	}
}

