import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.util.StringTokenizer;
import java.io.*;
import java.net.URL;

// マップエディタ
public class MapEdit extends Applet implements ActionListener, AdjustmentListener, ItemListener{
	static boolean RELEASE_MODE = false;

	int map_height;
	int map_width;

	// ゲームモード
	static final int LOOK_ONLY_MODE = 1;	// 閲覧モード
	static final int EDIT_MODE = 0;	// 編集モード
	static final int GAME_MODE = 2;	// ゲームモード
	int GameMode;

	int GetGameMode(){ return GameMode; }

	// スクロールバー２つ
	Scrollbar sb[] = new Scrollbar[2];

	// ボタン4つ
	Button bn[] = new Button[4];

	// チョイス
	Choice cho = new Choice();

	// 作業しているマップID
	static String EditMapID;
	static String GetMapID(){ return EditMapID; }

	// マップデータファイル
	String data_up;
	String data_down;
	String image_data;
	String event_data_file;
	String map_chip_id;

	// 各キャンバス作成
	SelectChipCanvas select_canvas = new SelectChipCanvas();
	SelectChipCanvas select_canvas_up = new SelectChipCanvas();

	// パーティの初期位置
	int m_first_place_x;
	int m_first_place_y;

	// ループマップフラグ
	boolean m_loop_map_flag;
	boolean IsLoopMap(){return m_loop_map_flag;}

	// カメラ座標
	private Point m_camera = new Point( MapManage.WIDTH/2, MapManage.HEIGHT/2 );

	Point GetCamera(){
		return m_camera;
	}
	void SetCamera( int x, int y ){
		m_camera.x = x;
		m_camera.y = y;
	}

	public void start(){
		MapCanvas.GetInstance().start();
	}
	public void stop(){
		MapCanvas.GetInstance().stop();
	}

	//--------------------------------------------------
	// 初期化
	//--------------------------------------------------
	public void init(){
		// 初期化にかかる時間を計測
		long waitTime = System.currentTimeMillis();

		System.out.println("init()");

		// マップID(データファイル名)
		String map_id = getParameter("map_id");

		// ゲームモード
		GameMode = Integer.parseInt( getParameter("GameMode") );

		setLayout( null );

		// ゲームモードならスクロールバー不要
		if( GameMode != GAME_MODE ){
			// スクロールバー作成
			// X方向
			sb[0] = new Scrollbar( Scrollbar.HORIZONTAL );
			sb[0].setLocation( 16-16, 0+MapManage.HEIGHT );
			sb[0].setSize( MapManage.WIDTH, 16 );
			sb[0].addAdjustmentListener( this );
			add( sb[0] );

			// Y方向
			sb[1] = new Scrollbar( Scrollbar.VERTICAL );
			sb[1].setLocation( 0+MapManage.WIDTH, 0 );
			sb[1].setSize( 16, MapManage.HEIGHT );
			sb[1].addAdjustmentListener( this );
			add( sb[1] );
		}

		// 各マネージャーのインスタンス作成
		MapManage.NewInstance( this );
		PlayerManage.NewInstance( this );
		CharaManage.NewInstance( this );
		Game.NewInstance( this );
		TalkManage.NewInstance( this );
		MapCanvas.NewInstance( this );
		BattleManage.NewInstance( this );

		// nocashがあればキャッシュ防止（ブラウザモード）
		if( Integer.parseInt( getParameter("nocash") ) == 1 ){
			RELEASE_MODE = true;
		}

		// マップ管理クラス初期化
		MapManage.GetInstance().Initialize();

		// キャラ管理クラス初期化
		CharaManage.GetInstance().Initialize();

		// プレイヤー管理クラス初期化
		PlayerManage.GetInstance().Initialize();

		// ゲームモードの設定
		MapManage.GetInstance().SetGameMode( GameMode );

		// 主人公キャラ読み込み
		// メディアトラッカー（先ロード用）
		MediaTracker mediaT = new MediaTracker(this);
		PlayerManage.GetInstance().LoadCharaImage( "chara_img/heros.gif", 0, mediaT );
		PlayerManage.GetInstance().LoadCharaImage( "chara_img/norimono.gif", 1, mediaT );
		// ロード待ち
		try{
			mediaT.waitForAll();
		}catch( InterruptedException e ){}
		// 主人公作成
		PlayerManage.GetInstance().MakePlayer();

		// エディタモードは主人公いらない
		if( GameMode != GAME_MODE ){
			PlayerManage.GetInstance().m_player_num = 0;
		}

		// マップ読み込み
		ChangeMap( map_id );

		// 主人公配置
		PlayerManage.GetInstance().SetPlayerLocation( m_first_place_x, m_first_place_y );

		if( MapManage.GetInstance().GetGameMode() == MapManage.EDIT_MODE ){
			bn[2] = new Button("保存");
			bn[2].setLocation( 180, 276+8 );
			bn[2].setSize( 48, 16 );
			bn[2].addActionListener( this );
			add( bn[2] );

			bn[3] = new Button("読込");
			bn[3].setLocation( MapManage.HEIGHT, 276+8 );
			bn[3].setSize( 48, 16 );
			bn[3].addActionListener( this );
			add( bn[3] );
		}

		// ゲームモードならスクロールバー不要
		if( GameMode != GAME_MODE ){
			// チョイス作成
			cho.addItem("昼");
			cho.addItem("夜");
			cho.addItem("グレー");
			cho.setLocation( 200, MapManage.WIDTH );
			cho.setSize( 50, 20 );
			cho.addItemListener( this );
			add( cho );
		}

		// キャンバス追加1(メインマップ)

		// 編集モードは大きく
		if( MapManage.GetInstance().GetGameMode() == MapManage.EDIT_MODE ){
			MapCanvas.GetInstance().setSize( MapManage.WIDTH, 512 );
		}
		// 閲覧モード,ゲームモードは小さく
		else if( MapManage.GetInstance().GetGameMode() == MapManage.LOOK_ONLY_MODE ){
			MapCanvas.GetInstance().setSize( MapManage.WIDTH, MapManage.HEIGHT );
		}
		// ゲームモードは２倍角
		else if( MapManage.GetInstance().GetGameMode() == MapManage.GAME_MODE ){
			MapCanvas.GetInstance().setSize( MapManage.WIDTH<<1, MapManage.HEIGHT<<1 );
		}

		MapCanvas.GetInstance().setLocation( 0, 0 );
		add( MapCanvas.GetInstance() );
		MapCanvas.GetInstance().Initialize();

		// 編集モードはセレクトキャンバス追加
		if( MapManage.GetInstance().GetGameMode() == MapManage.EDIT_MODE ){
			// キャンバス追加2(チップセレクタ)
			select_canvas.setSize( SelectChipCanvas.WIDTH, SelectChipCanvas.HEIGHT );
			select_canvas.setLocation( MapManage.WIDTH+32, 0 );
			add( select_canvas );
			// addの後で初期化を呼ばないとなぜかcreateImageがヌルポを返す
			select_canvas.Initialize( MapManage.GetInstance(), MapCanvas.GetInstance(), MapManage.DOWN_LAYER_MODE );

			// キャンバス追加3(チップセレクタアップ)
			select_canvas_up.setSize( SelectChipCanvas.WIDTH, SelectChipCanvas.HEIGHT );
			select_canvas_up.setLocation( MapManage.WIDTH+32 + MapManage.CHIP_SIZE * 7, 0 );
			add( select_canvas_up );
			// addの後で初期化を呼ばないとなぜかcreateImageがヌルポを返す
			select_canvas_up.Initialize( MapManage.GetInstance(), MapCanvas.GetInstance(), MapManage.UP_LAYER_MODE );
		}

		// ここまで
		MapManage.GetInstance().initTime = System.currentTimeMillis() - waitTime;
	}

	//--------------------------------------------------
	// コンフィグデータ読み込んで設定
	//--------------------------------------------------
	void LoadConfigData( String mapid ){
		String file;
		if( RELEASE_MODE ){
			file = "./map/"+mapid+"/config.txt" + "?" + System.currentTimeMillis();
		}else{
			file = "./map/"+mapid+"/config.txt";
		}
		DebugPrint( file );
		try{
			InputStream is = new URL( this.getDocumentBase(), file ).openStream();

			// テキストだからリーダーを使う
			BufferedReader br = new BufferedReader( new InputStreamReader( is ) );

			// ライン格納
			String line;

			int i;
			DebugPrint( "config_load_start" );

			// 初期化
			m_loop_map_flag = false;

			// 一行ずつ読み込む
			while( ( line = br.readLine() ) != null ){
				// 解析
				AnalyzeConfigLine( line );
			}
			is.close();
		}catch( IOException e ){
			DebugPrint( "load_fail" );
		}
	}

	//--------------------------------------------------
	// コンフィグデータ解析
	//--------------------------------------------------
	void AnalyzeConfigLine( String line ){
		// トークン分割用クラス
		StringTokenizer st;

		st = new StringTokenizer( line, "<>" );
		String key = "";
		String val = "";

		// キー
		if( st.hasMoreTokens() ){
			key = st.nextToken();
		}
		// 値
		if( st.hasMoreTokens() ){
			val = st.nextToken();
		}else{
			val = "0";
		}

		// ハッシュを作るのもめんどうなので検索
		if( key.equals( "Width" ) ){
			map_width = Integer.parseInt( val );
		}
		else if( key.equals( "Height" ) ){
			map_height = Integer.parseInt( val );
		}
		else if( key.equals( "ChipSet" ) ){
			map_chip_id = GetUntilExp( val );	// 拡張子除く
		}
		// パーティの初期位置
		else if( key.equals( "FirstPartyPlaceX" ) ){
			m_first_place_x = Integer.parseInt( val );
		}
		else if( key.equals( "FirstPartyPlaceY" ) ){
			m_first_place_y = Integer.parseInt( val );
		}
		// ループマップ
		else if( key.equals( "LoopMap" ) ){
			m_loop_map_flag = Integer.parseInt( val ) == 1 ? true : false;
		}
	}

	// 拡張子除いて返す
	String GetUntilExp( String file ){
		int index = file.lastIndexOf(".");
		return file.substring( 0, index );
	}

	//--------------------------------------------------
	// マップ切り替え(引数：マップNO)
	//--------------------------------------------------
	void ChangeMap( String mapid ){
		int i;

		// マップIDさえ分かれば、コンフィグデータを開いて各種情報取得できる。
		LoadConfigData( mapid );

		// スクロールバーのサイズ更新
		if( GameMode != GAME_MODE ){
			sb[ 0 ].setValues( 0, 32, 0, map_width + 32 - MapManage.WIDTH/16 );
			sb[ 1 ].setValues( 0, 32, 0, map_height + 32 - MapManage.HEIGHT/16 );
		}

		// マップリセット
		MapManage.GetInstance().Reset( map_width, map_height );

		// キャラリセット
		CharaManage.GetInstance().Reset();

		// メディアトラッカー（先ロード用）
		MediaTracker mediaT = new MediaTracker(this);

		// マップNOによってファイル切り替え
		data_up = "./map/"+mapid+"/map.dat";
		data_down = "./map/"+mapid+"/mapup.dat";
		image_data = "./map_img/"+map_chip_id+".gif";
		event_data_file = "./map/"+mapid+"/event_list.txt";

		// マップデータ読み込み

		// ブラウザならキャッシュが残るので、タイムを付加?
		if( RELEASE_MODE ){
			MapManage.GetInstance().LoadMapData( data_up + "?" + System.currentTimeMillis() );
			MapManage.GetInstance().LoadMapUpData( data_down + "?" + System.currentTimeMillis() );
		}else{
			MapManage.GetInstance().LoadMapData( data_up );
			MapManage.GetInstance().LoadMapUpData( data_down );
		}

		// マップ画像読み込み
		// 画像はほぼ不変なので対策いらないか
		//if( RELEASE_MODE ){
		//	MapManage.GetInstance().LoadMapImage( image_data + "?" + System.currentTimeMillis(), mediaT );
		//}else{
			MapManage.GetInstance().LoadMapImage( image_data, mediaT );
		//}

		// イベントリスト読み込み
		if( RELEASE_MODE ){
			CharaManage.GetInstance().LoadEventList( event_data_file + "?" + System.currentTimeMillis() );
		}else{
			CharaManage.GetInstance().LoadEventList( event_data_file );
		}

		// 通過リスト読み込み
		MapManage.GetInstance().LoadCanWalkList( "canwalk/"+map_chip_id+".txt", MapManage.DOWN_LAYER_MODE );
		MapManage.GetInstance().LoadCanWalkList( "canwalk/"+map_chip_id+"_up.txt", MapManage.UP_LAYER_MODE );

		// キャラ画像読み込み
		for( i = 0; i < CharaManage.GetInstance().history_index; i++ ){
			CharaManage.GetInstance().LoadCharaImage( "chara_img/"+CharaManage.GetInstance().file_history[i], i, mediaT );
		}

		// 武器画像読み込み
		BattleManage.GetInstance().big_weapon_image = BattleManage.GetInstance().LoadImage( "chara_img/weapon.gif", mediaT );

		// ロード待ち
		try{
			mediaT.waitForAll();
		}catch( InterruptedException e ){}

		// 画像バラバラ化
		MapManage.GetInstance().MakeBaraMap();

		// キャラ作成
		CharaManage.GetInstance().MakeChara();

		// 武器画像作成
		BattleManage.GetInstance().MakeCharaImage();

		EditMapID = mapid;

		// ガーベッジコレクション
		Runtime.getRuntime().gc();
	}

	//--------------------------------------------------
	// デバッグプリント
	//--------------------------------------------------
	void DebugPrint( String str ){
		System.out.println( str );
	}

	//--------------------------------------------------
	// スクロールバーが変更された場合
	//--------------------------------------------------
	public void adjustmentValueChanged( AdjustmentEvent ae ){
		MapManage.GetInstance().SetIndex( sb[0].getValue(), sb[1].getValue() );

		// キャンバスをリペイント
		MapCanvas.GetInstance().MyRepaint();
	}

	//--------------------------------------------------
	// ボタンが押された場合
	//--------------------------------------------------
	public void actionPerformed( ActionEvent ae ){
		Object src = ae.getSource();

		if( src == bn[2] ){
			// 保存
			MapManage.GetInstance().SaveData( EditMapID );
		}
		// 読込
		else if( src == bn[3] ){
			// ブラウザならキャッシュが残るので、タイムを付加?
			if( RELEASE_MODE ){
				MapManage.GetInstance().LoadMapData( data_up + "?" + System.currentTimeMillis() );
				MapManage.GetInstance().LoadMapUpData( data_down + "?" + System.currentTimeMillis() );
			}else{
				MapManage.GetInstance().LoadMapData( data_up );
				MapManage.GetInstance().LoadMapUpData( data_down );
			}
		}
		// キャンバスをリペイント
		// MapCanvas.GetInstance().repaint();
		MapCanvas.GetInstance().MyRepaint();
		//select_canvas.repaint();
	}

	//--------------------------------------------------
	// チョイス
	//--------------------------------------------------
	public void itemStateChanged( ItemEvent ie ){
		Choice c = (Choice)ie.getItemSelectable();

		// 対応のモードに変える
		MapManage.GetInstance().SetPixAction( c.getSelectedIndex() );

		// キャンバスをリペイント
		MapCanvas.GetInstance().MyRepaint();
	}

	//--------------------------------------------------
	// 描画
	//--------------------------------------------------
	public void update( Graphics g ){ paint(g); }
	public void paint( Graphics g ){
		Dimension d = getSize();
		g.setColor( Color.white );
		g.fillRect( 0, 0, d.width, d.height );
	}

}
