package org.academiadecodigo.enuminatti.paint.grid;

import org.academiadecodigo.enuminatti.paint.file.Save;
import org.academiadecodigo.simplegraphics.keyboard.*;

/**
 * MIT License
 * (c) 2017 Ricardo Constantino
 */

public class Grid implements KeyboardHandler {

    private final int cols;
    private final int rows;

    private final String SAVEFILE = "resources/save.txt";

    private Cell[] cells;
    private Cursor cursor;
    private boolean quitPressed;

    public Grid(int cols, int rows) {
        this.cols = cols;
        this.rows = rows;

        cursor = new Cursor(this, 0, 0);

        cells = new Cell[cols * rows];

        int cellNum = 0;
        for (int row = 0; row < rows; row++) {
            for (int col = 0; col < cols; col++) {
                cells[cellNum++] = new Cell(col, row);
            }
        }

        addHandlers();
    }

    private void addHandlers() {
        Keyboard k = new Keyboard(this);

        int[] keys = new int[]{
                KeyboardEvent.KEY_LEFT,
                KeyboardEvent.KEY_RIGHT,
                KeyboardEvent.KEY_UP,
                KeyboardEvent.KEY_DOWN,
                KeyboardEvent.KEY_SPACE,
                KeyboardEvent.KEY_S,
                KeyboardEvent.KEY_L,
                KeyboardEvent.KEY_C,
                KeyboardEvent.KEY_Q,
                KeyboardEvent.KEY_T
        };

        for (int key : keys) {
            KeyboardEvent newKey = new KeyboardEvent();
            newKey.setKey(key);
            newKey.setKeyboardEventType(KeyboardEventType.KEY_PRESSED);
            k.addEventListener(newKey);
        }
    }

    @Override
    public void keyPressed(KeyboardEvent e) {
        switch (e.getKey()) {
            case KeyboardEvent.KEY_LEFT:
                cursor.moveLeft();
                break;
            case KeyboardEvent.KEY_RIGHT:
                cursor.moveRight();
                break;
            case KeyboardEvent.KEY_UP:
                cursor.moveUp();
                break;
            case KeyboardEvent.KEY_DOWN:
                cursor.moveDown();
                break;
            case KeyboardEvent.KEY_SPACE:
                setCellColor(cursor.getCol(), cursor.getRow(), cursor.getCurrentSwatch());
                break;
            case KeyboardEvent.KEY_S:
                save();
                break;
            case KeyboardEvent.KEY_L:
                load();
                break;
            case KeyboardEvent.KEY_C:
                reset();
                break;
            case KeyboardEvent.KEY_Q:
                quitPressed = true;
                break;
            case KeyboardEvent.KEY_T:
                cursor.toggleSwatch();
                break;

        }
    }

    private void reset() {
        for (Cell cell : cells) {
            cell.unpaint();
        }
    }

    @Override
    public void keyReleased(KeyboardEvent e) {

    }

    private void save() {
        Save.save(cellsToCharArray(cells), SAVEFILE);
    }

    private void load() {
        char[] cellsToLoad = Save.load(cols, rows, SAVEFILE);

        for (int i = 0; i < cells.length; i++) {
            cells[i].setPainted(Swatch.fromChar(cellsToLoad[i]));
        }
    }


    private void toggleCell(int col, int row) {
        cells[posToIdx(col, row)].togglePainted();
    }

    private void setCellColor(int col, int row, Swatch swatch) {
        cells[posToIdx(col, row)].setPainted(swatch);
    }

    public int getCols() {
        return cols;
    }

    public int getRows() {
        return rows;
    }

    private int posToIdx(int col, int row) {
        int calcCol = Math.min(cols - 1, Math.max(0, col));
        int calcRow = Math.min(rows - 1, Math.max(0, row));

        return calcCol + calcRow * cols;
    }

    private static char[] cellsToCharArray(Cell[] cells) {
        char[] chars = new char[cells.length];

        for (int i = 0; i < cells.length; i++) {
            chars[i] = cells[i].toChar();
        }

        return chars;
    }

    public Cell[] getCells() {
        return cells;
    }

    public Cursor getCursor() {
        return cursor;
    }

    public boolean pressedQuit() {
        return quitPressed;
    }
}
