/*
 * Lostmazed
 *
 * Copyright 2011 Matúš Sulír.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package lostmazed.game;

import java.awt.event.KeyEvent;
import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;
import lostmazed.Game;
import soga2d.GraphicBoard;
import soga2d.GraphicObject;
import soga2d.Picture;
import soga2d.events.KeyListener;

/**
 * The player who wants to get out of the maze.
 * @author Matúš Sulír
 */
public class Player {
    private GraphicBoard board;
    private Picture image;
    private Maze maze;
    
    private int xSpeed;
    private int ySpeed;
    
    /**
     * Loads the graphics, initializes the player and adds him to the board.
     * @param board the board to add the player to
     * @throws IOException when the image can not be loaded
     */
    public Player(GraphicBoard board, Maze maze) throws IOException {
        this.board = board;
        this.maze = maze;
        
        image = new Picture("lostmazed/img/player.png");
        board.addObject(image);

        image.setKeyListener(new KeyListener() {
            @Override
            public void onKeyEvent(KeyEvent event) {
                onKey(event);
            }
        });
        
        image.moveTo(Game.WIDTH / 2, Game.HEIGHT / 2);
        
        new Timer().scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                onTimer();
            }
        }, 50, 50);
    }
    
    private void onTimer() {
        tryToMove(xSpeed, ySpeed, maze.getMaze());
    }
    
    /**
     * React to key events by moving the player.
     * @param event the key event
     */
    private void onKey(KeyEvent event) {
        int eventType = event.getID();
        
        if (eventType == KeyEvent.KEY_PRESSED || eventType == KeyEvent.KEY_RELEASED) {
            int newSpeed = 0;
            
            if (eventType == KeyEvent.KEY_PRESSED)
                newSpeed = 4;
            
            switch (event.getKeyCode()) {
                case KeyEvent.VK_UP:
                    ySpeed = -newSpeed;
                    break;
                case KeyEvent.VK_DOWN:
                    ySpeed = newSpeed;
                    break;
                case KeyEvent.VK_LEFT:
                    xSpeed = -newSpeed;
                    break;
                case KeyEvent.VK_RIGHT:
                    xSpeed = newSpeed;
                    break;
            }
        }
    }
    
    private void tryToMove(int deltaX, int deltaY, GraphicObject colliding) {
        board.lock();
        
        int xStep = Integer.signum(deltaX);
        
        for (int x = xStep; x != deltaX; x += xStep) {
            image.moveBy(xStep, 0);
            
            if (image.collidesWith(colliding)) {
                image.moveBy(-xStep, 0);
                break;
            }
        }
        
        int yStep = Integer.signum(deltaY);
        
        for (int y = yStep; y != deltaY; y += yStep) {
            image.moveBy(0, yStep);
            
            if (image.collidesWith(colliding)) {
                image.moveBy(0, -yStep);
                break;
            }
        }
        
        board.unlock();
    }
}

@@ -1314,37 +1314,8 @@
 rd;%0A
-import soga2d.GraphicObject;%0A
 impo
@@ -1551,21 +1551,16 @@
 e maze;%0A
-    %0A
     priv
@@ -2460,32 +2460,105 @@
 50);%0A    %7D%0A    %0A
+    /**%0A     * Called periodically to move the player if needed.%0A     */%0A
     private void
@@ -2606,24 +2606,8 @@
 peed
-, maze.getMaze()
 );%0A 
@@ -3534,100 +3534,409 @@
     
-private void tryToMove(int deltaX, int deltaY, GraphicObject colliding) %7B%0A        board.lock
+/**%0A     * Moves the player if there is no wall in the current direction.%0A     * %0A     * If there is a wall, moves the player as close to the wall as possible.%0A     * @param deltaX the number of pixels to move in x direction%0A     * @param deltaY the number of pixels to move in y direction%0A     */%0A    private void tryToMove(int deltaX, int deltaY) %7B%0A        board.lock();%0A        %0A        updateAngle
 ();%0A
@@ -4132,33 +4132,38 @@
 ollidesWith(
-colliding
+maze.getMaze()
 )) %7B%0A       
@@ -4448,17 +4448,22 @@
 ith(
-colliding
+maze.getMaze()
 )) %7B
@@ -4590,10 +4590,609 @@
 ;%0A    %7D%0A
+    %0A    /**%0A     * Updates the orientation of the image according to the current moving%0A     * direction.%0A     */%0A    private void updateAngle() %7B%0A        // add one to the direction (-1, 0 or 1) obtain an array index%0A        int xDirection = Integer.signum(xSpeed) + 1;%0A        int yDirection = Integer.signum(ySpeed) + 1;%0A        %0A        int%5B%5D%5B%5D angles = %7B%0A            %7B-45, 0, 45%7D,%0A            %7B-90, -1, 90%7D,%0A            %7B-135, 180, 135%7D%0A        %7D;%0A        %0A        int newAngle = angles%5ByDirection%5D%5BxDirection%5D;%0A        %0A        if (newAngle != -1)%0A            image.setAngle(newAngle);%0A    %7D%0A
 %7D%0A

Add player rotation