package com.fundynamic.dune2themaker.game.map;

import org.newdawn.slick.Image;
import org.newdawn.slick.SlickException;
import com.fundynamic.dune2themaker.game.TerrainFactory;
import com.fundynamic.dune2themaker.game.terrain.Terrain;
import com.fundynamic.dune2themaker.game.terrain.TerrainFacing;

public class Map {

	private final TerrainFactory terrainFactory;
	private final int height, width;
	private Image mapImage;

	private boolean initialized;

	private Cell[][] cells;

	public Map(TerrainFactory terrainFactory, int width, int height) throws SlickException {
		this.terrainFactory = terrainFactory;
		this.height = height;
		this.width = width;
	}

	public int getWidth() {
		return width;
	}

	public int getHeight() {
		return height;
	}

	public Cell getCell(int x, int y) {
		return cells[x][y];
	}

	public Image getMapImage() throws SlickException {
		if (this.mapImage == null) {
			mapImage = new MapRenderer().render(this);
		}
		return mapImage;
	}

	public void init() throws SlickException {
		if (!initialized) {
			// this does not work when we move the code in the constructor?
			initializeEmptyMap(width, height);
			putTerrainOnMap();
            smooth();
            initialized = true;
		}
	}

	private void initializeEmptyMap(int width, int height) {
		this.cells = new Cell[width + 2][height + 2];
		for (int x = 0; x < this.width + 2; x++) {
			for (int y = 0; y < this.height + 2; y++) {
				cells[x][y] = new Cell(terrainFactory.createEmptyTerrain());
			}
		}
	}

	// @TODO: move this to a MapLoader / MapCreator / MapFactory / MapRepository
	private void putTerrainOnMap() {
		for (int x = 1; x <= this.width; x++) {
			for (int y = 1; y <= this.height; y++) {
				final Cell cell = cells[x][y];
				final Terrain terrain = terrainFactory.create((int) (Math.random() * 7), cell);
				cell.changeTerrain(terrain);
			}
		}
	}

	public void smooth() {
		for (int x = 1; x <= this.width; x++) {
            for (int y = 1; y <= this.height; y++) {
                final SquareCell cell = new SquareCell(x, y);
                final Terrain terrain = cell.getTerrain();
                terrain.setFacing(cell.determineFacing());
			}
		}
	}

    private class SquareCell {
        private final int x, y;

        private SquareCell(int x, int y) {
            this.x = x;
            this.y = y;
        }

        public Terrain getTerrain() {
            return cells[x][y].getTerrain();
        }

        private TerrainFacing determineFacing() {
            Terrain terrain = getTerrain();
            FacingDeterminer facingDeterminer = new FacingDeterminer();
            facingDeterminer.setTopSame(terrain.isSame(getTerrainTopNeighbour()));
            facingDeterminer.setRightSame(terrain.isSame(getTerrainRightNeighbour()));
            facingDeterminer.setBottomSame(terrain.isSame(getTerrainBottomNeighbour()));
            facingDeterminer.setLeftSame(terrain.isSame(getTerrainLeftNeighbour()));
            return facingDeterminer.getFacing();
        }

        private Cell getCell(int x, int y) {
            return cells[x][y];
        }

        private Terrain getTerrainLeftNeighbour() {
            return getCell(x - 1, y).getTerrain();
        }

        private Terrain getTerrainBottomNeighbour() {
            return getCell(x, y + 1).getTerrain();
        }

        private Terrain getTerrainRightNeighbour() {
            return getCell(x + 1, y).getTerrain();
        }

        private Terrain getTerrainTopNeighbour() {
            return getCell(x, y - 1).getTerrain();
        }
    }



}

@@ -2753,38 +2753,26 @@
 .isSame(
-get
+top
 Terrain
-TopNeighbour
 ()));%0D%0A 
@@ -2827,26 +2827,28 @@
 .isSame(
-ge
+righ
 tTerrain
 RightNei
@@ -2839,30 +2839,16 @@
 tTerrain
-RightNeighbour
 ()));%0D%0A 
@@ -2908,33 +2908,21 @@
 ame(
-get
+bottom
 Terrain
-BottomNeighbour
 ()))
@@ -2980,26 +2980,27 @@
 .isSame(
-ge
+lef
 tTerrain
 LeftNeig
@@ -2991,29 +2991,16 @@
 tTerrain
-LeftNeighbour
 ()));%0D%0A 
@@ -3177,26 +3177,27 @@
 Terrain 
-ge
+lef
 tTerrain
 LeftNeig
@@ -3192,21 +3192,8 @@
 rain
-LeftNeighbour
 () %7B
@@ -3287,33 +3287,21 @@
 ain 
-get
+bottom
 Terrain
-BottomNeighbour
 () %7B
@@ -3391,26 +3391,28 @@
 Terrain 
-ge
+righ
 tTerrain
 RightNei
@@ -3407,22 +3407,8 @@
 rain
-RightNeighbour
 () %7B
@@ -3502,30 +3502,18 @@
 ain 
-get
+top
 Terrain
-TopNeighbour
 () %7B

rename getTerrainX methods into xTerrain