var lvName = "Courtyard";

function buildMainRooms()
{
    trace("Starting Desolated Courtyard.");

    trace("Generating main rooms.");

    Struct.createSpecificRoom("aCEntrance").setName("start")
        .chain(Struct.createSpecificRoom("aCMountainLeft").setName("cliffLeft"))
        .chain(Struct.createSpecificRoom("aCMountainRight").setName("cliffRight"))
        .chain(Struct.createSpecificExit("decayingCells", "aCMidExit"))
        .chain(Struct.createSpecificExit("T_Roof", "aCEndExit").setName("mainExit"))
        .chain(Struct.createSpecificRoom("aCTeleportGate"))
        .chain(Struct.createSpecificExit("T_PrisonDepths", "aCEndRoom"));

    // Struct.createExit("decayingCells")
    //     .branchBetween("cliffLeft", "cliffRight")
    //     .setName("decayingCells");
    // Struct.createRoomWithType("WallJumpGate")
    //     .addBefore("decayingCells");

    if(Random.isBelow(0.6)) {
        Struct.createShop(MerchantType.Weapons)
            .setName("shop1")
            .branchBetween("start", "cliffLeft");
    }
    else {
        Struct.createShop(MerchantType.Weapons)
            .setName("shop1")
            .branchBetween("cliffRight", "mainExit");
    }
    Struct.createRoomWithType("BreakableGroundGate")
        .addBefore("shop1");

    if(Random.isBelow(0.4)) {
        Struct.createShop(MerchantType.Actives)
            .setName("shop2")
            .branchBetween("start", "cliffLeft");
    }
    else {
        Struct.createShop(MerchantType.Actives)
            .setName("shop2")
            .branchBetween("cliffRight", "mainExit");
    }
    Struct.createRoomWithType("TeleportGate")
        .addBefore("shop2");

    if(Random.isBelow(0.6)) {
        Struct.createRoomWithType("Treasure")
            .branchBetween("start", "cliffLeft");
    }
    if(Random.isBelow(0.4)) {
        Struct.createRoomWithType("Treasure")
            .branchBetween("cliffRight", "mainExit");
    }

    Struct.createSpecificRoom("aCMountainTeleport1")
        .addBetween("cliffLeft", "cliffRight");

    trace("Generating fixed rooms.");

    Struct.createSpecificRoom("aCLadderGate")
        .addBetween("cliffRight", "mainExit", 2);
    Struct.createSpecificRoom("aCMultiTreasure")
        .addBetween("start", "cliffLeft");
    Struct.createRoomWithTypeFromGroup("DualTreasure", "alaahCourtyardCommon")
        .addFlag(RoomFlag.Outside)
        .addBetween("cliffRight", "mainExit");
    Struct.createRoomWithTypeFromGroup("HealPotion", "alaahCourtyardCommon")
        .addFlag(RoomFlag.Outside)
        .addBetween("start", "cliffLeft");
    Struct.createRoomWithTypeFromGroup("CursedTreasure", "alaahCourtyardCommon")
        .addFlag(RoomFlag.Outside)
        .addBetween("start", "cliffLeft");
    Struct.createRoomWithTypeFromGroup("BuyableTreasure", "alaahCourtyardCommon")
        .addFlag(RoomFlag.Outside)
        .addBetween("cliffRight", "mainExit");
    Struct.createSpecificRoom("aCEvilRoom")
        .addBetween("start", "cliffLeft", 1);
    Struct.createSpecificRoom("aCEvilRoomEvil")
        .addBetween("start", "cliffLeft", 1);

    var exit = Struct.getRoomByName("mainExit");
    var undergrounds = Struct.allRooms.filter(function(_room)
        return _room != exit && _room.isMainLevel() && !_room.isParentOf(exit) && !_room.isChildOf(exit)
    );
    var outRooms = Struct.allRooms.filter(function(_room)
        return _room.isMainLevel() && _room.parent != null && _room.isParentOf(exit) && _room != exit &&
              (_room.isParentOf(Struct.getRoomByName("cliffLeft")) || _room.isChildOf(Struct.getRoomByName("cliffRight")))
    );

    trace("Generating celldoors.");

    Struct.createRunicZDoor(Struct.createRoomWithType("Treasure"), 1, undergrounds);
    Struct.createRunicZDoor(Struct.createRoomWithTypeFromGroup("Special", "alaahCourtyardKey"), 2, undergrounds);
    Struct.createRunicZDoor(Struct.createRoomWithType("Treasure"), 3, undergrounds);
    Struct.createRunicZDoor(Struct.createRoomWithType("CursedTreasure"), 4, undergrounds);
    Struct.createRunicZDoor(Struct.createRoomWithTypeFromGroup("Special", "alaahCourtyardKey"), 4, undergrounds);
    Struct.createRunicZDoor(Struct.createSpecificRoom("GenericZDoor_LR"), 4, undergrounds);

    trace("Generating more fixed rooms.");

    Struct.createSpecificRoom("aCSecretWallJump")
        .addBefore(Random.arraySplice(outRooms).getName());
    Struct.createSpecificRoom("aCSecretStomp")
        .addBefore(Random.arraySplice(outRooms).getName());
    Struct.createSpecificRoom("aCSecretHouse")
        .addBefore(Random.arraySplice(outRooms).getName());
    Struct.createSpecificRoom("aCSecretFlower")
        .addBefore(Random.arraySplice(outRooms).getName());
    Struct.createSpecificRoom("aCIsland")
        .addBefore(Random.arraySplice(outRooms).getName())
        .addZChild(Struct.createSpecificRoom("aCIslandInt"))
        .setName("desolate");
}

function buildSecondaryRooms()
{
    var exit = Struct.getRoomByName("mainExit");
    var mains = Struct.allRooms.filter(function(_room)
        return _room.isMainLevel() && _room.parent != null && _room.isParentOf(exit) && _room != exit && _room.childrenCount > 1 &&
              (_room.isParentOf(Struct.getRoomByName("cliffLeft")) || _room.isChildOf(Struct.getRoomByName("cliffRight")))
    );

    trace("Generating combat rooms.");
    var mainsCopy = mains.copy();
    for(i in 0...4) {
        if(mainsCopy.length == 0) {
            mainsCopy = mains.copy();
        }
        Struct.createRoomWithTypeFromGroup("Combat", "alaahCourtyardCommon")
            .addFlag(RoomFlag.Outside)
            .addBefore(Random.arraySplice(mainsCopy).getName());
    }

    var combatRooms = Struct.allRooms.filter(function(_room)
        return _room.type == "Combat" && _room.hasFlag(RoomFlag.Outside) &&
              (_room.isParentOf(Struct.getRoomByName("cliffLeft")) || _room.isChildOf(Struct.getRoomByName("cliffRight")))
    );
    var undergrounds = Struct.allRooms.filter(function(_room)
        return _room != exit && _room.isMainLevel() && !_room.isParentOf(exit) && !_room.isChildOf(exit)
    );

    trace("Generating trap rooms.");
    for(i in 0...Random.irange(2, 3)){
        Struct.createRoomWithTypeFromGroup("Trap_1", "alaahCourtyardCommon")
            .addFlag(RoomFlag.Outside)
            .addBefore(Random.arraySplice(combatRooms).getName());
    }
    Struct.createRoomWithTypeFromGroup("Combat", "alaahCourtyardKey")
        .addFlag(RoomFlag.Outside)
        .addBefore(Random.arraySplice(combatRooms).getName());
    for(i in 0...Random.irange(3, 5)) {
        Struct.createRoomWithTypeFromGroup("Trap_1", "CommonTraps")
            .addBefore(Random.arrayPick(undergrounds).getName());
    }
}

function addTeleports()
{
    var exit = Struct.getRoomByName("mainExit");
    var secondExit = Struct.getRoomByName("mainExit");
    var rooms = Struct.allRooms.filter(function(_room)
        return _room.isMainLevel()
    );
    var mains = Struct.allRooms.filter(function(_room)
        return _room.isMainLevel() && _room.parent != null && _room.isParentOf(exit) &&
              (_room.isParentOf(Struct.getRoomByName("cliffLeft")) || _room.isChildOf(Struct.getRoomByName("cliffRight")))
    );

    trace("Generating TPs.");
    //Turn crosses into teleports
    for(room in rooms) {
        if(room.type == "Corridor" && room.isParentOf(exit) && room.childrenCount > 1 && room.calcTypeDistance("Teleport", true) > 1) {
            room.setType("Teleport");
        }
    }
    // Meta gates teleport
    for(room in rooms.filter(function(_room) return !_room.hasFlag(RoomFlag.Outside) && (_room.type == "WallJumpGate" || _room.type == "LadderGate" || _room.type == "TeleportGate" || _room.type == "BreakableGroundGate")) ){
        if(room.calcTypeDistance("Teleport", false) > 1 ){
            Struct.createTeleportBefore(room);
        }
    }

    // more common teleports in the overworld
    for(room in rooms.filter(function(_room) return _room.hasFlag(RoomFlag.Outside))) {
        if(room.calcTypeDistance("Teleport", true) > 3){
            trace("Generating a tp before " + room.getName());
            Struct.createRoomWithTypeFromGroup("Teleport", "alaahCourtyardCommon").addFlag(RoomFlag.Outside).addBefore(room.getName());
        }
    }

    // Dead Ends
    for(room in rooms) {
        if(room.childrenCount == 0 && room != secondExit && room.calcTypeDistance("Teleport", true) > 1){
            Struct.createRoomWithType("Teleport").addBefore(room.getName());
        }
    }

    // final tp
    if(exit.parent.type != "Teleport") {
        Struct.createRoomWithTypeFromGroup("Teleport", "alaahCourtyardCommon").addFlag(RoomFlag.Outside).addBefore(exit.getName());
    }

    var nodes = rooms.filter(function(_room)
        return _room.isMainLevel() && _room.hasFlag(RoomFlag.Outside) &&
              (_room.isParentOf(Struct.getRoomByName("cliffLeft")) || _room.isChildOf(Struct.getRoomByName("cliffRight")))
    );
    nodes.sort(function(a, b) return compare(a.spawnDistance, b.spawnDistance));
    for(n in nodes) {
        if(n.spawnDistance > 1 && n.prent != null && n.calcTypeDistance("Teleport", true) > 2) {
            trace("Generating a tp before " + n.getName());
            if(n.hasFlag(RoomFlag.Outside)) {
                Struct.createRoomWithTypeFromGroup("Teleport", "alaahCourtyardCommon").addFlag(RoomFlag.Outside).addBefore(n.getName());
            }
            else {
                Struct.createRoomWithType("Teleport").addBefore(n.getName());
            }
        }
    }
}

function buildTimedDoors()
{
    var cliff = Struct.getRoomByName("cliffRight");

    // DecisionHelper doesn't appear in the docs
    // Refer to this:
    // https://github.com/deepnight/ld40-catsAreAssholes/blob/master/src/DecisionHelper.hx
    var dh = new DecisionHelper(Struct.allRooms);

    // Remove:
    // * not main level (zDoors)
    // although a zDoor timedoor would be cool
    // * not outside (underground)
    // * before the vine cliff
    dh.remove(function(_room) return !_room.isMainLevel() || !_room.hasFlag(RoomFlag.Outside) || _room.isParentOf(cliff) || _room.getName() == "cliffRight");

    /// RoomNode::spawnDistance is nowhere to be found
    // So I have honestly no fucking idea what it does
    // But the previous line does the job well enough for the thing to work well
    dh.score(function(_room) return _room.spawnDistance <= 1 ? -4 : _room.spawnDistance >= 3 ? -10 : 0);

    // Randomly add +1 score to some rooms
    dh.score(function(_room) return Random.irange(0, 1));

    trace("The Timedoor is " + dh.getBest().getName() + ".");

    Struct.createTimedBranchBefore(dh.getBest());
}

function finalize()
{
    var exit = Struct.getRoomByName("mainExit");

    trace("Finalizing.");
    for(room in Struct.allRooms){
        if((room.type == "Corridor" || room.type == "Teleport") && room.isParentOf(exit)){
            room.setGroup("alaahCourtyardCommon");
            room.addFlag(RoomFlag.Outside);
        }
    }

    // Add vertical elevator spacers
    /* for(room in Struct.allRooms.copy()){
        if(room != exit && room.isMainLevel() && ! room.isParentOf(exit) && room.parent != null && room.parent.isParentOf(exit)) {
            Struct.createRoomWithTypeFromGroup("Corridor", "CourtyardVerticalCorridor").addBefore(room.getName());
        }
    }

    // Switch useless corridors to Combat corridors
    for(room in Struct.allRooms){
        if( room.type == "Corridor" && room.hasFlag(RoomFlag.Outside) && room.childrenCount > 1 ){
            room.setType("Combat");
            room.setGroup("CourtyardCombatCorridor");
        }
    }*/

    for(room in Struct.allRooms) {
        if(room.type == "TimedDoor" || room.type == "TimedTreasure"){
            room.setGroup("alaahCourtyardCommon");
        }
    }

    Struct.createSpecificRoom("aCMountainPrelude")
        .addBefore("cliffLeft");
        for(i in 0...2) {
            Struct.createRoomWithTypeFromGroup("Combat", "alaahCourtyardMountain")
                .addFlag(RoomFlag.Outside)
                .addBetween("cliffLeft", "cliffRight");
        }

    // Horizontal overworld
    for(room in Struct.allRooms) {
        if(room.parent != null && room.hasFlag(RoomFlag.Outside)) {
            room.setConstraint(LinkConstraint.HorizontalSameDirOnly);
            room.setChildPriority(1);
        }
    }

     Struct.getRoomByName("start").chain(Struct.createSpecificExit("BoatDock", "aCStartExit"));//.setConstraint(LinkConstraint.VerticalSameDirOnly));

    trace("Done.");
}
function buildMobRoster(_mobList)
{
    trace("Applying mob roster.");
    addMobRosterFrom("PrisonCourtyard", _mobList);
}

function setLevelProps(_levelProps)
{
    trace("Applying props.");
    _levelProps.timedDoor = 5.5;
    _levelProps.timedGoldMul = 1.5;
    _levelProps.timedScrolls = 1;
    _levelProps.wind = -3.0;
    _levelProps.musicIntro = "music/courtyard_intro.ogg";
    _levelProps.musicLoop = "music/courtyard_loop.ogg";

    _levelProps.doorColor = 144411;
    _levelProps.zDoorColor = 144411;
    _levelProps.loadingColor = 1055263;
    _levelProps.loadingDescColor = 6652612;
}

function setLevelInfo(_levelInfo)
{
    trace("Applying level info.");
    _levelInfo.baseLootLevel = 2;
    _levelInfo.baseMobTier = 2;
    _levelInfo.biome = "PrisonCourtyard2";
    _levelInfo.cellBonus = 0.0;
    _levelInfo.doubleUps = 0;
    _levelInfo.eliteRoomChance = 0.0;
    _levelInfo.eliteWanderChance = 1.0;
    _levelInfo.extraMobTier = 0;
    _levelInfo.flags = 13;
    _levelInfo.goldBonus = 0;
    _levelInfo.mobDensity = 3.0;
    _levelInfo.name = "Desolated Courtyard";
    _levelInfo.tripleUps = 2;
}
