import theater.*;

import java.awt.Color;
import java.awt.event.KeyEvent;


public class CurvesWorld extends Stage {
    public final static int WIDTH = 800;
    public final static int HEIGHT = 600;
    public final static int BORDERWIDTH = 100;
    public final static int MAX_NOOF_PLAYERS = 5;
    public final static int FRAGMENT_SIZE = 4;
    final static int TITLE = 0;
    final static int CHOICE_BEGIN = 1;
    final static int CHOICE_WAIT = 2;
    final static int CHOICE_ENDED = 3;
    final static int ROUND_STARTED = 4;
    final static int ROUND_ACTIVE = 5;
    final static int ROUND_END_WAIT = 12;
    final static int ROUND_ENDED = 6;
    final static int GAME_END = 7;
    final static int NEW_GAME = 8;
    final static int END = 9;
    final static int COUNTDOWN = 10;
    final static int COUNTDOWN_WAIT = 11;
    int gameState;
    Title title;
    Button[] playerChoice;
    Clock clock = null;
    Clock waitClock = null;
    CountDown countDown;
    Border border;
    ChoiceButton nButton;
    ChoiceButton qButton;
    Color[] colors;
    int[] minusKeys;
    int[] plusKeys;
    Points[] points;
    int numberOfPlayers;
    int numberOfLiving;
    Player[] player;
    Curve[] curve;
    boolean[] dead;

    public CurvesWorld() {
        super(WIDTH, HEIGHT, 1);
        Performance.getPerformance().setSpeed(38);
        createAndSetBackground();
        createValues();
        setTitle();
    }

    public void run() {
        switch (gameState) {
        case TITLE:
            handleTitle();

            break;

        case CHOICE_BEGIN:
            handleChoice();

            break;

        case CHOICE_WAIT:
            break;

        case CHOICE_ENDED:
            handleChoiceEnd();

            break;

        case COUNTDOWN:
            countDown();

            break;

        case COUNTDOWN_WAIT:
            break;

        case ROUND_STARTED:
            handleRound();

            break;

        case ROUND_ACTIVE:
            break;

        case ROUND_END_WAIT:
            handleWait();

            break;

        case ROUND_ENDED:
            handleRoundEnd();

            break;

        case GAME_END:
            handleGameEnd();

            break;

        case NEW_GAME:
            handleNewGame();

            break;

        case END:
            handleEnd();
            Performance.getPerformance().stop();

            break;
        }
    }

    void setTitle() {
        title = new Title();
        add(title, WIDTH / 2, HEIGHT / 2);
        gameState = TITLE;
    }

    void finishChoice(int players) {
        this.numberOfPlayers = players;
        this.gameState = CHOICE_ENDED;
    }

    void dead(Player pl) {
        dead[pl.getNumber()] = true;
        pl.addPoints(numberOfPlayers - numberOfLiving);
        points[pl.getNumber()].update();
        numberOfLiving--;

        if (numberOfLiving == 1) {
            int l = getLiving();
            player[l].addPoints(numberOfPlayers - 1);
            points[l].update();
            curve[l].stop();
            gameState = ROUND_END_WAIT;
        }
    }

    private int getLiving() {
        for (int i = 0; i < numberOfPlayers; i++) {
            if (!dead[i]) {
                return i;
            }
        }

        return -1; // not possible
    }

    void countDownFinished() {
        remove(countDown);
        countDown = null;
        gameState = ROUND_STARTED;
    }

    private void createAndSetBackground() {
        TheaterImage image = new TheaterImage(WIDTH, HEIGHT);
        image.setColor(Color.BLACK);
        image.fillRect(0, 0, WIDTH, HEIGHT);
        setBackground(image);
    }

    private void createValues() {
        this.colors = new Color[MAX_NOOF_PLAYERS];
        this.colors[0] = Color.RED;
        this.colors[1] = Color.GREEN;
        this.colors[2] = Color.BLUE;
        this.colors[3] = Color.YELLOW;
        this.colors[4] = Color.MAGENTA;
        // this.colors[5] = Color.ORANGE;
        this.minusKeys = new int[MAX_NOOF_PLAYERS];
        this.minusKeys[0] = KeyEvent.VK_Q;
        this.minusKeys[1] = KeyEvent.VK_LEFT;
        this.minusKeys[2] = KeyEvent.VK_S;
        this.minusKeys[3] = KeyEvent.VK_K;
        this.minusKeys[4] = KeyEvent.VK_D;
        // this.minusKeys[5] = "j";
        this.plusKeys = new int[MAX_NOOF_PLAYERS];
        this.plusKeys[0] = KeyEvent.VK_A;
        this.plusKeys[1] = KeyEvent.VK_RIGHT;
        this.plusKeys[2] = KeyEvent.VK_X;
        this.plusKeys[3] = KeyEvent.VK_M;
        this.plusKeys[4] = KeyEvent.VK_C;

        // this.plusKeys[5] = "n";
    }

    private void handleTitle() {
        if (clock == null) {
            clock = new Clock(1500);
        }

        if (clock.isNull()) {
            remove(title);
            clock = null;
            gameState = CHOICE_BEGIN;
        }
    }

    private void handleChoice() {
        playerChoice = new Button[MAX_NOOF_PLAYERS];

        for (int i = 1; i < MAX_NOOF_PLAYERS; i++) {
            playerChoice[i] = new Button("players", i + 1, this.colors[i]);
            add(playerChoice[i], getNumberOfColumns() / 2, i * 100);
        }

        gameState = CHOICE_WAIT;
    }

    private void handleChoiceEnd() {
        this.remove(this.getComponents());

        player = new Player[this.numberOfPlayers];

        for (int i = 0; i < this.numberOfPlayers; i++) {
            player[i] = new Player(i, colors[i], minusKeys[i], plusKeys[i]);
        }

        if (border == null) {
            border = new Border(BORDERWIDTH, this.getNumberOfRows());
            add(border, getNumberOfColumns() - (BORDERWIDTH / 2),
                getNumberOfRows() / 2);
            points = new Points[this.numberOfPlayers];

            for (int i = 0; i < this.numberOfPlayers; i++) {
                points[i] = new Points(player[i]);
                add(points[i], getNumberOfColumns() - (BORDERWIDTH / 2),
                    (i + 1) * 100);
            }
        }

        gameState = COUNTDOWN;
    }

    private void countDown() {
        countDown = new CountDown(5);
        add(countDown, (getNumberOfColumns() - BORDERWIDTH) / 2,
            getNumberOfRows() / 2);
        gameState = COUNTDOWN_WAIT;
    }

    private void handleRound() {
        dead = new boolean[this.numberOfPlayers];
        curve = new Curve[this.numberOfPlayers];

        for (int i = 0; i < this.numberOfPlayers; i++) {
            dead[i] = false;
            curve[i] = new Curve(player[i]);

            int x = new java.util.Random().nextInt(WIDTH - BORDERWIDTH - 100) +
                50;
            int y = new java.util.Random().nextInt(HEIGHT - 100) + 50;
            int rotation = new java.util.Random().nextInt(360);
            curve[i].setRotation(rotation);
            add(curve[i], x, y);
        }

        Curve.startClock();
        numberOfLiving = this.numberOfPlayers;
        gameState = ROUND_ACTIVE;
    }

    private void handleWait() {
        if (waitClock == null) {
            waitClock = new Clock(2000);
        }

        if (waitClock.isNull()) {
            waitClock = null;
            gameState = ROUND_ENDED;
        }
    }

    private void handleRoundEnd() {
        this.remove(this.getComponents(Fragment.class));

        if (gameEnded()) {
            gameState = GAME_END;
        } else {
            gameState = COUNTDOWN;
        }
    }

    private boolean gameEnded() {
        for (int i = 0; i < this.numberOfPlayers; i++) {
            if (player[i].getPoints() >= ((this.numberOfPlayers - 1) * 10)) {
                return true;
            }
        }

        return false;
    }

    private void handleGameEnd() {
        remove(border);
        this.remove(getComponents(Points.class));
        border = null;

        for (int i = 0; i < this.numberOfPlayers; i++) {
            Points text = new Points(player[i]);
            add(text, getNumberOfColumns() / 2, (i + 1) * 100);
        }

        nButton = new ChoiceButton("New Game?");
        add(nButton, (1 * getNumberOfColumns()) / 3, MAX_NOOF_PLAYERS * 100);
        qButton = new ChoiceButton("Quit?");
        add(qButton, (2 * getNumberOfColumns()) / 3, MAX_NOOF_PLAYERS * 100);
        gameState = NEW_GAME;
    }

    private void handleNewGame() {
        // auf finishChoice warten
    }

    void finishChoice(ChoiceButton cButton) {
        if (cButton == nButton) {
            this.remove(this.getComponents());
            player = new Player[this.numberOfPlayers];

            for (int i = 0; i < this.numberOfPlayers; i++) {
                player[i] = new Player(i, colors[i], minusKeys[i], plusKeys[i]);
            }

            gameState = CHOICE_BEGIN;
        } else if (cButton == qButton) {
            gameState = END;
        }
    }

    private void handleEnd() {
        this.remove(this.getComponents());
        add(new End(), getNumberOfColumns() / 2, getNumberOfRows() / 2);
    }

    public void mousePressed(MouseInfo event) {
        switch (gameState) {
        case NEW_GAME:
            handleNewGame();

            break;
        }
    }

    public void keyPressed(KeyInfo event) {
        switch (gameState) {
        case TITLE:
            remove(title);
            clock = null;
            gameState = CHOICE_BEGIN;
        }
    }
}
