package template.shooting;

import java.util.LinkedList;

import javax.vecmath.Point3d;
import javax.vecmath.Vector3d;

import framework.AI.AStar;
import framework.AI.GeometryGraph;
import framework.AI.Location;
import framework.AI.Plan;
import framework.animation.Animation3D;
import framework.gameMain.OvergroundActor;
import framework.model3D.Object3D;
import framework.model3D.Position3D;
import framework.physics.Ground;
import framework.physics.Velocity3D;

/**
 * 敵
 * @author 新田直也
 *
 */
public class Enemy extends OvergroundActor {
	private AStar aStar = new AStar();
	private Plan plan = null;
	
	// 定数
	public static final double ENEMY_SPEED = 3.0;
	public static final double BULLET_SPEED = 10.0;
	
	public Enemy(Object3D body, Animation3D animation) {
		super(body, animation);
	}
	
	/**
	 * 単位時間ごとの動作（衝突判定処理も行う）
	 * @param interval --- 前回呼び出されたときからの経過時間（ミリ秒単位）
	 * @param ground --- 地面（構造物）
	 * @param player --- プレイヤーの位置を考慮して移動計画を立てるので必要
	 * @param geometryGraph --- グラフによって単純化した地面
	 */
	public void motion(long interval, Ground ground, Player player, GeometryGraph geometryGraph) {
		if (!doPlan(plan) || Math.random() < 0.005) {
			// 計画が完了するか、気まぐれで新しい計画を立てる
			plan = planning(player, geometryGraph);
			startPlan(plan);
		}
		super.motion(interval, ground);
	}
	
	private Plan planning(Player player, GeometryGraph geometryGraph) {
		Location startLoc;
		Location goalLoc;
		startLoc = geometryGraph.getNearestLocation(getPosition());
		goalLoc = geometryGraph.getNearestLocation(player.getPosition());
		Plan aStarPlan = aStar.getPath(startLoc, goalLoc);
		if (aStarPlan != null) {
			return aStarPlan;	// Aスターアルゴリズムを使った計画
		}
		startLoc = new Location(new Point3d(getPosition().getVector3d()));
		goalLoc = new Location(new Point3d(player.getPosition().getVector3d()));
		return new Plan(startLoc, goalLoc);			// スタートとゴールを直線で結ぶ計画
	}
	
	private void startPlan(Plan plan) {
		if (plan == null) return;		// そもそもまだ一回も計画を立てていない
		Location nextLoc = plan.getNextLocation();
		if (nextLoc == null) return;	// 計画のゴールに辿り着いた
		// 計画上の次の通過点目指して移動速度と体の向きを変更
		Vector3d direction = new Vector3d(nextLoc.getCenter());
		if (direction.length() > 0.0) {
			direction.sub(getPosition().getVector3d());
			direction.normalize();
			direction.scale(ENEMY_SPEED);
			setVelocity(new Velocity3D(direction));		// 移動速度の設定
			direction.setY(0.0);
			direction.normalize();
			setDirection(direction);	// 体の向きの設定
		}
	}
	
	private boolean doPlan(Plan plan) {
		if (plan == null) return false;		// そもそもまだ一回も計画を立てていない
		if (plan.updateCurrentLocation(getPosition())) {
			Location loc = plan.getCurrentLocation();
			if (loc == null) return false;	// 計画のゴールに辿り着いた
			// 計画上の次の通過点目指して移動速度と体の向きを変更
			Vector3d direction = new Vector3d(loc.getCenter());
			if (direction.length() > 0.0) {
				direction.sub(getPosition().getVector3d());
				direction.normalize();
				direction.scale(ENEMY_SPEED);
				setVelocity(new Velocity3D(direction));		// 移動速度の設定
				direction.setY(0.0);
				direction.normalize();
				setDirection(direction);	// 体の向きの設定
			}
		}
		return true;
	}

	public EnemiesBullet shoot(Player player, EnemiesBulletModel enemiesBulletModel) {
		EnemiesBullet enemiesBullet = enemiesBulletModel.createEnemiesBullet();
		// プレイヤーをめがけて打つ
		Vector3d bulletVelocity = player.getPosition().sub(this.getPosition()).getVector3d();
		bulletVelocity.normalize();
		bulletVelocity.scale(BULLET_SPEED);
		enemiesBullet.setVelocity(new Velocity3D(bulletVelocity));
		enemiesBullet.setPosition(this.getPosition().add(-0.5, 0.0, 0.0));
		return enemiesBullet;
	}
}
