package pathgame.tilemap;

import java.util.Iterator;
import java.util.LinkedList;

/** Fixed size container for tile maps. Changes are stored in a dirty flag,
 * which can be used for rendering.
 *
 * @author kajetan
 */
public class TileMap
{
    private static class TownConverter
    {
        private int x;
        private int y;
        private int ticks = 0;
        private int index = -1;
    }
    
    private int towns = 0;
    private final int width;
    private final int height;
    private final int[][] tiles;
    private boolean dirty = true;
    private final LinkedList<TownConverter> townConverters = new LinkedList<>();
    
    private int homeX;
    private int homeY;
    
    /** Creates a new tile map of the given size.
     *
     * @param width the width of the map
     * @param height the height of the map
     */
    public TileMap(int width, int height)
    {
        this.width = width;
        this.height = height;
        tiles = new int[width][height];
    }
    
    /** Returns the width of the map.
     *
     * @return the width of the map
     */
    public int getWidth()
    {
        return width;
    }

    /** Returns the height of the map.
     *
     * @return the height of the map
     */
    public int getHeight()
    {
        return height;
    }
    
    /** Sets the tile at the given map position. The dirty flag is set.
     *
     * @param x the x coordinate of the tile
     * @param y the y coordinate of the tile
     * @param tile a tile
     */
    public void setTile(int x, int y, Tile tile)
    {
        dirty = true;
        if(tiles[x][y] == Tiles.TOWN.getId())
        {
            towns--;
        }
        if(tile == Tiles.TOWN)
        {
            towns++;
        }
        tiles[x][y] = tile.getId();
    }
    
    /** Returns the tile at the given map position or null if the tile is invalid.
     *
     * @param x the x coordinate of the tile
     * @param y the y coordinate of the tile
     * @return the tile at the given map position or null if the tile is invalid
     */
    public Tile getTile(int x, int y)
    {
        return Tile.fromId(tiles[x][y]);
    }

    /** Returns true if the map was modified. This is used for rendering.
     *
     * @return true if the map was modified
     */
    public boolean isDirty()
    {
        return dirty;
    }
    
    /** Clears the dirty flag of the map.
     *
     */
    public void clean()
    {
        dirty = false;
    }
    
    public void tick()
    {
        Iterator<TownConverter> iter = townConverters.iterator();
        while(iter.hasNext())
        {
            TownConverter tc = iter.next();
            tc.ticks++;
            if(tc.ticks % 10 == 0)
            {
                tc.index++;
                if(tc.index >= Tiles.TOWN_BLOCKED.length)
                {
                    iter.remove();
                    continue;
                }
                setTile(tc.x, tc.y, Tiles.TOWN_BLOCKED[tc.index]);
            }
        }
    }
    
    /** Slowly Converts a tile into blocked town.
     *
     * @param x the x coordinate of the tile
     * @param y the y coordinate of the tile
     */
    public void convertTown(int x, int y)
    {
        TownConverter tc = new TownConverter();
        tc.x = x;
        tc.y = y;
        townConverters.add(tc);
    }
    
    /** Returns the number of active towns.
     *
     * @return the number of active towns
     */
    public int getNumberOfTowns()
    {
        return towns;
    }
    
    /** Sets the position of the home town.
     *
     * @param x the x coordinate of the home town 
     * @param y the y coordinate of the home town
     */
    public void setHomeTown(int x, int y)
    {
        homeX = x;
        homeY = y;
    }

    /** Returns the x coordinate of the home town.
     *
     * @return the x coordinate of the home town
     */
    public int getHomeX()
    {
        return homeX;
    }

    /** Returns the y coordinate of the home town.
     *
     * @return the y coordinate of the home town
     */
    public int getHomeY()
    {
        return homeY;
    }
}

