package net.cobem.grizzly.habbohotel.rooms;

import net.cobem.grizzly.habbohotel.pathfinding.AffectedTile;
import net.cobem.grizzly.habbohotel.pathfinding.Position;
import net.cobem.grizzly.habbohotel.rooms.items.FloorItem;
import net.cobem.grizzly.habbohotel.rooms.models.SquareState;

public class RoomMap {
    private Room Room;

    public byte[][] FurniCollisionMap;
    public boolean[][] UserCollisionMap;

    public RoomMap(Room mRoom) {
        this.Room = mRoom;

        FurniCollisionMap = new byte[this.Room.getModel().MapSizeX][this.Room.getModel().MapSizeY];
        UserCollisionMap = new boolean[this.Room.getModel().MapSizeX][this.Room.getModel().MapSizeY];

        for (int x = 0; x < this.Room.getModel().MapSizeX; x++) //Loopception courtesy of Cobe & Cecer
        {
            for (int y = 0; y < this.Room.getModel().MapSizeY; y++) {
                FurniCollisionMap[x][y] = 1;
            }
        }
    }

    public void GenerateFurniCollisionMap() {
        for (int x = 0; x < this.Room.getModel().MapSizeX; x++) //Loopception courtesy of Cobe & Cecer
        {
            for (int y = 0; y < this.Room.getModel().MapSizeY; y++) {
                FurniCollisionMap[x][y] = 1;
            }
        }

        for (FloorItem Item : this.Room.getFloors().values()) {

            if (Item == null) {
                continue;
            }

            if (Item.getBase().Width == 1 && Item.getBase().Length == 1) {
                if (!Item.getBase().Sitable && !Item.getBase().Walkable && !Item.getBase().Layable) {
                    FurniCollisionMap[Item.X][Item.Y] = 0;
                }

                if (Item.getBase().Sitable || Item.getBase().Layable) {
                    FurniCollisionMap[Item.X][Item.Y] = 2;
                }

                if (Item.getBase().Interaction.equals("gate") && Item.ExtraData.equals("1")){
                    FurniCollisionMap[Item.X][Item.Y] = 1;
                }
            } else {
                for (AffectedTile Tile : AffectedTile.GetAffectedTiles(Item.getBase().Length, Item.getBase().Width, Item.X, Item.Y, Item.Rotation)) {
                    if (!Item.getBase().Sitable && !Item.getBase().Walkable && !Item.getBase().Layable) {
                        FurniCollisionMap[Tile.X][Tile.Y] = 0;
                    }

                    if (Item.getBase().Sitable || Item.getBase().Layable) {
                        FurniCollisionMap[Tile.X][Tile.Y] = 2;
                    }
                }
            }
        }
    }

    public void ReGenerateCollisionMap() {
        this.Room.getPathfinder().ApplyCollisionMap(
                GenerateCollisionMap(),
                GenerateFurniHeightMap());

        this.Room.getGhostPathfinder().ApplyCollisionMap(
                GenerateCollisionMap(),
                GenerateFurniHeightMap());

        GenerateFurniCollisionMap();
    }

    public byte[][] GenerateCollisionMap() {
        byte[][] CollisionMap = new byte[this.Room.getModel().MapSizeX][this.Room.getModel().MapSizeY];

        for (int x = 0; x < this.Room.getModel().MapSizeX; x++) //Loopception courtesy of Cobe & Cecer
        {
            for (int y = 0; y < this.Room.getModel().MapSizeY; y++) {
                if (FurniCollisionMap[x][y] == 0) //Tile is closed becuase furni is there..
                {
                    CollisionMap[x][y] = FurniCollisionMap[x][y];
                } else if (this.Room.getModel().Squares[x][y] == SquareState.WALKABLE) //By model, it's walkable
                {
                    if (UserCollisionMap[x][y]) {
                        CollisionMap[x][y] = 0;
                    } else {
                        CollisionMap[x][y] = 1;
                    }
                } else //It's not a valid tile
                {

                    CollisionMap[x][y] = 0;
                }
            }
        }

        return CollisionMap;
    }

    public float[][] GenerateFurniHeightMap() {
        float[][] FurniHeightMap = new float[this.Room.getModel().MapSizeX][this.Room.getModel().MapSizeY];

        for (int x = 0; x < this.Room.getModel().MapSizeX; x++) //Loopception courtesy of Cobe & Cecer
        {
            for (int y = 0; y < this.Room.getModel().MapSizeY; y++) {
                if (FurniCollisionMap[x][y] == 0) {
                    FurniHeightMap[x][y] = (float) this.Room.getModel().SquareHeight[x][y];
                } else {
                    try {
                        for (FloorItem Item : this.Room.getFloors().values()) {

                            FurniHeightMap[x][y] = Item.Height;
                        }
                    } catch (Exception ex) {
                        FurniHeightMap[x][y] = (float) this.Room.getModel().SquareHeight[x][y];
                    }
                }
            }
        }

        return FurniHeightMap;
    }

    public FloorItem GetItemAtPosition(Position Pos) {
        FloorItem Return = null;
        Float LowestHeight = (float) 0.0;
        boolean HeightNotSet = true;

        for (FloorItem Item : this.Room.getItemsByPosition(Pos).values()) {
            if (HeightNotSet) {
                LowestHeight = Item.Height;
                HeightNotSet = false;
            }

            if (Item.Height > LowestHeight) //Ensure that we get the very bottom? I've dun confused myself..
            {
                continue;
            }

            if (Item.getBase().Width == 1 && Item.getBase().Length == 1) {
                Return = Item;
            } else {
                for (AffectedTile Tile : AffectedTile.GetAffectedTiles(Item.getBase().Length, Item.getBase().Width, Item.X, Item.Y, Item.Rotation)) {
                    Return = Item;
                }
            }
        }

        return Return;
    }

    public boolean realTileOpen(Position Position) {
        for (FloorItem Item : this.Room.getItemsByPosition(Position).values()) {
            if (!Item.getBase().Walkable) {
                return false;
            }
        }

        return true;
    }
}
