import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
import java.io.*;
import javax.imageio.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class SimYukkuri extends JFrame implements ActionListener {
	JPanel		rootPane	= new JPanel();
	JPanel		buttonPane	= new JPanel();
	JComboBox	s1, s2;
	JLabel		l1, l2;
	static myPane	mypane  = new myPane();
	static Thread	mythread;	
	
	public SimYukkuri() {	
		super("しむゆっくり");
		// setup button pane
		buttonPane.setLayout(new GridLayout(20, 1));
		buttonPane.setBorder(new LineBorder(Color.gray, 2));
		JLabel title = new JLabel("しむゆっくり Ver1.4　");
		buttonPane.add(title);
		l1 = new JLabel("道具/Tools");
		buttonPane.add(l1);
		String[] list1 = {"針", "ハンマー", "バイブ", "ジュース", "えさ", "ホウキ", "おかざり"};
		s1 = new JComboBox(list1);
		buttonPane.add(s1);
		JLabel l2 = new JLabel("言語/Language");
		buttonPane.add(l2);
		String[] list2 = {"日本語", "英語"};
		s2 = new JComboBox(list2);
		s2.addActionListener(this);
		buttonPane.add(s2);
		// setup my pane
		mypane.addMouseListener(new myListener());
		// setup root pane
		rootPane.setLayout(new BorderLayout());
		rootPane.add("Center", mypane);
		rootPane.add("East", buttonPane);
		// setup my frame
		setSize(1024, 600);
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		setLocation(new Point(100, 100));
		setContentPane(rootPane);
		setResizable(false);
		setVisible(true);
	}
	
	public static void main(String[] args) {
		SimYukkuri myyukkuri = new SimYukkuri();
		mypane.isRunning = true;
		mythread = new Thread(mypane);
		mythread.start();
	}
	
	public void actionPerformed(ActionEvent e) {
		switch (s2.getSelectedIndex()) {
		case 0:
			mypane.yukkuri.setLanguage(Body.JAPANESE);
			s1.removeAllItems();
			s1.addItem("針");
			s1.addItem("ハンマー");
			s1.addItem("バイブ");
			s1.addItem("ジュース");
			s1.addItem("えさ");
			s1.addItem("ホウキ");
			s1.addItem("おかざり");
			s2.removeAllItems();
			s2.addItem("日本語");
			s2.addItem("英語");
			s2.setSelectedIndex(0);
			break;
		case 1:
			mypane.yukkuri.setLanguage(Body.ENGLISH);
			s1.removeAllItems();
			s1.addItem("Needle");
			s1.addItem("Hammer");
			s1.addItem("Vibrator");
			s1.addItem("Juice");
			s1.addItem("Food");
			s1.addItem("Sweep");
			s1.addItem("Accessory");
			s2.removeAllItems();
			s2.addItem("Japanese");
			s2.addItem("English");
			s2.setSelectedIndex(1);
			break;
		}
	}
	
	public class myListener extends MouseAdapter {
		public void mouseClicked(MouseEvent e){
			Point p = e.getPoint();
			Dimension size = mypane.getSize();
			int w = size.width, h = size.height;
			boolean hit = false;
			if (s1.getSelectedIndex() == 5) {//ホウキ
				for (Shit s:Yukkuri.shitList) {
					int ageState = s.getAgeState();
					int dia[] = {10, 20, 30};
					int offsetX = (myPane.maxSize - dia[ageState])/2;
					int offsetY = (myPane.maxSize - dia[ageState]);
					int dx = (int)p.getX() - (Translate.transX(s.getX(), s.getY(), Box.maxX, Box.maxY)*(w-myPane.maxSize)/Box.maxX + offsetX);
					int dy = (int)p.getY() - (Translate.transY(s.getX(), s.getY(), Box.maxX, Box.maxY)*(h-myPane.maxSize)/Box.maxY + offsetY);
					if (dx >= 0 && dx <= dia[ageState] && dy >= 0 && dy <= dia[ageState]) {
						s.remove();
						hit = true;
					}
				}
				for (Food f:Yukkuri.foodList) {
					int offsetX = (myPane.maxSize - myPane.foodSize)/2;
					int offsetY = (myPane.maxSize - myPane.foodSize/2);
					int dx = (int)p.getX() - (Translate.transX(f.getX(), f.getY(), Box.maxX, Box.maxY)*(w-myPane.maxSize)/Box.maxX + offsetX);
					int dy = (int)p.getY() - (Translate.transY(f.getX(), f.getY(), Box.maxX, Box.maxY)*(h-myPane.maxSize)/Box.maxY + offsetY);
					if (dx >= 0 && dx <= myPane.foodSize && dy >= 0 && dy <= myPane.foodSize/2) {
						f.remove();
						hit = true;
					}
				}
			}
			for (Body b:Yukkuri.bodyList) {
				int ageState = b.getAgeState();
				int dia[] = {myPane.maxSize/4, myPane.maxSize/2, myPane.maxSize};
				int offsetX = (myPane.maxSize - dia[ageState])/2;
				int offsetY = (myPane.maxSize - dia[ageState]);
				int dx = (int)p.getX() - (Translate.transX(b.getX(), b.getY(), Box.maxX, Box.maxY)*(w-myPane.maxSize)/Box.maxX + offsetX);
				int dy = (int)p.getY() - (Translate.transY(b.getX(), b.getY(), Box.maxX, Box.maxY)*(h-myPane.maxSize)/Box.maxY + offsetY);
				if (dx >= 0 && dx <= dia[ageState] && dy >= 0 && dy <= dia[ageState]) {
					switch (s1.getSelectedIndex()) {
					case 0:
						//針
						b.strikeByNeedle();
						break;
					case 1:
						//ハンマー
						b.strikeByHammer();
						break;
					case 2:
						//バイブ
						b.forceSukkiri();
						break;
					case 3:
						//ジュース
						b.giveJuice();
						break;
					case 4:
						//えさ
						break;
					case 5:
						//ホウキ
						if (b.isDead()) {
							b.remove();
						}
						break;
					case 6:
						//おかざり
						if (b.isAccessory()) {
							b.takeAccessory();
						}
						else {
							b.giveAccessory();
						}
						break;
					default:
						System.out.println("invalid tool");
					}
					hit = true;
				}
			}
			if (!hit && s1.getSelectedIndex() == 4) { //えさ
				int offsetX = (myPane.maxSize - mypane.foodSize)/2;
				int offsetY = (myPane.maxSize - myPane.foodSize/2);
				int X = ((int)p.getX() - offsetX)*Box.maxX/(w-myPane.maxSize);
				int Y = ((int)p.getY() - offsetY)*Box.maxY/(h-myPane.maxSize);				
				int x = Translate.invX(X, Y, Box.maxX, Box.maxY);
				int y = Translate.invY(X, Y, Box.maxX, Box.maxY);
				if (x >= 0 && x <= Box.maxX && y >= 0 && y <= Box.maxY) {
					//ゆっくりフード
					mypane.yukkuri.addYukkuriFood(x, y);
				}
			}
		}
	}
}

class myPane extends JPanel implements Runnable {
	public boolean isRunning = false;
	public Yukkuri yukkuri = new Yukkuri();
	public static final int maxSize = 128;	// max size of icons
	public static final int foodSize = 64;	// size of food
	private Image[][] bodyImage = new Image[3][15];
	private Image[] foodImage = new Image[2];
	private Image shitImage;
	private Image shadowImage;
	private Image backGroundImage;
	private List <Obj>list4sort = new ArrayList<Obj>();
	private int jump[] = {0, 8, 12, 14, 15, 14, 12, 8, 0};
	
	public void run() {
		//load images
		try {
			ClassLoader loader = this.getClass().getClassLoader();
			bodyImage[1][0] = ImageIO.read(loader.getResourceAsStream("images/marisa1.png"));
			bodyImage[1][1] = ImageIO.read(loader.getResourceAsStream("images/marisa2.png"));
			bodyImage[1][2] = ImageIO.read(loader.getResourceAsStream("images/marisa3.png"));
			bodyImage[1][3] = ImageIO.read(loader.getResourceAsStream("images/marisa4.png"));
			bodyImage[1][4] = ImageIO.read(loader.getResourceAsStream("images/marisa5.png"));
			bodyImage[1][5] = ImageIO.read(loader.getResourceAsStream("images/marisa6.png"));
			bodyImage[1][6] = ImageIO.read(loader.getResourceAsStream("images/marisa7.png"));
			bodyImage[1][7] = ImageIO.read(loader.getResourceAsStream("images/marisa8.png"));
			bodyImage[1][8] = ImageIO.read(loader.getResourceAsStream("images/marisa9.png"));
			bodyImage[1][9] = ImageIO.read(loader.getResourceAsStream("images/marisa10.png"));
			bodyImage[1][10] = ImageIO.read(loader.getResourceAsStream("images/marisa11.png"));
			bodyImage[1][11] = ImageIO.read(loader.getResourceAsStream("images/marisa2-1.png"));
			bodyImage[1][12] = ImageIO.read(loader.getResourceAsStream("images/marisa2-2.png"));
			bodyImage[1][13] = ImageIO.read(loader.getResourceAsStream("images/marisa1-2.png"));
			bodyImage[1][14] = ImageIO.read(loader.getResourceAsStream("images/marisa3-2.png"));
			bodyImage[2][0] = ImageIO.read(loader.getResourceAsStream("images/reimu1.png"));
			bodyImage[2][1] = ImageIO.read(loader.getResourceAsStream("images/reimu2.png"));
			bodyImage[2][2] = ImageIO.read(loader.getResourceAsStream("images/reimu3.png"));
			bodyImage[2][3] = ImageIO.read(loader.getResourceAsStream("images/reimu4.png"));
			bodyImage[2][4] = ImageIO.read(loader.getResourceAsStream("images/reimu5.png"));
			bodyImage[2][5] = ImageIO.read(loader.getResourceAsStream("images/reimu6.png"));
			bodyImage[2][6] = ImageIO.read(loader.getResourceAsStream("images/reimu7.png"));
			bodyImage[2][7] = ImageIO.read(loader.getResourceAsStream("images/reimu8.png"));
			bodyImage[2][8] = ImageIO.read(loader.getResourceAsStream("images/reimu9.png"));
			bodyImage[2][9] = ImageIO.read(loader.getResourceAsStream("images/reimu10.png"));
			bodyImage[2][10] = ImageIO.read(loader.getResourceAsStream("images/reimu11.png"));
			bodyImage[2][11] = ImageIO.read(loader.getResourceAsStream("images/reimu2-1.png"));
			bodyImage[2][12] = ImageIO.read(loader.getResourceAsStream("images/reimu2-2.png"));
			bodyImage[2][13] = ImageIO.read(loader.getResourceAsStream("images/reimu1-2.png"));
			bodyImage[2][14] = ImageIO.read(loader.getResourceAsStream("images/reimu3-2.png"));
			foodImage[0] = ImageIO.read(loader.getResourceAsStream("images/gohan1.png"));
			foodImage[1] = ImageIO.read(loader.getResourceAsStream("images/gohan2.png"));
			shitImage = ImageIO.read(loader.getResourceAsStream("images/unun.png"));
			shadowImage = ImageIO.read(loader.getResourceAsStream("images/shadow.png"));
			backGroundImage = ImageIO.read(loader.getResourceAsStream("images/back.jpg"));
		} catch (IOException e1) {System.out.println("File I/O error");}
		// make initial bodies
		yukkuri.addBody(10, 20, Body.MARISA, Body.ADULT);
		yukkuri.addBody(120, 20, Body.REIMU, Body.ADULT);
		// run animation
		while (isRunning) {
			yukkuri.run();
			repaint();
			try {
				Thread.sleep(100);
			} catch (InterruptedException e2) {e2.printStackTrace();}
		}
	}
	
	public void paint(Graphics g) {
		list4sort.clear();
		list4sort.addAll(Yukkuri.bodyList);
		list4sort.addAll(Yukkuri.foodList);
		list4sort.addAll(Yukkuri.shitList);
		Collections.sort(list4sort, new objComparator());
		Dimension size = getSize();
		int w = size.width, h = size.height;
		g.drawImage(backGroundImage,  0, 0, w, h, this);
		for (Obj o : list4sort) {
			switch (o.objType) {
			case Obj.YUKKURI: {
				Body b = (Body)o;
				int ageState = b.getAgeState();
				int dia[] = {maxSize/4, maxSize/2, maxSize};
				int offsetX = (maxSize - dia[ageState])/2;
				int offsetY = (maxSize - dia[ageState]);
				int drX = Translate.transX(b.getX(), b.getY(), Box.maxX, Box.maxY)*(w-maxSize)/Box.maxX + offsetX;
				int drY = Translate.transY(b.getX(), b.getY(), Box.maxX, Box.maxY)*(h-maxSize)/Box.maxY + offsetY;
				int jumpLevel[] = {4, 2, 1};
				// draw face
				g.drawImage(shadowImage, drX, drY, dia[ageState], dia[ageState], this);
				if (!b.isAccessory()) {
					if (b.isDead()) {
						g.drawImage(bodyImage[b.getBodyType()][10], drX, drY, dia[ageState], dia[ageState], this);
					}
					else if (b.isDamaged()) {
						g.drawImage(bodyImage[b.getBodyType()][9], drX, drY, dia[ageState], dia[ageState], this);
					}
					else {
						drY -= jump[(int)b.getAge() % 9]/2/jumpLevel[ageState];
						g.drawImage(bodyImage[b.getBodyType()][8],drX, drY, dia[ageState], dia[ageState], this);
					}
				}
				else if (b.isStrike()) {
					g.drawImage(bodyImage[b.getBodyType()][7],drX, drY, dia[ageState], dia[ageState], this);
				}
				else if (b.isShitting() || b.isBirth()) {
					g.drawImage(bodyImage[b.getBodyType()][1], drX, drY, dia[ageState], dia[ageState], this);				
				}
				else if (b.isFurifuri()) {
					if (b.getAge() % 8 <= 3) {
						g.drawImage(bodyImage[b.getBodyType()][11], drX, drY, dia[ageState], dia[ageState], this);
					}
					else if (b.getAge() % 8 <= 7) {
						g.drawImage(bodyImage[b.getBodyType()][12], drX, drY, dia[ageState], dia[ageState], this);
					}
				}
				else if (b.isExciting()) {
					drY -= jump[(int)b.getAge() % 9]/jumpLevel[ageState];
					g.drawImage(bodyImage[b.getBodyType()][2], drX, drY, dia[ageState], dia[ageState], this);
				}
				else if (b.isSleeping()) {
					g.drawImage(bodyImage[b.getBodyType()][3], drX, drY, dia[ageState], dia[ageState], this);
				}
				else if (b.isPeroPero() || b.isEating()) {
					g.drawImage(bodyImage[b.getBodyType()][13], drX, drY, dia[ageState], dia[ageState], this);
				}
				else if (b.isSukkiri()) {
					g.drawImage(bodyImage[b.getBodyType()][14], drX, drY, dia[ageState], dia[ageState], this);
				}
				else if (b.isDead()) {
						g.drawImage(bodyImage[b.getBodyType()][4], drX, drY, dia[ageState], dia[ageState], this);
				}
				else if (b.isDamaged()) {
					g.drawImage(bodyImage[b.getBodyType()][5], drX, drY, dia[ageState], dia[ageState], this);
				}
				else if (b.isUngry()) {
					drY -= jump[(int)b.getAge() % 9]/jumpLevel[ageState];
					g.drawImage(bodyImage[b.getBodyType()][6], drX, drY, dia[ageState], dia[ageState], this);
				}
				else {
					drY -= jump[(int)b.getAge() % 9]/2/jumpLevel[ageState];
					g.drawImage(bodyImage[b.getBodyType()][0], drX, drY, dia[ageState], dia[ageState], this);
				}
				// draw script
				if (b.getMessage() != null) {
					g.setColor(Color.white);
					g.fillRoundRect(drX+14, drY-14, b.getMessage().length()*yukkuri.fontWidth()+4, 16, 8, 8);
					g.setColor(Color.black);
					g.drawRoundRect(drX+14, drY-14, b.getMessage().length()*yukkuri.fontWidth()+4, 16, 8, 8);
					g.drawString(b.getMessage(), drX+14+2, drY);
				}
			}
			break;
			case Obj.FOOD: {
				Food f = (Food)o;
				int offsetX = (maxSize - foodSize)/2;
				int offsetY = (maxSize - foodSize/2);
				int drX = Translate.transX(f.getX(), f.getY(), Box.maxX, Box.maxY)*(w-maxSize)/Box.maxX + offsetX;
				int drY = Translate.transY(f.getX(), f.getY(), Box.maxX, Box.maxY)*(h-maxSize)/Box.maxY + offsetY;
				if (f.isEmpty()) {
					g.drawImage(foodImage[0], drX, drY, foodSize, foodSize/2, this);				
				}
				else {
					g.drawImage(foodImage[1], drX, drY, foodSize, foodSize/2, this);
				}
			}
			break;
			case Obj.SHIT: {
				Shit s = (Shit)o;
				int ageState = s.getAgeState();
				int dia[] = {10, 20, 30};
				int offsetX = (maxSize - dia[ageState])/2;
				int offsetY = (maxSize - dia[ageState]);
				int drX = Translate.transX(s.getX(), s.getY(), Box.maxX, Box.maxY)*(w-maxSize)/Box.maxX + offsetX;
				int drY = Translate.transY(s.getX(), s.getY(), Box.maxX, Box.maxY)*(h-maxSize)/Box.maxY + offsetY;
				g.drawImage(shitImage, drX, drY, dia[ageState], dia[ageState], this);
			}
			break;
			}
		}
	}
}

class objComparator implements Comparator {
	public int compare(Object arg0, Object arg1) {
		Obj o1 = (Obj)arg0;
		Obj o2 = (Obj)arg1;
		if (o1.getY() > o2.getY()) {
			return 1;
		} else if (o1.getY() < o2.getY()) {
			return -1;
		} else {
			return 0;
		}
	}
}

class Translate {
	static final private double m = 1.0 / 8.0;
	static final private double n = 7.0 / 8.0;
	
	static public int transX(int x, int y, int X, int Y) {
		return (int)(((n-m)*Y*x - m*X*y + m*X*Y)/((n-m-1)*y + Y));
	}
	
	static public int transY(int x, int y, int X, int Y) {
		return (int)(((n-m)*Y*y)/((n-m-1)*y + Y));
	}
	
	static public int invX(int x, int y, int X, int Y) {
		return (int)((Y*x + m*X*y - m*X*Y)/((n-m)*Y - (n-m-1)*y));
	}
	
	static public int invY(int x, int y, int X, int Y) {
		return (int)(Y*y/((n-m)*Y - (n-m-1)*y));
	}
}