package agents.spencerSchumann;

import java.util.ArrayList;

import engine.core.MarioForwardModel;

/**
 * @author Spencer Schumann
 */
public class Tiles {

    public static final byte EMPTY = 0;
    public static final byte SOLID = 1;
    public static final byte JUMPTHROUGH = 2;
    public static final byte BRICK = 5;
    public static final byte QUESTION = 6;
    public static final byte COIN = 7;
    public static final byte UNKNOWN = -1;

    public static boolean isWall(int tile) {
        switch (tile) {
            case SOLID:
            case BRICK:
            case QUESTION:
                return true;
            default:
                return false;
        }
    }

    private class Column {

        public int startRow = 0;
        int[] tiles = null;

        public void setTile(int y, int tile) {
            if (tiles == null) {
                tiles = new int[1];
                tiles[0] = tile;
                startRow = y;
            } else {
                if (startRow > y) {
                    int expansion = startRow - y;
                    int[] newTiles = new int[tiles.length + expansion];
                    System.arraycopy(tiles, 0, newTiles, expansion, tiles.length);
                    int i;
                    for (i = 0; i < startRow; i++) {
                        newTiles[i] = UNKNOWN;
                    }
                    tiles = newTiles;
                    startRow = y;
                } else if (y >= startRow + tiles.length) {
                    int expansion = y - startRow - tiles.length + 1;
                    int[] newTiles = new int[tiles.length + expansion];
                    System.arraycopy(tiles, 0, newTiles, 0, tiles.length);
                    int i;
                    for (i = tiles.length; i < newTiles.length; i++) {
                        newTiles[i] = UNKNOWN;
                    }
                    tiles = newTiles;
                }
                tiles[y - startRow] = tile;
            }
        }

        public int getTile(int y) {
            if (y < startRow || y >= startRow + tiles.length) {
                return UNKNOWN;
            } else {
                return tiles[y - startRow];
            }
        }
    }

    ArrayList<Column> columns;

    public Tiles() {
        columns = new ArrayList<Column>();
    }

    private void setTile(int x, int y, int tile) {
        if (x < 0) {
            return;
        }
        while (x >= columns.size()) {
            columns.add(null);
        }
        Column c = columns.get(x);
        if (c == null) {
            c = new Column();
            columns.set(x, c);
        }
        c.setTile(y, tile);
    }

    public int getTile(int x, int y) {
        if (x < 0) {
            return EMPTY;
        } else if (x >= columns.size()) {
            return UNKNOWN;
        }
        Column c = columns.get(x);
        if (c == null) {
            return UNKNOWN;
        } else {
            return c.getTile(y);
        }
    }

    public int[][] getScene(int x, int y, int width, int height) {
        int[][] scene = new int[height][width];
        int row, col;
        for (row = 0; row < height; row++) {
            for (col = 0; col < width; col++) {
                scene[row][col] = getTile(col + x, row + y);
            }
        }
        return scene;
    }

    public void addObservation(MarioForwardModel model) {
        int[][] scene = model.getMarioSceneObservation();

        float[] marioPos = model.getMarioFloatPos();
        int offsetX = (int) (marioPos[0] / 16.0f);
        int offsetY = (int) (marioPos[1] / 16.0f);
        offsetX -= model.obsGridWidth / 2;
        offsetY -= model.obsGridHeight / 2;

        int x, y;
        for (x = 0; x < scene.length; x++) {
            for (y = 0; y < scene[x].length; y++) {
                int tile = scene[x][y];
                switch (tile) {
                    case 0: // nothing
                        tile = EMPTY;
                        break;
                    case 17:
                        tile = SOLID;
                        break;
                    case 23: // Brick
                        tile = BRICK;
                        break;
                    case 24: // Question 
                        tile = QUESTION;
                        break;
                    case 31: // coin
                        tile = COIN;
                        break;
                    case 59: // Ledge
                        tile = JUMPTHROUGH;
                        break;
                    default:
                        tile = UNKNOWN;
                        break;
                }
                if (tile != UNKNOWN) {
                    setTile(x + offsetX, y + offsetY, tile);
                }
            }
        }
    }
}
