import java.awt.AWTEvent;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.event.KeyEvent;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.awt.Polygon;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import java.awt.geom.AffineTransform;

public class H extends JFrame
{
    static String input;

    public static void main(String[] args) throws Exception
    {
        H frame = new H();
		frame.setTitle("Hiragana Piranha");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(800, 600);
        frame.setResizable(false);
		frame.setLocation(112, 84);
        frame.setVisible(true);

        frame.createBufferStrategy(2);
        BufferStrategy bufferStrategy = frame.getBufferStrategy();
		
		//load graphics
		BufferedImage piranha = ImageIO.read(frame.getClass().getResource("p.png"));
		BufferedImage diver = ImageIO.read(frame.getClass().getResource("d.png"));
		
		// fonts
		Font enFont = new Font("SansSerif", Font.PLAIN, 30);
		Font jpFont = new Font("MS Gothic", Font.PLAIN, 20);
		
		//create polygons for the water highlights
		Color[] colors = {new Color(0x00aaaaf0), new Color(0x00c6c6fd), new Color(0x00b4b4fb)};
		Polygon[] highlights = new Polygon[3];
		for (int i = 0; i < 3; i++)
		{
			highlights[i] = new Polygon();
			highlights[i].addPoint(400, 0);
			highlights[i].addPoint(500, 0);
			highlights[i].addPoint(300, 600);
			highlights[i].addPoint(200, 600);
		}
		highlights[1].translate(300, 0);
		highlights[2].translate(700, 0);
		
		// String kana = "\u3042\u3044\u3046\u3048\u304a\u304b\u304d\u304f\u3051\u3053\u3055\u3057\u3059\u305b\u305d\u305f\u3061\u3064\u3066\u3068\u306a\u306b\u306c\u306d\u306e\u306f\u3072\u3075\u3078\u307b\u307e\u307f\u3080\u3081\u3082\u3084\u3086\u3088\u3089\u308a\u308b\u308c\u308d\u308f\u3092\u3093";
		char kanaCode = 0x3040;
		String kanaDeltas = "2222212222222222232221111133333111122211111231";
		String kana = "";

		String romajiString = "A I U E O KA KI KU KE KO SA SHI/SI/ SU SE SO TA CHI/TI/ TSU/TU/ TE TO NA NI NU NE NO HA HI FU/HU/ HE HO MA MI MU ME MO YA YU YO RA RI RU RE RO WA O N/ ";
		String[] romaji = new String[46];
		int a = 0;
		
		// init the piranha data
		int[] alive = new int[46];
		int[] x = new int[46];
		int[] y = new int[46];
		int[] wordIndex = new int[46];
		
		for (int i = 0; i < 46; i++)
		{
			// create string of hiragana
			kanaCode += kanaDeltas.charAt(i) - (char)48;
			kana += String.valueOf(kanaCode);

			// split the romanized readings into an array
			int b = romajiString.indexOf(" ", a);
			romaji[i] = romajiString.substring(a, b);
			a = b + 1;
			
			// init wordIndex, which associates a piranha with a kana. this will be randomized for each round
			wordIndex[i] = i;
		}

		// init other data
		int round = 0;
		int state = 0;
		
		int frameCount = 0;
		int startFrame = 0;
		int nextBubble = 20;
		
		int[] bubbleDepth = new int[46];
		int bubble = 0;
		
		int score = 0;
		input = "";
		int dead = 0;

        while(true)
        {
            Graphics2D g = (Graphics2D) bufferStrategy.getDrawGraphics();
			
			g.setFont(enFont);

			// draw background
            g.setColor(new Color(0x00bebefc));
            g.fillRect(0, 0, 800, 600);
			
			// draw "watery highlights"
			for (int i = 0; i < 3; i++)
			{
				g.setColor(colors[i]);
				g.fill(highlights[i]);
				
				// move left; shift back to right when out of view
				// int dx = highlights[i].contains(-100, 1) ? 1200 : -1;
				highlights[i].translate(highlights[i].contains(-100, 1) ? 1200 : -1, 0);
			}
						
			// draw diver
			int diverDepth = 280 - (int)(10 * Math.cos((double)frameCount / 10));
			g.drawImage(diver, 5, diverDepth, null);

			// draw bubbles
			g.setColor(Color.BLACK);
			for (int i = 0; i < 46; i++)
			{
				if (bubbleDepth[i] > 0)
				{
					bubbleDepth[i] -= 3;
					int wobble = (bubbleDepth[i] % 4) / 2;
					g.drawOval(65 + wobble, bubbleDepth[i], 5, 5);
				}
			}
			
			// create new bubble at random intervals
			if (frameCount == nextBubble)
			{
				bubbleDepth[(bubble++) % 46] = diverDepth;
				nextBubble = frameCount + 5 + (int)(Math.random() * 75);
			}

			// draw score
			g.drawString("Score: " + score, 330, 75);
			
			int inputLength = input.length();
			
			// set number of piranhas
			int n = 3 + (round % 10) / 2 + round / 10;
			if (n > 46)
			{
				n = 46;
			}

			if (state == 0) // intro
			{
				// draw intro text
				g.drawString("Hiragana Piranha", 280, 300);
				g.drawString("Press Enter to start", 270, 335);
				
				//start game when user presses enter
				if (input.contains("*"))
				{
					score = 0;
					dead = 0;
					round = 1;
					state = 1;
					input = "";
				}
			}
			else if (state == 1) // init
			{
				// set initial positions and words
				for (int i = 0; i < n; i++)
				{
					alive[i] = 1;
					x[i] = 800 + (int)(300 * Math.random());
					y[i] = 50 + (int)((500 / n) * i + 50 * Math.random());

					// randomize kana
					int j = (int) (Math.random() * 46);
					int temp = wordIndex[i];
					wordIndex[i] = wordIndex[j];
					wordIndex[j] = temp;
				}
				state = 2;
				startFrame = frameCount;
			}
			else if (state == 2) // playing
			{
				g.setColor(Color.BLACK);
				
				// draw round number at start of round
				if (frameCount - startFrame < 50)
				{
					g.drawString("Round " + round, 330, 315);
				}
				
				// draw user input
				g.drawString("> " + input, 370, 555);
				
				int aliveCount = 0;
				// move & draw piranhas
				for (int i = 0; i < n; i++)
				{
					if (alive[i] > 0) // if alive
					{
						aliveCount++;
						
						// test whether killed by user. must be alive and on screen
						if (alive[i] == 1 && dead == 0 && x[i] < 800 && (input.equals(romaji[wordIndex[i]]) || (input.length() > 0 && romaji[wordIndex[i]].contains(input + "/"))))
						{
							score += 100 + x[i] / 8;
							alive[i] = 2;
							input = "";
						}
						
						if (alive[i] == 1) // if alive
						{
							// move piranha left
							int speed = 2 + (round / 10);
							
							if (x[i] > 50)
							{
								x[i] -= speed;
							}
							
							// adjust height to close in on diver
							double z = x[i] < 600 ? z = Math.sqrt((double)(x[i] - 50) / 550) : 1;
							int yy = (int)(y[i] * z + 290 * (1 - z));
							
							// draw piranha
							g.drawImage(piranha, x[i], yy, null);
							
							// draw kana
							g.setColor(Color.WHITE);
							g.setFont(jpFont);
							g.drawString(kana.substring(wordIndex[i], wordIndex[i] + 1), x[i] + 25, yy + 25);
							
							// draw hint
							if (x[i] < 760 - 60 * round)
							{
								String hint = romaji[wordIndex[i]];
								if (hint.contains("/"))
								{
									hint = hint.substring(0, hint.length() - 1);
								}
								g.setColor(Color.BLACK);
								g.drawString(hint, x[i] + 25, yy + 65);
							}
							
							// check whether it has reached diver
							if (x[i] < 80 && dead == 0)
							{
								dead ++;
							}
						}
						else // alive[i] == 2, dead but still visible floating
						{
							// move it up
							y[i] -= 3;
							g.drawImage(piranha, new AffineTransform(1, 0, 0, -1, x[i], y[i]), null);
							if (y[i] < 0)
							{
								alive[i] = 0;
							}
						}						
					}
				}
								
				if (dead > 0) // if dead
				{
					g.setColor(Color.RED);
					g.fillOval(70 - dead / 2, 310 - dead / 2, dead, dead);

					g.setFont(enFont);
					g.setColor(Color.BLACK);
					g.drawString("Ouch!", 350, 315);
					dead += 6;
					if (dead > 1800)
					{
						state = 0;
						dead = 0;
					}
				}
				
				// check length because user might have typed during this frame
				// clear user input on pressing Enter (a "*")
				// clear user input if he gets it wrong - assume that a guess ends with a vowel
				if (input.length() == inputLength && inputLength > 0 && "AEIOU*".contains(input.substring(input.length() - 1)))
				{
					input = "";
				}
				
				// check for end of round
				if (aliveCount == 0)
				{
					round++;
					state = 1;
				}
			}
			
            g.dispose();
            bufferStrategy.show();

			frameCount++;
			
            try
            {
                Thread.sleep(30);
            }
            catch (Exception e)
            {
            }
        }
    }

    public void processKeyEvent(KeyEvent e)
    {
		if (e.getID() == java.awt.Event.KEY_PRESS)
		{
			int k = e.getKeyCode();
			if (k == KeyEvent.VK_ENTER)
			{
				input += "*";
			}
			if (k == KeyEvent.VK_BACK_SPACE && input.length() > 0)
			{
				input = input.substring(0, input.length() - 1);
			}
			String s = e.getKeyText(k);
			if (s.length() == 1)
			{
				input += s;
			}
		}
    }
}
