/// <reference path="Classes/Things/Person.ts" />
/// <reference path="Classes/Things/MapNote.ts" />
/// <reference path="Classes/Things/Humanoid/Humanoid.ts" />

/// <reference path="Classes/Rulebook.ts" />
/// <reference path="Classes/Rule.ts" />
/// <reference path="Classes/Save/StoredVariable.ts" />
/// <reference path="PlayBegins.ts" />
module WorldState {
    var worldTurn : number = 0;
    var playerTurn : number = 0;
    export var player : Humanoid = new Humanoid({isMale : false});

    player.description = Humanoid.getPlayerDescription;

    var rememberedRooms = new StoredVariable<Array<string>>({
        id : "Remembered Rooms",
        value : []
    });

    var rememberedFodder : Array<Room> = [];

    let rememberedRoomsForIntelligence = 2;
    let rememberedRoomsForSurvival = 1;

    export var RememberingRoomRulebook : Rulebook<Room> = new Rulebook("Remembering Room something");

    export function isTurnWaiting () {
        return worldTurn < playerTurn;
    }

    export function incrementWorldTurn () {
        worldTurn++;
    }

    export function incrementPlayerTurn () {
        playerTurn++;
    }

    export function getCurrentTurn () {
        return playerTurn;
    }

    export function setCurrentTurn (turn : number) {
        playerTurn = turn;
        worldTurn = turn;
    }

    export let RememberingRoomInList = RememberingRoomRulebook.createAndAddRule({
        name : "Is room listed in remembered rooms?",
        firstPriority : Rule.PRIORITY_LOWEST,
        priority : Rule.PRIORITY_LOW,
        code : runner => {
            if (rememberedRooms.value.indexOf(runner.noun.getName()) != -1 || rememberedFodder.indexOf(runner.noun) != -1) {
                return true;
            }
        }
    });

    export let RememberingRoomInMap = RememberingRoomRulebook.createAndAddRule({
        name : "Is room shown on a map?",
        firstPriority : Rule.PRIORITY_LOWEST,
        priority : Rule.PRIORITY_LOWEST,
        code : runner => {
            let maps = <Array<MapNote>> Thing.CarryRelation.getRightType(player, MapNote);
            for (let i = 0; i < maps.length; i++) {
                if (maps[i].contains(runner.noun)) {
                    return true;
                }
            }
        }
    });

    export async function isRoomRemembered (room : Room) : Promise<boolean> {
        let result = await RememberingRoomRulebook.execute({noun : room});
        return result == true; // can return "undefined"
    }

    export function getRememberedRooms () {
        return rememberedRooms.value;
    }

    export function getRememberedRoomsAsRooms () : Array<Room> {
        let rooms = [];
        rememberedRooms.value.forEach(roomName => {
            let room = Room.getRoom(roomName);
            if (room != undefined) rooms.push(room);
        });

        return rooms;
    }

    export function getMaximumRememberedRooms () {
        let intRooms = player.getStat(Attributes.Intelligence) * rememberedRoomsForIntelligence;
        let skillRooms = player.getSkill(Skills.Survival) * rememberedRoomsForSurvival;
        return intRooms + skillRooms;
    }

    export function truncateRooms () {
        while (rememberedRooms.value.length > getMaximumRememberedRooms()){
            rememberedRooms.value.pop();
        }
    }

    export function rememberRoom (...rooms : Array<Room>) {
        rooms.forEach((value) => {
            if (value instanceof Room) {
                if (value.fodder) {
                    if (rememberedFodder.indexOf(value) == -1) {
                        rememberedFodder.push(value);
                    }
                } else {
                    let idx = rememberedRooms.value.indexOf(value.getName());
                    if (idx != -1) {
                        rememberedRooms.value.splice(idx, 1);
                    }
                    rememberedRooms.value.unshift(value.getName());
                }
            }
        });
        truncateRooms();
    }

    export function saveState () {
        let things = {
            carried: [],
            worn: [],
            wielded: []
        };

        return {
            Things : things
        };
    }

    export let CorrectRememberedRoomsRule = PlayBegins.rulebook.createAndAddRule({
        name : "Correct remembered rooms",
        firstPriority : Rule.PRIORITY_LOWEST,
        priority : Rule.PRIORITY_MEDIUM,
        code : () => {
            let allRooms = rememberedRooms.value;
            let currentRoom = WorldState.player.getRoom();
            if (allRooms.length == 0) {
                rememberedRooms.value = [currentRoom.getName()];
                return;
            }
            let newRooms = [];

            function recursivelyAddRooms (room : Room) {
                if (room instanceof RoomRandom) {
                    if (room.fodder) {
                        rememberedFodder.push(room);
                        room.connections.forEach((newRoom) => {
                            recursivelyAddRooms(newRoom);
                        });
                    } else if (allRooms.indexOf(room.getName()) != -1 && newRooms.indexOf(room.getName()) == -1) {
                        newRooms.push(room.getName());
                        room.connections.forEach((newRoom) => {
                            recursivelyAddRooms(newRoom);
                        });
                    }
                }
            }

            recursivelyAddRooms(currentRoom);
            rememberedRooms.value = newRooms;
        }
    })
}