import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

import java.beans.*;
import java.io.*;
import java.net.URL;
import java.util.*;

import javax.swing.text.*;
import javax.swing.undo.*;
import javax.swing.event.*;
import java.applet.*;

class TacticsApplet extends Applet implements MouseListener, MouseMotionListener,
 KeyListener, FocusListener, Runnable  {

	Thread viewerThread = null;	// 画面更新用のスレッド。
	MediaTracker mediaTracker;
	int MTID;

	int gameSpeed = 500;

	Image	 offscreen;	//オフスクリーン
	Graphics offGraphics;	//

	UnitGraphicsEngineAppQuarter	ugeQuarter;
	UnitGraphicsEngineApp		ugeApp;

	//画面に描画される1スクウェアの大きさ。
	int squareSizeX = 32;
	int squareSizeY = 32;

	boolean showHP = false;	//Creatureユニットのhp(体力)を表示するか否か。

	int ctrNationality = 1;		// どの勢力を操作するか。
	Creature ctrCreature = null;	// 現在コントローラーが選択しているユニット。
	boolean ctrWalking = true;	//true == go, false == stop;
	Direction ctrDirection = new Direction( Direction.UP );
	int ctrX = 0, ctrY = 0;
	static Image ctrImg[] = new Image[4];		// 兵士コントロール用カーソル画像。
	static Image ctrStopImg[] = new Image[4];	// 兵士コントロール用カーソル画像。兵士を止めるとき。

	static Image imgSuqare;
	static Image imgBlueCavalry[] = new Image[4];
	static Image imgRedCavalry[] = new Image[4];

	Board marchField;			// 行軍画面。この上を敵味方の軍隊ユニットが行軍し、敵国の首都を目指す。
	Board battleField;			// 戦闘画面。
	int boardSizeX = 16, boardSizeY = 16;	// 行軍・戦闘画面の縦横の大きさ。

	public void init() {

		mediaTracker = new MediaTracker(this);
		MTID = 0;

		// カーソル画像の読み込み。
		ctrImg[0] = getImage(getCodeBase(), "up.gif");
		mediaTracker.addImage(ctrImg[0], MTID);
		ctrImg[1] = getImage(getCodeBase(), "right.gif");
		mediaTracker.addImage(ctrImg[1], MTID);
		ctrImg[2] = getImage(getCodeBase(), "down.gif");
		mediaTracker.addImage(ctrImg[2], MTID);
		ctrImg[3] = getImage(getCodeBase(), "left.gif");
		mediaTracker.addImage(ctrImg[3], MTID);

		// カーソルストップ画像の読み込み。
		ctrStopImg[0] = getImage(getCodeBase(), "stop_up.gif");
		mediaTracker.addImage(ctrStopImg[0], MTID);
		ctrStopImg[1] = getImage(getCodeBase(), "stop_right.gif");
		mediaTracker.addImage(ctrStopImg[1], MTID);
		ctrStopImg[2] = getImage(getCodeBase(), "stop_down.gif");
		mediaTracker.addImage(ctrStopImg[2], MTID);
		ctrStopImg[3] = getImage(getCodeBase(), "stop_left.gif");
		mediaTracker.addImage(ctrStopImg[3], MTID);

		imgBlueCavalry[0] = getImage(getCodeBase(), "blueCavalry0.gif");
		mediaTracker.addImage( imgBlueCavalry[0], MTID );
		imgBlueCavalry[0] = getImage(getCodeBase(), "blueCavalry0.gif");
		mediaTracker.addImage( imgBlueCavalry[0], MTID );
		imgBlueCavalry[0] = getImage(getCodeBase(), "blueCavalry0.gif");
		mediaTracker.addImage( imgBlueCavalry[0], MTID );
		imgBlueCavalry[0] = getImage(getCodeBase(), "blueCavalry0.gif");
		mediaTracker.addImage( imgBlueCavalry[0], MTID );

		imgSuqare = getImage( getCodeBase(), "suqare.gif" );
		mediaTracker.addImage( imgSuqare, MTID );

		ugeQuarter = new UnitGraphicsEngineAppQuarter( this, mediaTracker );
		ugeApp = new UnitGraphicsEngineApp(this, mediaTracker);
		Unit.setUGE( ugeApp );

		try
		{
			//イメージの強制ロードを要求
			mediaTracker.waitForID(MTID);
		}
		catch (InterruptedException e)
		{
			return;
		}

		addMouseListener(this);
		addMouseMotionListener(this);
		addKeyListener(this);
		addFocusListener( this );

		// オフスクリーンの作成。
		offscreen = createImage(2176, 1600);
		offGraphics  = offscreen.getGraphics();

		// ゲームボードの作成。
		marchField = new Board(boardSizeX, boardSizeY);



	        requestFocus();  // キーボードフォーカスを要求

		// 地形データと構造物データの読みこみ。
		initMarchField();

		Commander blueCommander0 = new Commander(0, 0, null, null, 1, null, false);
		Commander blueCommander1 = new Commander(0, 0, null, null, 1, null, false);
		Commander blueCommander2 = new Commander(0, 0, null, null, 1, null, false);

		Army blueArmy0 = new Army(0, 15, marchField, new Direction( Direction.UP ), 1, null, false, blueCommander0, this);
		Army blueArmy1 = new Army(1, 15, marchField, new Direction( Direction.RIGHT ), 1, null, false, blueCommander1, this);
		Army blueArmy2 = new Army(0, 14, marchField, new Direction( Direction.UP ), 1, null, false, blueCommander2, this);

		blueCommander0.setArmy(blueArmy0);
		blueCommander1.setArmy(blueArmy1);
		blueCommander2.setArmy(blueArmy2);

		marchField.setCreature(0, 15, blueArmy0);
		marchField.setCreature(1, 15, blueArmy1);
		marchField.setCreature(0, 14, blueArmy2);

		marchField.getRunnableUnitList().add( blueArmy0 );
		marchField.getRunnableUnitList().add( blueArmy1 );
		marchField.getRunnableUnitList().add( blueArmy2 );


		Commander redCommander0 = new Commander(0, 0, null, null, 0, null, true);
		Commander redCommander1 = new Commander(0, 0, null, null, 0, null, true);
		Commander redCommander2 = new Commander(0, 0, null, null, 0, null, true);

		Army redArmy0 = new Army(15, 0, marchField, new Direction( Direction.DOWN ), 0, marchField.getUnit(0,15), true, redCommander0, this);
		Army redArmy1 = new Army(14, 0, marchField, new Direction( Direction.LEFT ), 0, blueArmy0, true, redCommander1, this);
		Army redArmy2 = new Army(15, 1, marchField, new Direction( Direction.DOWN ), 0, marchField.getUnit(0,15), true, redCommander2, this);

		redCommander0.setArmy(redArmy0);
		redCommander1.setArmy(redArmy1);
		redCommander2.setArmy(redArmy2);

		marchField.setCreature(15, 0, redArmy0);
		marchField.setCreature(14, 0, redArmy1);
		marchField.setCreature(15, 1, redArmy2);

		marchField.getRunnableUnitList().add( redArmy0 );
		marchField.getRunnableUnitList().add( redArmy1 );
		marchField.getRunnableUnitList().add( redArmy2 );

	}

	public void start() {
		if (viewerThread == null) {
			viewerThread = new Thread(this);
			viewerThread.start();
		}
	}
	public void run() {
		while (0 < gameSpeed) {

			repaint();	//

			// ゲーム速度に応じてウエイトをおく。
			try
			{
				viewerThread.sleep(gameSpeed/16);
									}
			catch (InterruptedException e)
			{
			}

		}
	}

	public void setBoard( Board board ) { marchField = board; }
	public Board getBoard() { return marchField; }

	// HTMLのparamタグから、地形データ、構造物データを読みこみ、MarchFieldを初期化するメソッド。
	public void initMarchField() {

		String rs;
		int geoKind;	//地形データ。

		// 地形データの読み込みと、chineseContinentへの配置。
		for (int y = 0; y < boardSizeY; y++) {

			rs = getParameter("g" + y);

			for (int x = 0; x < boardSizeX; x++) {
				int commaInt = rs.indexOf(",");

				if (commaInt != -1) {
					geoKind = Integer.parseInt(rs.substring(0, commaInt));
					rs = rs.substring(commaInt+1);
				}
				else {
					geoKind = Integer.parseInt(rs);
				}	

				// 得られたgeoKindの値をもとにGroundオブジェクトを生成し、chineseContinentにセット。
				marchField.setUnit(x, y, new Ground(x, y, marchField, geoKind) );
			}
		}

		// 構造物データの読み込みと、chineseContinentへの配置。
		for (int y = 0; y < boardSizeY; y++) {

			rs = getParameter("s" + y);

			for (int x = 0; x < boardSizeX; x++) {
				int commaInt = rs.indexOf(",");

				if (commaInt != -1) {
					geoKind = Integer.parseInt(rs.substring(0, commaInt));
					rs = rs.substring(commaInt+1);
				}
				else {
					geoKind = Integer.parseInt(rs);
				}	

				// 得られたgeoKindの値をもとにGroundオブジェクトを生成し、chineseContinentにセット。
				Structure structure;

				switch (geoKind) {
					case 1:
						structure = new NapCapital(x, y, marchField, 1);
						break;
					case 2:
						structure = new NapCapital(x, y, marchField, 2);
						break;
					case 3:
						structure = new NapCity(x, y, marchField);
						marchField.getRunnableUnitList().add( (NapCity)structure );
						break;

					case 7:
					case 8:
					case 9:
					case 10:
					case 11:
					case 12:
					case 13:
					case 14:
					case 15:
					case 16:
					case 17:
						structure = new Road(x, y, 1, geoKind-7);
						break;

					default:
						structure = null;
						break;
				}

				marchField.setStructure(x, y, structure);
			}
		}
	}

		
	public void paint(Graphics g) {

		int boardSizeX = marchField.getSizeX();
		int boardSizeY = marchField.getSizeY();

		for (int y = 0; y < boardSizeY; y++)
		 for (int x = 0; x < boardSizeX; x++) {

			Unit unit = marchField.getUnit(x,y);
			if (unit != null) {
				g.setColor( Color.white );
				g.fillRect( squareSizeX * x , squareSizeY * y, squareSizeX, squareSizeY);
				unit.show(g, squareSizeX, squareSizeY, (Component)this);

				//ユニットの体力ゲージを表示するか否か。
				if (showHP) {
					Creature creature = marchField.getCreature(x,y);
					if ( creature != null) {
						int gageHP = calcGage(creature.getHp(), creature.getMaxHp());

						g.setColor( Color.blue );
						g.fillRect( squareSizeX * x, squareSizeY * y +24, gageHP,4 );
					}
				}
			}
			else {
				g.setColor( Color.white );
				g.fillRect( squareSizeX * x, squareSizeY * y, squareSizeX, squareSizeY);
			}
		}

		// 矢などの飛行物の描画。
		marchField.getFlyingUnitList().show(g, squareSizeX,squareSizeY, (Component)this);


		// コントロール用の矢印の描画。
		if ( ctrX < boardSizeX && ctrY < boardSizeY ) {
			if (ctrWalking) {
				g.drawImage( ctrImg[ctrDirection.getDirection()], ctrX * squareSizeX, ctrY * squareSizeY, this);
			}
			else {
				g.drawImage( ctrStopImg[ctrDirection.getDirection()], ctrX * squareSizeX, ctrY * squareSizeY, this);
			}
		}


		// クォータービューの描画。
		g.setColor( Color.white );
		g.fillRect( 0 , 512, 2176, 1088);
//		g.fillRect( 0 , 512, 2176, 548);
		Unit.setUGE( ugeQuarter );

		int leftUpX = 0;
		int leftUpY = 0;
		int rightDownX = boardSizeX -1;
		int rightDownY = boardSizeY -1;

		int x = leftUpX;
		int y = leftUpY;
		int tempX = x;
		int tempY = y;

		do {
			x = tempX;
			y = tempY;

			do {
				int quarterX = 1088 - 68;
				int quarterY = 512;

				int viewerX = (x * 68 - y * 68) + quarterX;
				int viewerY = ( x + y ) * 34 + quarterY;

				g.drawImage( imgSuqare, viewerX,  viewerY, this);

				Creature creature = marchField.getCreature(x,y);
				if ( creature != null) {

					creature.show(g, quarterX, quarterY, (Component)this );
				}

				x++;
				y--;
			} while ( y >= leftUpY && x <= rightDownX);

			if ( ++tempY > rightDownY ) {
				tempY--;
				tempX++;
			}

		} while ( tempX <= rightDownX && tempY <= rightDownY );

		Unit.setUGE( ugeApp );

	}

	public void update(Graphics g) {
		if (offscreen != null) {

			paint(offGraphics);
			g.drawImage(offscreen, 0,0, this);
		}
		else {
			paint(g);
		}
	}


	public void destroy() {

		for (int x = 0; x < boardSizeX; x++)
		 for (int y = 0; y < boardSizeY; y++)
			marchField.removeUnit(x, y);

		marchField.setSpeed(0);

		removeMouseListener(this);
		removeMouseMotionListener(this);
		removeKeyListener(this);
		removeFocusListener( this );

	}

	public int calcGage(int src, int max) {
		int retGage = src / (max / squareSizeX);

		if ( 0 >= retGage && 0 < src)
			retGage = 1;
		if ( squareSizeX < retGage)
			retGage = squareSizeX;			
		return retGage;
	}

	public void mouseDragged(MouseEvent e) {
	}
	public void mouseMoved(MouseEvent e) {
		ctrX = e.getX()/squareSizeX;
		ctrY = e.getY()/squareSizeY;
		repaint();
	}

	public void mouseReleased(MouseEvent e) {
		if (ctrCreature != null) {
			// マウスポインタの変更。
			ctrX = e.getX()/squareSizeX;
			ctrY = e.getY()/squareSizeY;

			Unit target = marchField.getCreature(ctrX, ctrY);

			if (target == null) {
				target = marchField.getUnit(ctrX, ctrY);
				ctrCreature.setTarget(target);
				ctrCreature.setAuto(true);
			}
			else {
				if (target == ctrCreature) {
					ctrCreature.setDirection( ctrDirection );
					ctrCreature.setWalking(ctrWalking);
					ctrCreature.setAuto(false);
				}
				else {
					ctrCreature.setTarget(target);
					ctrCreature.setAuto(true);
				}
			}

		}
		ctrCreature = null;
	}
	public void mousePressed(MouseEvent e) {

		if (ctrCreature == null) {
			// マウスポインタの変更。
			ctrX = e.getX()/squareSizeX;
			ctrY = e.getY()/squareSizeY;

			Creature creature = marchField.getCreature(ctrX, ctrY);

			if ( creature != null )
				if (ctrNationality == creature.getNationality())
					ctrCreature = creature;
		}
	}
	public void mouseClicked(MouseEvent e) {
		// マウスポインタの変更。
		ctrX = e.getX()/squareSizeX;
		ctrY = e.getY()/squareSizeY;

		Creature creature = marchField.getCreature(ctrX, ctrY);

		if ( creature != null )
			if (ctrNationality == creature.getNationality()) {
			 // 兵士の向きを変更。
				creature.setDirection( ctrDirection );
				creature.setWalking(ctrWalking);
				creature.setAuto(false);
			}

		repaint();
	}

	public void mouseEntered(MouseEvent e) {
	}
	public void mouseExited(MouseEvent e) {
	}

	public void keyTyped(KeyEvent e) {
	}
	public void keyPressed(KeyEvent e) {
		if (e.getKeyCode() == e.VK_SPACE) {
			showHP = !showHP;
			repaint();
		}

		if (e.getKeyCode() == e.VK_UP) {
			ctrDirection.setDirection(Direction.UP);
			repaint();
		}
		if (e.getKeyCode() == e.VK_RIGHT) {
			ctrDirection.setDirection(Direction.RIGHT);
			repaint();
		}
		if (e.getKeyCode() == e.VK_DOWN) {
			ctrDirection.setDirection(Direction.DOWN);
			repaint();
		}
		if (e.getKeyCode() == e.VK_LEFT) {
			ctrDirection.setDirection(Direction.LEFT);
			repaint();
		}

		if (e.getKeyCode() == e.VK_SHIFT) {
			ctrWalking = !ctrWalking;
			repaint();
		}

		if (e.getKeyCode() == e.VK_ENTER) {
			if (0 == marchField.getSpeed())
				marchField.setSpeed(gameSpeed);	// ゲーム速度を設定しゲームをスタート。
			else
				marchField.setSpeed(0);	// ゲーム速度を0にしゲームを中断。
		}
	}
	public void keyReleased(KeyEvent e) {
	}

	public void focusGained( FocusEvent evt ) {
	}
	public void focusLost( FocusEvent evt ) {
	}

}


