import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.LinkedList;
import java.util.List;

public class Controller extends KeyAdapter implements FocusListener {
    public Controller(GamePanel gamePanel, Ground ground) {
        this.gamePanel = gamePanel;
        this.ground = ground;
        this.delay = Config.getInstance().getDelay();
        this.gamePanel.setBackground(Config.getInstance().getBackgroundColor());
        
        enableTetrisAutoDown();
    }
    
    // 开始游戏
    public void startGame() {
        score = 0;
        suspended = false;
        delay = Config.getInstance().getDelay();
        ground.clear();
        currentShape = ShapeFactory.createShape();
        gamePanel.setGameOver(false);
        gamePanel.setScore(score); // 删除上次的得分
        
        while (!nextShapes.isEmpty()) {
            nextShapes.remove(0);
        }
        int count = Config.getInstance().getNextShapesCount();
        for (int i = 0; i < count; ++i) {
            nextShapes.add(ShapeFactory.createShape());
        }
    }

    public void suspend() {
        suspended = true;
    }

    public void resume() {
        suspended = false;
    }

    @Override
    public void keyPressed(KeyEvent e) {
        int code = e.getKeyCode();
        
        // 控制模块
        switch (code) {
        case KeyEvent.VK_N:
            startGame();
            return;
        case KeyEvent.VK_Q:
            System.exit(0);
            return;
        case KeyEvent.VK_P:
            suspended = !suspended;
        }
            
        // 保证游戏结束后不会发生空指针异常，游戏停止时也不处理键盘按下事件
        if (currentShape == null || suspended) {
            return;
        }

        // 先进行变形，如果变形后不适合，再变形回来
        switch (code) {
        case KeyEvent.VK_W:
        case KeyEvent.VK_UP:
            currentShape.rotateRight();
            if (!isShapeMoveable(currentShape)) {
                currentShape.rotateLeft();
            }
            break;
        case KeyEvent.VK_S:
        case KeyEvent.VK_DOWN:
            moveShapeDown(currentShape);
            break;
        case KeyEvent.VK_SPACE:
            do {
                currentShape.moveDown();
            } while (isShapeMoveable(currentShape));
            currentShape.moveUp();
            
            // 因为已经移动到最底部了，所以往上再走一步，缓冲一下(时间: 当前delay)
            currentShape.moveUp();
            moveShapeDown(currentShape);
            break;
        case KeyEvent.VK_A:
        case KeyEvent.VK_LEFT:
            currentShape.moveLeft();
            if (!isShapeMoveable(currentShape)) {
                currentShape.moveRight();
            }
            break;
        case KeyEvent.VK_D:
        case KeyEvent.VK_RIGHT:
            currentShape.moveRight();
            if (!isShapeMoveable(currentShape)) {
                currentShape.moveLeft();
            }
            break;
        case KeyEvent.VK_B:
            boolean yes = Config.getInstance().isBackgroundDrawn();
            yes = !yes;
            Config.getInstance().setBackgroundDrawn(yes);
            break;
        case KeyEvent.VK_L:
            nextShapes.remove(nextShapes.size() - 1);
            nextShapes.add(0, ShapeFactory.createLongShape());
            break;
        }

        refreshGamePanel();
    }
    
    @Override
    public void focusGained(FocusEvent e) {
        resume();
    }
    
    @Override
    public void focusLost(FocusEvent e) {
        suspend();
    }
    
    private void enableTetrisAutoDown() {
     // 方块自动下落
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    while (true) {
                        if (!suspended) {
                            if (currentShape != null && Controller.this.ground != null) {
                                moveShapeDown(currentShape);
                                refreshGamePanel();
                            }
                        }
                        Thread.sleep(delay);
                    }
                } catch (Exception e) {
                }
            }
        }).start();
    }

    private void refreshGamePanel() {
        gamePanel.display(currentShape, nextShapes, ground);
    }
    
    private void moveShapeDown(final Shape shape) {
        // 当方块不能再下落时，合并到Ground中
        shape.moveDown();
        if (!isShapeMoveable(shape)) {
            shape.moveUp();
            score += ground.accept(shape);
            gamePanel.setScore(score);

            // 每多得10分，加快下落速度10毫秒
            if (score - preScore > Config.getInstance().getAccelerateStep()) {
                preScore = score;

                if (delay > 60) {
                    delay -= Config.getInstance().getAcceleration();
                }
            }

            if (isGameOver()) {
                // 因为在下落线程一直不停的试途下落，所以在游戏结束后置为空.
                currentShape = null;
                gamePanel.setGameOver(true);
            } else {
                if (!nextShapes.isEmpty()) {
                    currentShape = nextShapes.remove(0);
                }
                nextShapes.add(ShapeFactory.createShape());
            }
        }
    }
    
    // 判断方块是否可以左移，右移，旋转，下落
    private boolean isShapeMoveable(Shape shape) {
        int shapeX = shape.getX();
        int shapeY = shape.getY();
    
        boolean movable = true;
        
        // 查看方块中为1的位置
        // 1. 是否超出了Ground的左边和右边，下方
        // 2. 在Gound中对应的位置上是否也为1，如果为1，则不可以变化.
        // 3. 是否超出了Ground的下方.
        outer: for (int sx = 0; sx < shape.getColumnCount(); ++sx) {
            for (int sy = 0; sy < shape.getRowCount(); ++sy) {
                if (shape.getCellValue(sx, sy) == 1) {
                    // 在Ground中的坐标(x, y)，相对于Ground的左上角
                    int x = shapeX + sx;
                    int y = shapeY + sy;
                    
                    if (x < 0 || x >= ground.getColumnCount() || y >= ground.getRowCount()) {
                        // 超出左右两边，或下方
                        movable = false;
                        break outer;
                    } else if (y >= 0 && y < ground.getRowCount() && ground.getCellValue(x, y) == 1) {
                        movable = false;
                        break outer;
                    }
                }
            }
        }
    
        return movable;
    }

    // 只要在Ground的第一行有方块，说明游戏结束
    private boolean isGameOver() {
        for (int x = 0; x < ground.getColumnCount(); ++x) {
            if (ground.getCellValue(x, 0) == 1) { return true; }
        }
        return false;
    }

    private int delay;
    private int score;
    private int preScore;
    private boolean suspended = true;
    private Shape currentShape;
    private List<Shape> nextShapes = new LinkedList<Shape>();
    private Ground ground;
    private GamePanel gamePanel;
}
