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();
                TerrainFacing facing = cell.determineFacing(x, y, terrain);
                terrain.setFacing(facing);
			}
		}
	}



    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(int xOfCellInCenter, int yOfCellInCenter, Terrain terrainOfCellInCenter) {
            FacingDeterminer facingDeterminer = new FacingDeterminer();
            final Cell topNeighbour = getCellTopNeighbour(xOfCellInCenter, yOfCellInCenter);
            final Cell rightNeighbour = getCellRightNeighbour(xOfCellInCenter, yOfCellInCenter);
            final Cell bottomNeighbour = getCellBottomNeighbour(xOfCellInCenter, yOfCellInCenter);
            final Cell leftNeighbour = getCellLeftNeighbour(xOfCellInCenter, yOfCellInCenter);
            facingDeterminer.setTopSame(terrainOfCellInCenter.isSame(topNeighbour.getTerrain()));
            facingDeterminer.setRightSame(terrainOfCellInCenter.isSame(rightNeighbour.getTerrain()));
            facingDeterminer.setBottomSame(terrainOfCellInCenter.isSame(bottomNeighbour.getTerrain()));
            facingDeterminer.setLeftSame(terrainOfCellInCenter.isSame(leftNeighbour.getTerrain()));
            return facingDeterminer.getFacing();
        }

        private Cell getCellLeftNeighbour(int x, int y) {
            return cells[x-1][y];
        }

        private Cell getCellBottomNeighbour(int x, int y) {
            return cells[x][y+1];
        }

        private Cell getCellRightNeighbour(int x, int y) {
            return cells[x+1][y];
        }

        private Cell getCellTopNeighbour(int x, int y) {
            return cells[x][y-1];
        }
    }



}

@@ -2200,31 +2200,26 @@
     
-T
+t
 errain
+.set
 Facing
- facing = 
+(
 cell
@@ -2239,65 +2239,9 @@
 ing(
-x, y, terrain);%0D%0A                terrain.setFacing(facing
+)
 );%0D%0A
@@ -2431,26 +2431,24 @@
        %7D%0D%0A%0D%0A
-%0D%0A
         publ
@@ -2583,82 +2583,56 @@
 ing(
-int xOfCellInCenter, int yOfCellInCenter, Terrain terrainOfCellInCenter) %7B
+) %7B%0D%0A            Terrain terrain = getTerrain();
 %0D%0A  
@@ -2764,40 +2764,8 @@
 our(
-xOfCellInCenter, yOfCellInCenter
 );%0D%0A
@@ -2830,40 +2830,8 @@
 our(
-xOfCellInCenter, yOfCellInCenter
 );%0D%0A
@@ -2898,40 +2898,8 @@
 our(
-xOfCellInCenter, yOfCellInCenter
 );%0D%0A
@@ -2962,40 +2962,8 @@
 our(
-xOfCellInCenter, yOfCellInCenter
 );%0D%0A
@@ -3005,38 +3005,24 @@
 Same(terrain
-OfCellInCenter
 .isSame(topN
@@ -3092,38 +3092,24 @@
 Same(terrain
-OfCellInCenter
 .isSame(righ
@@ -3182,38 +3182,24 @@
 Same(terrain
-OfCellInCenter
 .isSame(bott
@@ -3279,22 +3279,8 @@
 rain
-OfCellInCenter
 .isS
@@ -3415,36 +3415,24 @@
 ftNeighbour(
-int x, int y
 ) %7B%0D%0A       
@@ -3512,36 +3512,24 @@
 omNeighbour(
-int x, int y
 ) %7B%0D%0A       
@@ -3608,36 +3608,24 @@
 htNeighbour(
-int x, int y
 ) %7B%0D%0A       
@@ -3706,28 +3706,16 @@
 ighbour(
-int x, int y
 ) %7B%0D%0A   

remove parameters from private squareCell class.