import java.util.*;

public class Yukkuri {	
	public static ArrayList<Body> bodyList = new ArrayList<Body>();
	public static ArrayList<Food> foodList = new ArrayList<Food>();
	public static ArrayList<Shit> shitList = new ArrayList<Shit>();
	
	private Random rnd = new Random();
	private int language = Body.JAPANESE;
	
	private int distance(int x, int y) {
		return x*x + y*y;
	}
	
	private boolean checkPartner(Body b) {
		if (b.isDead() || b.isSleeping()) {
			return false;
		}
		boolean ret = false;
		Body found = null;
		int minDistance = Box.maxX * Box.maxY;
		// find nearest neighborhood
		for (Body partner:bodyList) {
			if (partner == b) {
				continue;
			}
			if (partner.isDead() || (b.isExciting() && !partner.isAdult())) {
				continue;
			}
			int dist, dx, dy;
			dx = b.getX() - partner.getX();
			dy = b.getY() - partner.getY();
			dist = distance(dx, dy);
			if (minDistance > dist) {
				found = partner;
				minDistance = dist;
			}
		}
		if (found != null) {
			if (minDistance <= distance(b.getStep(), b.getStep())) {
				if (b.isExciting()) {
					b.doSukkiri(found);
				}
				else if (!found.isAccessory()) {
					b.showHateYukkuri();
					found.strikeByNeedle();
				}
				else if (rnd.nextInt(20) == 0) {
					b.doSurisuri(found);
				}
			}
			else {
				if (b.isExciting()) {
					b.moveToSukkiri(found.getX(), found.getY());
					ret = true;
				}
				else if (!found.isAccessory() && rnd.nextInt(10) == 0) {
					b.showHateYukkuri();
					b.moveTo(found.getX(), found.getY());
				}
				else if (!b.isAdult() && found.isAdult()) {
					b.moveTo(found.getX(), found.getY());
				}
			}
		}
		return ret;
	}

	private boolean checkFood(Body b) {
		boolean ret = false;
		if (b.isSleeping() || b.isDead() || !b.isHungry()) {
			return false;
		}
		Food found = null;
		int minDistance = Box.maxX * Box.maxY;
		for (Food f:foodList) {
			if (f.isEmpty()) {
				continue;
			}
			int distance, dx, dy;
			dx = b.getX() - f.getX();
			dy = b.getY() - f.getY();
			distance = distance(dx, dy);
			if (minDistance > distance) {
				found = f;
				minDistance = distance;
			}
		}
		if (found != null) {
			if (minDistance <= distance(b.getStep(), b.getStep())) {
				b.eatFood(b.getEatAmount());
				found.eatFood(b.getEatAmount());
			} else {
				// go to nearest food
				b.moveToFood(found.getX(), found.getY());
				ret = true;
			}
		}
		else {
			b.showNoFood();
		}
		return ret;
	}
	
	private boolean checkShit(Body b) {
		boolean ret = false;
		Shit found = null;
		int minDistance = Box.maxX * Box.maxY;
		for (Shit s:shitList) {
			int distance, dx, dy;
			dx = b.getX() - s.getX();
			dy = b.getY() - s.getY();
			distance = distance(dx, dy);
			if (minDistance > distance) {
				found = s;
				minDistance = distance;
			}
		}
		if (found != null) {
			if (minDistance <= distance(b.getStep(), b.getStep())) {
				if (!b.isSleeping() && !b.isExciting()) {
					b.showHateShit();
				}
			}
		}
		return ret;
	}
	
	public void addBody(int x, int y, int type, int age, int language) {
		switch (type) {
		case Body.MARISA:
			bodyList.add(new Marisa(x, y, age, language));
			break;
		case Body.REIMU:
			bodyList.add(new Reimu(x, y, age, language));
			break;
		}
	}
	
	public void addFood(int x, int y, int type) {
		foodList.add(new Food(x, y, type));
	}
	
	public void addYukkuriFood(int x, int y) {
		addFood(x, y, Food.YUKKURIFOOD);
	}
	
	public void addCake(int x, int y) {
		addFood(x, y, Food.CAKE);
	}
	
	public void addShit(int x, int y, int ageState) {
		shitList.add(new Shit(x, y, ageState));
	}
	
	public void setLanguage(int lang) {
		switch (lang) {
		case 0:
			language = Body.JAPANESE;
			break;
		case 1:
			language = Body.ENGLISH;
			break;
		}
	}
	
	public int fontWidth() {
		int width = 13;
		switch (language) {
		case Body.JAPANESE:
			width = 13;
			break;
		case Body.ENGLISH:
			width = 7;
			break;
		}
		return width;
	}
	
	public void run() {
		int ret = 0;
		// Update food state.
		for (int i=0; i < foodList.size(); i++) {
			Food f = (Food)foodList.get(i);
			ret = f.clockTick();
			if (ret == Food.REMOVED) {
				foodList.remove(i);
			}
		}
		// Update shit state.
		for (int i=0; i < shitList.size(); i++) {
			Shit s = (Shit)shitList.get(i);
			ret = s.clockTick();
			if (ret == Shit.REMOVED) {
				shitList.remove(i);
			}
		}
		// update body state
		for (int i=0; i < bodyList.size(); i++) {
			Body b = (Body)bodyList.get(i);
			b.setLanguage(language);
			ret = b.clockTick();
			switch (ret) {
			case Body.DEAD:
				continue;
			case Body.BIRTHBABY: 
				addBody(b.getX(), b.getY(), b.getBabyType(), 0, language);
				break;
			case Body.DOSHIT:
				addShit(b.getX(), b.getY(), b.getAgeState());
				break;
			case Body.REMOVED:
				bodyList.remove(i);
				continue;
			default:
				break;
			}

			// check Sukkiri
			if (!checkPartner(b)) {
				// check Food
				checkFood(b);
				checkShit(b);
			}
		}
	}
}