const AUTHORIZED_ALLIANCES = {
    "s58-fr": ["NAZGUL"]
};

const MOVING_FACTOR = {
    "s56-fr": 3,
    "s57-fr": 4,
    "s58-fr": 1.98,
}

const BUILDINGS = {
    "main": "Château",
    "stone": "Carrière",
    "wood": "Scierie",
    "iron": "Mine de minerai",
    "storage": "Entrepôt",
    "hide": "Cachette",
    "farm": "Moulin",
    "barracks": "Caserne",
    "wall": "Remparts",
    "stable": "Élevage d'ânes",
    "snob": "Résidence",
    "smith": "Orfèvrerie",
    "statue": "Mémorial",
}

const UNITS = {
    "farmer": "Milice de paysans",
    "sword": "Templier",
    "spear": "Écuyer",
    "axe": "Sauvage",
    "bow": "Grand Arc",
    "spy": "Éclaireur",
    "light": "Croisé",
    "heavy": "Chevalier Noir",
    "ram": "Bélier",
    "kata": "Trébuchet",
    "snob": "Comte",
}

function num(s) {
	return parseInt(s.replace(".", ""));
}

function str(n) {
	if (n === 0) {
		return "0";
	}
	let s = "";
	while (n > 0) {
		if (s !== "") {
			s = "." + s;
		}
		let r = n % 1000;
		s = r.toString().padStart(3, "0") + s;
		n = ~~(n/1000);
	}
	return s.replace(/^0+/, "");
}

function createCustomElement(tag, attrs, text, style) {
    let elt = document.createElement(tag);
    if (attrs) {
        for (let [key, value] of Object.entries(attrs)) {
            if (value !== null) {
                elt.setAttribute(key, value.toString());
            }
        }
    }
    if (text) {
        elt.textContent = text.toString();
    }
    if (style) {
        for (let [key, value] of Object.entries(style)) {
            elt.style[key] = value.toString();
        }
    }
    return elt;
}

function createCustomInput(type, name, value, attrs, style) {
    let mergedAttrs = {};
    if (attrs) {
        mergedAttrs = attrs;
    }
    mergedAttrs["type"] = type;
    if (name) {
        mergedAttrs["name"] = name;
    }
    if (value) {
        mergedAttrs["value"] = value;
    }
    return createCustomElement("input", mergedAttrs, null, style);
}

function createKeyValueRow(key, value) {
    let row = createCustomElement("tr");
    let keyCell = createCustomElement("td", null, key);
    let valueCell = createCustomElement("td", null, value);
    row.appendChild(keyCell);
    row.appendChild(valueCell);
    return row;
}

function searchPoint(text) {
    let index = text.search(/\d{3}\|\d{3}/);
    let point = text.slice(index, index + 7).split("|");
    return {x: point[0], y: point[1]}
}

function selectVillage(selectRef, inputXRef, inputYRef) {
    let select = document.getElementById(selectRef);
    let inputX = document.getElementById(inputXRef);
    let inputY = document.getElementById(inputYRef);
    if (select.selectedIndex === 0) {
        inputX.value = "";
        inputY.value = "";
    } else {
        let xy = select.value.split("|");
        inputX.value = xy[0];
        inputY.value = xy[1];
    }
}

function storeOrderToken(ownVillages, targetVillage) {
    let orderToken = sessionStorage.getItem("orderToken");
    if (orderToken !== null) {
        return;
    }

    let breakLoop = false;
    for (let villageId in ownVillages) {
        if (breakLoop === true) {
            return;
        }
        let xhrOrder = new XMLHttpRequest();
        xhrOrder.addEventListener("readystatechange", function () {
            if (xhrOrder.readyState === xhrOrder.DONE) {
                let parser = new DOMParser();
                let doc = parser.parseFromString(xhrOrder.responseText, "text/html");
                let quantityDivs = doc.getElementsByClassName("quantity");
                let unit = null;
                for (let i = 0; i < quantityDivs.length; i ++) {
                    let quantityInput = quantityDivs[i].getElementsByTagName("input")[0];
                    let quantityClick = quantityDivs[i].getElementsByClassName("click")[0];
                    if (quantityClick.textContent !== "(0)") {
                        unit = quantityInput.getAttribute("name");
                        break;
                    }
                }
                if (unit === null) {
                    return;
                }

                let xhrSend = new XMLHttpRequest();
                let formData = new FormData();
                formData.set(unit, "1");
                formData.set("send_x", targetVillage.x);
                formData.set("send_y", targetVillage.y);
                formData.set("support", "Envoyer du renfort");
                let formParams = new URLSearchParams(formData);
                xhrSend.addEventListener("readystatechange", function () {
                    if (xhrSend.readyState === xhrSend.DONE) {
                        let parser = new DOMParser();
                        let doc = parser.parseFromString(xhrSend.responseText, "text/html");
                        let form = doc.getElementsByTagName("form")[0];
                        let action = form.getAttribute("action");
                        let orderToken = action.replace(/^.*p=([a-z0-9]+).*$/, "$1");
                        sessionStorage.setItem("orderToken", orderToken);
                        breakLoop = true;
                    }
                });
                xhrSend.open("POST", "/?village=" + villageId + "&s=build_barracks&m=command&sub=send");
                xhrSend.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
                xhrSend.send(formParams.toString());
            }
        });
        xhrOrder.open("GET", "/?village=" + villageId + "&s=build_barracks");
        xhrOrder.send();
    }
}

function storeTargetVillage(ownVillages) {
    let targetVillage = sessionStorage.getItem("targetVillage");
    if (targetVillage !== null) {
        storeOrderToken(ownVillages, JSON.parse(targetVillage));
        return;
    }

    let xhr = new XMLHttpRequest();
    targetVillage = {};
    xhr.addEventListener("readystatechange", function () {
        if (xhr.readyState === xhr.DONE) {
            let parser = new DOMParser();
            let doc = parser.parseFromString(xhr.responseText, "text/html");
            let cells = doc.getElementsByClassName("occupied range");
            for (let i = 0; i < cells.length; i ++) {
                let links = cells[i].getElementsByTagName("a");
                if (links.length === 0) {
                    continue;
                }
                let villageId = links[0].getAttribute("href").replace(/^.*id=(\d{4}).*$/, "$1");
                if (villageId in ownVillages) {
                    continue;
                }
                let villageXY = links[0].getAttribute("onmouseover").replace(/^.*(\d{3}\|\d{3}).*$/, "$1").split("|");
                targetVillage = {x: parseInt(villageXY[0]), y: parseInt(villageXY[1])};
                sessionStorage.setItem("targetVillage", JSON.stringify(targetVillage));
                storeOrderToken(ownVillages, targetVillage);
                break;
            }
        }
    });
    xhr.open("GET", "/?s=map");
    xhr.send();
}

function storeOwnVillages() {
    let ownVillages = sessionStorage.getItem("ownVillages");
    if (ownVillages !== null) {
        storeTargetVillage(JSON.parse(ownVillages));
        return;
    }

    let xhr = new XMLHttpRequest();
    xhr.addEventListener("readystatechange", function () {
        if (xhr.readyState === xhr.DONE) {
            let parser = new DOMParser();
            let doc = parser.parseFromString(xhr.responseText, "text/html");
            let mainContentPane = doc.getElementsByClassName("contentpane")[1];
            let table = mainContentPane.getElementsByClassName("borderlist")[1];
            let rows = table.getElementsByTagName("tr");
            let ownVillages = {};
            for (let i = 1; i < rows.length; i ++) {
                let cells = rows[i].getElementsByTagName("td");
                let link = cells[0].getElementsByTagName("a")[0];
                let villageId = link.getAttribute("href").replace(/^.*id=(\d{4}).*$/, "$1");
                let villageXY = cells[1].textContent.split("|");
                ownVillages[villageId] = {x: parseInt(villageXY[0]), y: parseInt(villageXY[1]), name: link.textContent};
            }
            sessionStorage.setItem("ownVillages", JSON.stringify(ownVillages));
            storeTargetVillage(ownVillages);
        }
    });
    xhr.open("GET", "/?s=info_player");
    xhr.send();
}

function shortcutElementReplace(elt, img, text) {
    // If more than one hyperlink element found,
    // then keep the last one but with href of the first one.
    let aElements = elt.getElementsByTagName("a");
    let imgElements = elt.getElementsByTagName("img");
    if (aElements.length > 1 || imgElements.length > 0) {
        aElements[aElements.length - 1].classList.add("has_notif");
        aElements[aElements.length - 1].setAttribute("href", aElements[0].getAttribute("href"));
        for (let i = imgElements.length - 1; i >= 0; i--) {
            imgElements[i].remove();
        }
        for (let i = aElements.length - 2; i >= 0; i--) {
            aElements[i].remove();
        }
    }

    let spanImageElement = createCustomElement("span", {"class": "shortcut_element_image"});
    let imgElement = createCustomElement("img", {"src": chrome.runtime.getURL("images/" + img + ".svg")});
    spanImageElement.appendChild(imgElement);

    aElements[0].textContent = "";
    aElements[0].appendChild(spanImageElement);

    if (text) {
        let spanDescElement = createCustomElement("span", {"class": "shortcut_element_desc"}, text);
        aElements[0].appendChild(spanDescElement);
    }
}

function customizeNavbar(layCastleElement) {
    /* Improve navbar icons */
    let shortcutElements = layCastleElement.getElementsByClassName("shortcut_element");
    shortcutElementReplace(shortcutElements[0], "ranking", shortcutElements[0].textContent.replace(/[^0-9]/g, ""));
    shortcutElementReplace(shortcutElements[1], "ally", "");
    shortcutElementReplace(shortcutElements[2], "profile", "");
    shortcutElementReplace(shortcutElements[3], "premium", "");
    shortcutElementReplace(shortcutElements[4], "messages", "");
    shortcutElementReplace(shortcutElements[5], "tools", "");
    shortcutElementReplace(shortcutElements[6], "favorites", "");

    /* Center navbar */
    let shortcutContainers = layCastleElement.getElementsByClassName("shortcut_container");
    shortcutContainers[0].classList.add("shortcut_container_left");
    shortcutContainers[2].classList.add("shortcut_container_right");
}

function countUpMs(tomorrow, afterTomorrow, movingDuration) {
    let arrivalDate = new Date(new Date().getTime() + movingDuration * 1000);
    let prefix = "";
    if (arrivalDate >= afterTomorrow) {
        prefix = "le " + arrivalDate.getDate() + "." + arrivalDate.getMonth() + " ";
    } else if (arrivalDate > tomorrow) {
        prefix = "demain ";
    }
    document.getElementById("countup-time-ms").textContent = prefix
        + "à "
        + arrivalDate.getHours().toString().padStart(2, "0")
        + ":"
        + arrivalDate.getMinutes().toString().padStart(2, "0")
        + ":"
        + arrivalDate.getSeconds().toString().padStart(2, "0")
        + ":"
        + Math.floor(arrivalDate.getMilliseconds() / 100);
}

function convertTimestamp(timestamp) {
    let now = new Date();
    let tomorrow = new Date(now.getTime() + 24*3600*1000);
    tomorrow.setHours(0);
    tomorrow.setMinutes(0);
    tomorrow.setSeconds(0);
    tomorrow.setMilliseconds(0);
    let afterTomorrow = new Date(tomorrow.getTime() + 24*3600*1000);
    let date = new Date(timestamp);

    let prefix = "";
    if (date >= afterTomorrow) {
        prefix = "le " + date.getDate() + "." + date.getMonth() + " ";
    } else if (date > tomorrow) {
        prefix = "demain ";
    }
    return prefix
        + "à "
        + date.getHours().toString().padStart(2, "0")
        + ":"
        + date.getMinutes().toString().padStart(2, "0")
        + ":"
        + date.getSeconds().toString().padStart(2, "0")
        + "."
        + Math.floor(date.getMilliseconds() / 100);
}

function convertDurationUntil(timestamp) {
    let now = new Date();
    let duration = timestamp - now.getTime();
    let hours = Math.floor(duration / (3600*1000));
    duration -= hours * 3600 * 1000;
    let minutes = Math.floor(duration / (60*1000));
    duration -= minutes * 60 * 1000;
    let seconds = Math.floor(duration / 1000);
    duration -= seconds * 1000;
    let tenth = Math.floor(duration / 100);
    return hours.toString().padStart(2, "0") + ":"
        + minutes.toString().padStart(2, "0") + ":"
        + seconds.toString().padStart(2, "0") + "."
        + tenth.toString();
}

function removeAdsBanner() {
    /* Remove iframe banner */
    document.getElementById("banner_skyscraper").remove();
}

function showPlayersId() {
    /* Add a column with player id */
    let mainContentPane = document.getElementsByClassName("contentpane")[1];
    let borderListTable = mainContentPane.getElementsByClassName("borderlist")[0];
    let playerRows = borderListTable.getElementsByTagName("tr");

    let headerCells = playerRows[0].getElementsByTagName("th");
    let nameCellIndex = -1;
    for (let i = 0; i < headerCells.length; i ++) {
        if (headerCells[i].textContent === "Nom") {
            nameCellIndex = i;
            break;
        }
    }
    if (nameCellIndex === -1) {
        /* Name column not found, so return */
        console.log("Column 'Nom' not found, cannot show player ids :(");
        return;
    }

    let idHeaderCell = createCustomElement("th", {"class": headerCells[0].getAttribute("class")}, "Id");
    for (let i = 1; i < playerRows.length; i ++) {
        let playerCells = playerRows[i].getElementsByTagName("td");
        let playerProfileLink = playerCells[nameCellIndex].getElementsByTagName("a")[0].getAttribute("href");
        let idValue = playerProfileLink.replace(/^.*id=(\d+)$/, "$1");
        let idCell = createCustomElement("td", {"class": playerCells[0].getAttribute("class")}, idValue);
        playerRows[i].insertBefore(idCell, playerCells[nameCellIndex]);
    }
    playerRows[0].insertBefore(idHeaderCell, headerCells[nameCellIndex]);
}

function showPlayerUnitPointsAndId() {
    let mainContentPane = document.getElementsByClassName("contentpane")[1];
    let borderLists = mainContentPane.getElementsByClassName("borderlist");

    let playerPropertiesTable = borderLists[0];
    let playerPropertiesTbody = playerPropertiesTable.getElementsByTagName("tbody")[0];
    let playerPropertiesRows = playerPropertiesTable.getElementsByTagName("tr");
    let totalPoints = num(playerPropertiesRows[2].getElementsByTagName("td")[1].textContent);
    let villagesCount = num(playerPropertiesRows[4].getElementsByTagName("td")[1].textContent);

    let villagesTable = borderLists[1];
    let villagesRows = villagesTable.getElementsByTagName("tr");
    let villagesPoints = 0;
    for (let i = 1; i < villagesRows.length; i += 1) {
        villagesPoints += num(villagesRows[i].getElementsByTagName("td")[2].textContent);
    }
    let villagesBonus = 2250 * Math.max(0, villagesCount - 1);

    let armyPoints = totalPoints - villagesPoints - villagesBonus;
    let armyPercent = "-";
    if (villagesCount > 0) {
        armyPercent = (Math.round(armyPoints / villagesCount) / 100).toString() + " %";
    }

    let moduleMenu = mainContentPane.getElementsByTagName("table")[0];
    let moduleHyperlink = moduleMenu.getElementsByTagName("a")[0];
    let playerId = moduleHyperlink.getAttribute("href").replace(/^.*[?&]id=(\d+).*$/, "$1");

    playerPropertiesTbody.appendChild(createKeyValueRow("Points troupes:", str(armyPoints)));
    playerPropertiesTbody.appendChild(createKeyValueRow("% points troupes:", armyPercent));
    playerPropertiesTbody.insertBefore(createKeyValueRow("Id:", playerId), playerPropertiesRows[2]);
}

function showAutoPlanerMenu(village, module) {
    let mainContentPane = document.getElementsByClassName("contentpane")[1];
    let navTable = mainContentPane.getElementsByTagName("table")[0];
    let navRow = navTable.getElementsByTagName("tr")[0];
    let navCells = navRow.getElementsByTagName("td");
    let separatorCell = createCustomElement("td");
    let separatorImg = createCustomElement("img");
    separatorCell.appendChild(separatorImg);
    let autonomousCell = createCustomElement("td");
    let autonomousLink = createCustomElement(
        "a", {"href": "/?village=" + village + "&s=tools&m=auto_planer"}, "Planificateur autonome d'attaques"
    );
    let rightImg = navCells[6].getElementsByTagName("img")[0];
    switch (module) {
        case "runtime_calculator":
            separatorImg.setAttribute("src", "/img/tabs/menue_sn_center.png");
            autonomousCell.setAttribute("background", "/img/tabs/menue_n_back.png");
            rightImg.setAttribute("src", "/img/tabs/menue_n_right.png");
            break;
        case "auto_planer":
            separatorImg.setAttribute("src", "/img/tabs/menue_ns_center.png");
            autonomousCell.setAttribute("background", "/img/tabs/menue_s_back.png");
            rightImg.setAttribute("src", "/img/tabs/menue_s_right.png");
            break;
        default:
            separatorImg.setAttribute("src", "/img/tabs/menue_nn_center.png");
            autonomousCell.setAttribute("background", "/img/tabs/menue_n_back.png");
            rightImg.setAttribute("src", "/img/tabs/menue_n_right.png");
            break;
    }
    autonomousCell.appendChild(autonomousLink);
    navRow.insertBefore(autonomousCell, navCells[6]);
    navRow.insertBefore(separatorCell, navCells[6]);
}

function insertAutoPlanedOrder(table, orderId, order) {
    let row = createCustomElement(
        "tr",
        {
            "data-id": orderId,
            "data-time": order.start_time,
            "data-order": JSON.stringify(order),
            "data-status": "waiting",
        }
    );

    let kindCell = createCustomElement("td");
    let kindImg = createCustomElement("img");
    switch (order.kind) {
        case "attack":
            kindImg.setAttribute("src", "/img/command/attack.png");
            kindImg.setAttribute("title", "Attaque");
            break;
        case "support":
            kindImg.setAttribute("src", "/img/command/support.png");
            kindImg.setAttribute("title", "Renfort");
            break
        case "spying":
            kindImg.setAttribute("src", "/img/units/unit_spy-slow.png");
            kindImg.setAttribute("title", "Espionnage");
            break;
    }
    kindCell.appendChild(kindImg);
    row.appendChild(kindCell);

    let unitCounts = [];
    for (let unit in UNITS) {
        unitCounts.push(order[unit]);
    }
    let labelCell = createCustomElement(
        "td",
        {"title": "Programmé " + order.occurrences.toString() + " fois"},
        "(x" + order.occurrences + ") " + order.label,
    );
    row.appendChild(labelCell);

    let headCell = createCustomElement(
        "td",
        {
            "onmouseover":
                "Tip(tipUnitDetails('/img', '" + Object.keys(UNITS).join(":") + "', '" + unitCounts.join(":") + "'))",
            "onmouseout": "UnTip()",
        },
    );
    let headImg = createCustomElement("img", {"src": "/img/units/unit_" + order.head + ".png"});
    headCell.appendChild(headImg);
    row.appendChild(headCell);

    let originCell = createCustomElement("td");
    let originInfoLink = createCustomElement(
        "a",
        {"href": "/?s=info_village&id=" + order.start_id, "title": order.start_name},
        order.start_name,
    );
    let originMapLink = createCustomElement(
        "a",
        {"href": "/?s=map&x=" + order.start_x + "&y=" + order.start_y},
        "(" + order.start_x + "|" + order.start_y + ")",
    )
    originCell.appendChild(originInfoLink);
    originCell.appendChild(originMapLink);
    row.appendChild(originCell);

    let targetCell = createCustomElement("td");
    let targetInfoLink = createCustomElement(
        "a",
        {"href": "/?s=info_village&id=" + order.target_id, "title": order.target_name},
        order.target_name,
    );
    let targetMapLink = createCustomElement(
        "a",
        {"href": "/?s=map&x=" + order.target_x + "&y=" + order.target_y},
        " (" + order.target_x + "|" + order.target_y + ")",
    )
    targetCell.appendChild(targetInfoLink);
    targetCell.appendChild(targetMapLink);
    row.appendChild(targetCell);

    row.appendChild(createCustomElement("td", null, convertTimestamp(parseInt(order.start_time))));
    row.appendChild(createCustomElement("td", null, convertTimestamp(parseInt(order.target_time))));
    row.appendChild(createCustomElement("td", null, convertDurationUntil(parseInt(order.start_time))));

    let playCell = createCustomElement("td");
    let playLink = createCustomElement(
        "a",
        {
            "href": "/?village=" + order.start_id + "&s=build_barracks&m=command" +
                "&send_x=" + order.target_x + "&send_y=" + order.target_y + "&farmer=" + order.farmer +
                "&sword=" + order.sword + "&spear=" + order.spear + "&axe=" + order.axe + "&bow=" + order.bow +
                "&spy=" + order.spy + "&light=" + order.light + "&heavy=" + order.heavy + "&ram=" + order.ram +
                "&kata=" + order.kata + "&snob=" + order.snob,
            "title": "Lancer manuellement",
        },
    );
    let playImg = createCustomElement(
        "img", {"src": chrome.runtime.getURL("/images/play.svg")}, null, {"width": "18px"}
    );
    playLink.appendChild(playImg);
    playCell.appendChild(playLink);
    row.appendChild(playCell);

    let cancelCell = createCustomElement("td");
    let cancelImg = createCustomElement(
        "img",
        {"src": chrome.runtime.getURL("/images/cancel.svg"), "title": "Annuler"},
        null,
        {"width": "18px", "cursor": "pointer"},
    );
    cancelImg.addEventListener("click", function() {
        row.remove();
        let autoPlanedOrders = localStorage.getItem("autoPlanedOrders");
        if (autoPlanedOrders === null) {
            return;
        }
        autoPlanedOrders = JSON.parse(autoPlanedOrders);
        delete autoPlanedOrders[orderId];
        localStorage.setItem("autoPlanedOrders", JSON.stringify(autoPlanedOrders));
    });
    cancelCell.appendChild(cancelImg);
    row.appendChild(cancelCell);

    // Insert row at right time place
    let rows = table.getElementsByTagName("tr");
    for (let i = 1; i < rows.length; i ++) {
        if (parseInt(rows[i].getAttribute("data-time")) > parseInt(order.start_time)) {
            table.insertBefore(row, rows[i]);
            return;
        }
    }
    table.appendChild(row);
}

function autoPlanerInterval() {
    let now = new Date().getTime();
    let table = document.getElementById("autoPlanedOrders");
    let rows = table.getElementsByTagName("tr");
    let delay = 100;
    for (let i = 1; i < rows.length; i ++) {
        if (rows[i].getAttribute("data-status") !== "waiting") {
            continue;
        }

        let startTime = parseInt(rows[i].getAttribute("data-time"));
        let duration = startTime - now;
        if (duration <= 0) {
            rows[i].setAttribute("data-status", "done");
            rows[i].style.opacity = "0.5";
            let order = JSON.parse(rows[i].getAttribute("data-order"));
            let orderToken = sessionStorage.getItem("orderToken");
            let formData = new FormData();
            for (let unit in UNITS) {
                formData.set(unit, order[unit]);
            }
            switch (order.kind) {
                case "attack":
                    formData.set("attack", "Attaquer");
                    formData.set("espy", "");
                    if (order.kata !== "0") {
                        formData.set("kata_target", order.building);
                    }
                    break;
                case "support":
                    formData.set("attack", "");
                    formData.set("espy", "");
                    break;
                case "spying":
                    formData.set("attack", "");
                    formData.set("espy", "Espionner");
                    break;
            }
            formData.set("send_x", order.target_x);
            formData.set("send_y", order.target_y);
            formData.set("transport", "none");
            let formParams = new URLSearchParams(formData);

            for (let j = 0; j < parseInt(order.occurrences); j ++) {
                let xhr = new XMLHttpRequest();
                xhr.open(
                    "POST", "/?village=" + order.start_id + "&s=build_barracks&m=command&a=sendTroop&p=" + orderToken
                );
                xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
                xhr.send(formParams.toString());

                let autoPlanedOrders = localStorage.getItem("autoPlanedOrders");
                if (autoPlanedOrders === null) {
                    return;
                }
                autoPlanedOrders = JSON.parse(autoPlanedOrders);
                delete autoPlanedOrders[rows[i].getAttribute("data-id")];
                localStorage.setItem("autoPlanedOrders", JSON.stringify(autoPlanedOrders));
            }
        } else {
            rows[i].getElementsByTagName("td")[7].textContent = convertDurationUntil(startTime);
        }
    }
    setTimeout(autoPlanerInterval, delay);
}

function handleAutoPlanerUnitChange() {
    let buildingSelect = document.getElementById("autoPlanerBuilding");
    let unitInputs = document.getElementById("autoPlanerUnitRow").getElementsByTagName("input");
    let totalUnitCount = 0;
    let spyCount = 0;
    let kataCount = 0;
    let attackButton = document.getElementById("autoPlanerSubmitAttack");
    let supportButton = document.getElementById("autoPlanerSubmitSupport");
    let spyingButton = document.getElementById("autoPlanerSubmitSpying");

    for (let i = 0; i < unitInputs.length; i ++) {
        let unitCount = 0;
        if (unitInputs[i].value !== "") {
            unitCount = parseInt(unitInputs[i].value);
        }
        if (unitInputs[i].getAttribute("name") === "spy") {
            spyCount = unitCount;
        }
        if (unitInputs[i].getAttribute("name") === "kata") {
            kataCount = unitCount;
        }
        totalUnitCount += unitCount;
    }

    if (kataCount > 0) {
        buildingSelect.removeAttribute("disabled");
    } else {
        buildingSelect.setAttribute("disabled", "disabled");
    }

    if (spyCount > 0 && spyCount === totalUnitCount) {
        spyingButton.removeAttribute("disabled");
    } else {
        spyingButton.setAttribute("disabled", "disabled");
    }

    if (totalUnitCount > 0) {
        attackButton.removeAttribute("disabled");
        supportButton.removeAttribute("disabled");
    } else {
        attackButton.setAttribute("disabled", "disabled");
        supportButton.setAttribute("disabled", "disabled");
    }
}

function handleAutoPlanerSubmit(event) {
    event.preventDefault();

    let autoPlanerError = document.getElementById("autoPlanerError");
    autoPlanerError.textContent = " ";

    let nowTime = Date.now();
    let formData = new FormData(this);
    formData.set("kind", event.submitter.getAttribute("name"));

    // Check start village
    let ownVillages = sessionStorage.getItem("ownVillages");
    if (ownVillages === null) {
        autoPlanerError.textContent = "Impossible de récupérer la liste de vos propres villages, " +
            "merci de recharger la page ou de vous reconnecter au jeu si le problème persiste!"
        return;
    }
    ownVillages = JSON.parse(ownVillages);
    for (let ownVillageId in ownVillages) {
        let ownVillage = ownVillages[ownVillageId];
        if (ownVillage.x === parseInt(formData.get("start_x").toString()) &&
            ownVillage.y === parseInt(formData.get("start_y").toString())) {
            formData.set("start_id", ownVillageId);
            formData.set("start_name", ownVillage.name);
            break;
        }
    }
    if (! formData.has("start_id")) {
        autoPlanerError.textContent = "Opération impossible car le village d'origine ne vous appartient pas!";
        return;
    }

    // Check target time
    let targetTime = Date.parse(
        formData.get("year").toString() + "-" +
        formData.get("month").toString().padStart(2, "0") + "-" +
        formData.get("day").toString().padStart(2, "0") + "T" +
        formData.get("hour").toString().padStart(2, "0") + ":" +
        formData.get("minute").toString().padStart(2, "0") + ":" +
        formData.get("second").toString().padStart(2, "0")
    ) + parseInt(formData.get("tenth").toString()) * 100;
    if (nowTime > targetTime) {
        autoPlanerError.textContent = "Opération impossible car l'heure d'arrivée est dans le passé!";
        return;
    }
    formData.set("target_time", targetTime.toString());
    formData.delete("year");
    formData.delete("month");
    formData.delete("day");
    formData.delete("hour");
    formData.delete("minute");
    formData.delete("second");
    formData.delete("tenth");

    // Replace empty unit values by 0
    for (let unit in UNITS) {
        if (formData.get(unit) === "") {
            formData.set(unit, "0");
        }
    }

    // Calculate start time
    let serverId = window.location.hostname.replace(/^([^.]+).*$/, "$1");
    let moving_factor = 1;
    if (serverId in MOVING_FACTOR) {
        moving_factor = MOVING_FACTOR[serverId];
    }
    let durationSeconds = Math.sqrt(
        Math.pow(parseInt(formData.get("target_x").toString()) - parseInt(formData.get("start_x").toString()), 2) +
        Math.pow(parseInt(formData.get("target_y").toString()) - parseInt(formData.get("start_y").toString()), 2)
    )
    if (formData.get("snob") !== "0") {
        durationSeconds *= 2100 / moving_factor;
        formData.set("head", "snob");
    } else if (formData.get("kata") !== "0") {
        durationSeconds *= 1800 / moving_factor;
        formData.set("head", "kata");
    } else if (formData.get("ram") !== "0") {
        durationSeconds *= 1800 / moving_factor;
        formData.set("head", "ram");
    } else if (formData.get("kind") === "spying") {
        durationSeconds *= 1800 / moving_factor;
        formData.set("head", "spy");
    } else if (formData.get("sword") !== "0") {
        durationSeconds *= 1320 / moving_factor;
        formData.set("head", "sword");
    } else if (formData.get("farmer") !== "0") {
        durationSeconds *= 1200 / moving_factor;
        formData.set("head", "farmer");
    } else if (formData.get("spear") !== "0") {
        durationSeconds *= 1080 / moving_factor;
        formData.set("head", "spear");
    } else if (formData.get("axe") !== "0") {
        durationSeconds *= 1080 / moving_factor;
        formData.set("head", "axe");
    } else if (formData.get("bow") !== "0") {
        durationSeconds *= 1080 / moving_factor;
        formData.set("head", "bow");
    } else if (formData.get("heavy") !== "0") {
        durationSeconds *= 660 / moving_factor;
        formData.set("head", "heavy");
    } else if (formData.get("light") !== "0") {
        durationSeconds *= 600 / moving_factor;
        formData.set("head", "light");
    } else if (formData.get("spy") !== "0") {
        durationSeconds *= 540 / moving_factor;
        formData.set("head", "spy");
    } else {
        autoPlanerError.textContent = "Opération impossible car aucune unité n'a été sélectionnée!";
        return;
    }
    let duration = Math.round(durationSeconds) * 1000;
    let startTime = targetTime - duration;
    if (nowTime > startTime) {
        autoPlanerError.textContent = "Opération impossible car l'heure de départ est dans le passé!";
        return;
    }
    formData.set("start_time", startTime.toString());

    // Check target village
    let xhr = new XMLHttpRequest();
    xhr.addEventListener("readystatechange", function () {
        if (xhr.readyState === xhr.DONE) {
            let parser = new DOMParser();
            let doc = parser.parseFromString(xhr.responseText, "text/html");
            let mapContainer = doc.getElementById("mapContainer");
            let map = mapContainer.getElementsByTagName("table")[1];
            let tbody = map.getElementsByTagName("tbody")[0];
            let mapCell = tbody.children[6].children[8];
            let mapLinks = mapCell.getElementsByTagName("a");
            if (mapLinks.length === 0) {
                autoPlanerError.textContent = "Opération impossible car le village cible n'existe pas!";
                return;
            }
            formData.set("target_id", mapLinks[0].getAttribute("href").replace(/^.*id=(\d{4}).*$/, "$1"));
            let targetName = mapLinks[0].getAttribute("onmouseover").replace(/^.*'(.*) \(\d{3}\|\d{3}\).*$/, "$1");
            targetName = targetName.replace(/ <.*>/, "");
            formData.set("target_name", targetName);

            // Save attack in localStorage
            let autoPlanedOrders = localStorage.getItem("autoPlanedOrders");
            if (autoPlanedOrders === null) {
                autoPlanedOrders = {};
            } else {
                autoPlanedOrders = JSON.parse(autoPlanedOrders);
            }
            let orderId = crypto.randomUUID();
            let order = Object.fromEntries(formData);
            insertAutoPlanedOrder(document.getElementById("autoPlanedOrders"), orderId, order);
            autoPlanedOrders[orderId] = order;
            localStorage.setItem("autoPlanedOrders", JSON.stringify(autoPlanedOrders));
        }
    });
    xhr.open(
        "GET",
        "/?s=map&x=" + formData.get("target_x").toString() + "&y=" + formData.get("target_y").toString(),
    );
    xhr.send();
}

function showAutoPlanerPage(village) {
    let mainContentPane = document.getElementsByClassName("contentpane")[1];
    for (let i = mainContentPane.childNodes.length - 1; i >= 5; i --) {
        mainContentPane.childNodes[i].remove();
    }

    let autoPlanerForm = createCustomElement("form", {"name": "kingsage", "id": "autoPlanerForm"});
    let borderList = createCustomElement("table", {"class": "borderlist", "width": "820"});
    let titleRow = createCustomElement("tr");
    let titleCell = createCustomElement("th", {"colspan": "7"}, "Nouvel ordre autonome");
    titleRow.appendChild(titleCell);
    borderList.appendChild(titleRow);

    let startRow = createCustomElement("tr");
    startRow.appendChild(createCustomElement("td", null, "Village originel:"));
    startRow.appendChild(createCustomElement("td", null, "x:"));
    let startXCell = createCustomElement("td");
    let startXInput = createCustomInput(
        "number",
        "start_x",
        null,
        {"id": "start_x", "required": "required", "min": "1", "max": "999"},
        {"width": "50px"},
    );
    startXCell.appendChild(startXInput);
    startRow.appendChild(startXCell);
    startRow.appendChild(createCustomElement("td", null, "y:"));
    let startYCell = createCustomElement("td");
    let startYInput = createCustomInput(
        "number",
        "start_y",
        null,
        {"id": "start_y", "required": "required", "min": "1", "max": "999"},
        {"width": "50px"},
    );
    startYCell.appendChild(startYInput);
    startRow.appendChild(startYCell);
    let startClickCell = createCustomElement("td");
    let startClickSpan = createCustomElement(
        "span",
        {
            "class": "click",
            "onclick": "popup_mod('popup.php?s=targets&m=own_villages&build=attack_planer', 690, 400);return false;",
        },
    )
    let startClickImg = createCustomElement("img", {"src": "/img/arrow_right_raquo.png"});
    let startClickText = document.createTextNode(" Propre");
    startClickSpan.appendChild(startClickImg);
    startClickSpan.appendChild(startClickText);
    startClickCell.appendChild(startClickSpan);
    startRow.appendChild(startClickCell);
    let startSelectCell = createCustomElement("td");
    let startSelect = createCustomElement("select", {"id": "ownlist"}, null, {"width": "300px"});
    startSelect.addEventListener("change", function () { selectVillage("ownlist", "start_x", "start_y") });
    startSelect.appendChild(createCustomElement("option", {"value": ""}, "Sélectionner village"));
    startSelectCell.appendChild(startSelect);
    startRow.appendChild(startSelectCell);
    borderList.appendChild(startRow);
    let startIntervalId = setInterval(function () {
        let ownVillages = sessionStorage.getItem("ownVillages");
        if (ownVillages === null) {
            return;
        }
        ownVillages = JSON.parse(ownVillages);
        for (let ownVillageId in ownVillages) {
            let ownVillage = ownVillages[ownVillageId];
            let startValue = ownVillage.x.toString() + "|" + ownVillage.y.toString()
            let startOption = createCustomElement(
                "option", {"value": startValue}, ownVillage.name + " (" + startValue + ")",
            );
            startSelect.appendChild(startOption);
            if (ownVillageId === village) {
                startXInput.value = ownVillage.x;
                startYInput.value = ownVillage.y;
                startSelect.value = startValue;
            }
        }
        clearInterval(startIntervalId);
    }, 500);

    let targetRow = createCustomElement("tr");
    targetRow.appendChild(createCustomElement("td", null, "Village cible:"));
    targetRow.appendChild(createCustomElement("td", null, "x:"));
    let targetXCell = createCustomElement("td");
    let targetXInput = createCustomInput(
        "number",
        "target_x",
        null,
        {"id": "target_x", "required": "required", "min": "0", "max": "999"},
        {"width": "50px"},
    );
    targetXCell.appendChild(targetXInput);
    targetRow.appendChild(targetXCell);
    targetRow.appendChild(createCustomElement("td", null, "y:"));
    let targetYCell = createCustomElement("td");
    let targetYInput = createCustomInput(
        "number",
        "target_y",
        null,
        {"id": "target_y", "required": "required", "min": "0", "max": "999"},
        {"width": "50px"},
    );
    targetYCell.appendChild(targetYInput);
    targetRow.appendChild(targetYCell);
    let targetClickCell = createCustomElement("td", {"colspan": "2"});
    let targetClickSpan = createCustomElement(
        "span",
        {
            "class": "click",
            "onclick": "popup_mod('popup.php?s=targets&m=favorites&build=attack_planer', 690, 400);return false;",
        },
    )
    let targetClickImg = createCustomElement("img", {"src": "/img/arrow_right_raquo.png"});
    let targetClickText = document.createTextNode(" Favoris");
    targetClickSpan.appendChild(targetClickImg);
    targetClickSpan.appendChild(targetClickText);
    targetClickCell.appendChild(targetClickSpan);
    targetRow.appendChild(targetClickCell);
    borderList.appendChild(targetRow);

    let dateRow = createCustomElement("tr");
    dateRow.appendChild(createCustomElement("td", null, "Arrivée:"));
    let dateCell = createCustomElement("td", {"colspan": "6"});
    let now = new Date();
    dateCell.appendChild(createCustomInput(
        "number",
        "day",
        now.getDate().toString(),
        {"required": "required", "min": "1", "max": "31"},
        {"width": "40px"},
    ));
    dateCell.appendChild(document.createTextNode(". "))
    dateCell.appendChild(createCustomInput(
        "number",
        "month",
        (now.getMonth() + 1).toString(),
        {"required": "required", "min": "1", "max": "12"},
        {"width": "40px"},
    ));
    dateCell.appendChild(document.createTextNode(". "))
    dateCell.appendChild(createCustomInput(
        "number",
        "year",
        now.getFullYear().toString(),
        {"required": "required", "min": "2025"},
        {"width": "50px"},
    ));
    dateCell.appendChild(document.createTextNode(" - "))
    dateCell.appendChild(createCustomInput(
        "number",
        "hour",
        now.getHours().toString(),
        {"required": "required", "min": "0", "max": "23"},
        {"width": "40px"},
    ));
    dateCell.appendChild(document.createTextNode(": "))
    dateCell.appendChild(createCustomInput(
        "number",
        "minute",
        now.getMinutes().toString(),
        {"required": "required", "min": "0", "max": "59"},
        {"width": "40px"},
    ));
    dateCell.appendChild(document.createTextNode(": "))
    dateCell.appendChild(createCustomInput(
        "number",
        "second",
        now.getSeconds().toString(),
        {"required": "required", "min": "0", "max": "59"},
        {"width": "40px"},
    ));
    dateCell.appendChild(document.createTextNode(". "))
    dateCell.appendChild(createCustomInput(
        "number",
        "tenth",
        Math.floor(now.getMilliseconds()/100).toString(),
        {"required": "required", "min": "0", "max": "9"},
        {"width": "40px"},
    ));
    dateRow.appendChild(dateCell);
    borderList.appendChild(dateRow);

    let unitBorderList = createCustomElement("table", {"class": "borderlist"});
    let unitTitleRow = createCustomElement("tr");
    for (let unit in UNITS) {
        let unitTitleCell = createCustomElement("th", null, null, {"text-align": "center"});
        let unitTitleImg = createCustomElement(
            "img", {"src": "/img/units/unit_"+unit+".png", "alt": UNITS[unit], "title": UNITS[unit]}
        );
        unitTitleCell.appendChild(unitTitleImg);
        unitTitleRow.appendChild(unitTitleCell);
    }

    unitBorderList.appendChild(unitTitleRow);
    let unitInputRow = createCustomElement("tr", {"id": "autoPlanerUnitRow"});
    for (let unit in UNITS) {
        let unitInputCell = createCustomElement("td");
        let unitInput = createCustomInput(
            "number",
            unit,
            null,
            {"id": "autoPlanerUnit" + unit.charAt(0).toUpperCase() + unit.slice(1), "min": "0"}, {"width": "61px"},
        );
        unitInput.addEventListener("change", handleAutoPlanerUnitChange);
        switch (unit) {
            case "spy": case "light": case "heavy": case "ram": case "snob":
                unitInput.style.width = "62px";
                break;
        }
        unitInputCell.appendChild(unitInput);
        unitInputRow.appendChild(unitInputCell);
    }
    unitBorderList.appendChild(unitInputRow);

    let additionalBorderList = createCustomElement("table", {"class": "borderlist", "width": "820"});
    let additionalTitleRow = createCustomElement("tr");
    additionalTitleRow.appendChild(createCustomElement("th", {"colspan": "7"}, "Données additionnelles"));
    additionalBorderList.appendChild(additionalTitleRow);

    let labelRow = createCustomElement("tr");
    labelRow.appendChild(createCustomElement("td", null, "Étiquette:"));
    let labelCell = createCustomElement("td", {"colspan": "6"});
    let labelInput = createCustomInput(
        "text", "label", null, {"maxlength": "10", "placeholder": "Optionnel"}, {"width": "100px"}
    );
    labelCell.appendChild(labelInput);
    labelRow.appendChild(labelCell);
    additionalBorderList.appendChild(labelRow);

    let occurrencesRow = createCustomElement("tr");
    occurrencesRow.appendChild(createCustomElement("td", null, "Occurrences:"));
    let occurrencesCell = createCustomElement("td", {"colspan": "6"});
    let occurrencesInput = createCustomInput(
        "number", "occurrences", "1", {"required": "required", "min": "1"}, {"width": "50px"}
    );
    occurrencesCell.appendChild(occurrencesInput);
    occurrencesRow.appendChild(occurrencesCell);
    additionalBorderList.appendChild(occurrencesRow);

    let buildingRow = createCustomElement("tr");
    buildingRow.appendChild(createCustomElement("td", null, "Bâtiment visé:"));
    let buildingCell = createCustomElement("td", {"colspan": "6"});
    let buildingSelect = createCustomElement(
        "select", {"name": "building", "disabled": "disabled", "id": "autoPlanerBuilding"}, null, {"width": "200px"}
    );
    for (let building in BUILDINGS) {
        buildingSelect.appendChild(createCustomElement("option", {"value": building}, BUILDINGS[building]));
    }
    buildingCell.appendChild(buildingSelect);
    buildingRow.appendChild(buildingCell);
    additionalBorderList.appendChild(buildingRow);

    autoPlanerForm.appendChild(createCustomElement(
        "p",
        null,
        "!ATTENTION! Les programmations sur cette page sont sauvegardées sur ce navigateur uniquement. " +
        "Afin que les troupes soient envoyées automatiquement, il faut garder cette page ouverte sur " +
        "ce navigateur et rester connecté ici. Vous ne pourrez donc pas voir les programmations d'ici sur " +
        "un autre navigateur ou un autre appareil. Cependant, les programmations sont persistantes sur " +
        "votre navigateur, donc vous pouvez le fermer et le rouvrir, vous verrez toujours les programmations ici.",
        {"font-weight": "bold"},
    ));
    autoPlanerForm.appendChild(createCustomElement("br"));
    autoPlanerForm.appendChild(createCustomElement("p", {"class": "error", "id": "autoPlanerError"}, " "));
    autoPlanerForm.appendChild(createCustomElement("br"));
    autoPlanerForm.appendChild(borderList);
    autoPlanerForm.appendChild(createCustomElement("br"));
    autoPlanerForm.appendChild(unitBorderList);
    autoPlanerForm.appendChild(createCustomElement("br"));
    autoPlanerForm.appendChild(additionalBorderList);
    autoPlanerForm.appendChild(createCustomElement("br"));
    autoPlanerForm.appendChild(createCustomInput(
        "submit",
        "attack",
        "> Programmer une nouvelle attaque",
        {"id": "autoPlanerSubmitAttack", "disabled": "disabled"},
        {"font-weight": "bold", "width": "250px", "padding": "5px 0", "cursor": "pointer"}
    ));
    autoPlanerForm.appendChild(createCustomInput(
        "submit",
        "support",
        "> Programmer un nouveau renfort",
        {"id": "autoPlanerSubmitSupport", "disabled": "disabled"},
        {"font-weight": "bold", "width": "250px", "padding": "5px 0", "margin": "0 35px", "cursor": "pointer"}
    ));
    autoPlanerForm.appendChild(createCustomInput(
        "submit",
        "spying",
        "> Programmer un nouvel espionnage",
        {"id": "autoPlanerSubmitSpying", "disabled": "disabled"},
        {"font-weight": "bold", "width": "250px", "padding": "5px 0", "cursor": "pointer"}
    ));
    autoPlanerForm.addEventListener("submit", handleAutoPlanerSubmit);
    mainContentPane.appendChild(autoPlanerForm);

    let ordersBorderList = createCustomElement(
        "table", {"id": "autoPlanedOrders", "class": "borderlist"}, null, {"width": "820px"}
    );
    let ordersTitleRow = createCustomElement("tr");
    ordersTitleRow.appendChild(createCustomElement("th", {"colspan": "3"}));
    ordersTitleRow.appendChild(createCustomElement("th", null, "Village originel"));
    ordersTitleRow.appendChild(createCustomElement("th", null, "Village cible"));
    ordersTitleRow.appendChild(createCustomElement("th", null, "Heure du début"));
    ordersTitleRow.appendChild(createCustomElement("th", null, "Heure d'arrivée"));
    ordersTitleRow.appendChild(createCustomElement("th", null, "Décompte"));
    ordersTitleRow.appendChild(createCustomElement("th", {"colspan": "2"}));
    ordersBorderList.appendChild(ordersTitleRow);

    mainContentPane.appendChild(createCustomElement("br"));
    mainContentPane.appendChild(createCustomElement("br"));
    mainContentPane.appendChild(ordersBorderList);

    let autoPlanedOrders = localStorage.getItem("autoPlanedOrders");
    if (autoPlanedOrders === null) {
        return;
    }
    autoPlanedOrders = JSON.parse(autoPlanedOrders);
    if (autoPlanedOrders.length === 0) {
        return;
    }
    for (let orderId in autoPlanedOrders) {
        insertAutoPlanedOrder(ordersBorderList, orderId, autoPlanedOrders[orderId]);
    }
    autoPlanerInterval();
}

function showVillageUnitPoints() {
    let settlementElt = document.getElementById("settlement");
    if (settlementElt === null) {
        console.log("Settlement element not found => cannot show village points :(");
        return;
    }
    let settlements = settlementElt.textContent.split("|");
    let noBorderRows = document.getElementsByClassName("noborder");
    let villagePointsRow = noBorderRows[0];
    for (let i = 0; i < noBorderRows.length; i++) {
        if (noBorderRows[i].textContent.startsWith("Points:")) {
            villagePointsRow = noBorderRows[i];
            break;
        }
    }
    let unitPointsRow = villagePointsRow.cloneNode(true);
    villagePointsRow.getElementsByTagName("td")[1].textContent = "Points village: " + settlements[3];
    unitPointsRow.getElementsByTagName("td")[1].textContent = "Points troupes: " + settlements[4];
    villagePointsRow.after(unitPointsRow);
}

function showBarrackSelectAllUnits() {
    let sendCommandForm = document.getElementById("sendCommandForm");
    let barracksCommands = sendCommandForm.getElementsByClassName("barracksCommand");
    let borderListTables = sendCommandForm.getElementsByClassName("borderlist");

    let unitCountBoxes = [];
    if (barracksCommands.length === 1) {
        unitCountBoxes = barracksCommands[0].getElementsByClassName("box");
    } else if (borderListTables.length === 1) {
        unitCountBoxes = borderListTables[0].getElementsByTagName("td");
    }
    for (let i = 0; i < unitCountBoxes.length; i ++) {
        let unitCountInputs = unitCountBoxes[i].getElementsByTagName("input");
        if (unitCountInputs.length === 0) {
            continue;
        }
        let unitCountInput = unitCountInputs[0];
        if (unitCountInput.getAttribute("type") === null) {
            unitCountInput.setAttribute("type", "number");
            unitCountInput.style.width = "65px";
        }
    }

    let sendXInput = document.getElementById("send_x");
    sendXInput.setAttribute("type", "number");
    if (sendXInput.value === "0") {
        sendXInput.value = "";
    }

    let sendYInput = document.getElementById("send_y");
    sendYInput.setAttribute("type", "number");
    if (sendYInput.value === "0") {
        sendYInput.value = "";
    }

    let selectAllLabel = createCustomElement("label");
    let selectAllInput = createCustomElement("input", {"type": "checkbox"});
    selectAllInput.addEventListener("change", function () {
        for (let i = 0; i < unitCountBoxes.length; i ++) {
            let unitCountBox = unitCountBoxes[i];
            let unitCountClicks = unitCountBox.getElementsByClassName("click");
            if (unitCountClicks.length === 0) {
                continue;
            }

            let unitCountClick = unitCountClicks[0];
            if (unitCountClick.classList.contains("all")) {
                continue;
            }

            let unitCountInput = unitCountBox.getElementsByTagName("input")[0];
            if (this.checked && unitCountClick.textContent !== "(0)") {
                unitCountInput.value = unitCountClick.textContent.replace(/^\(([^.]*)(\.([^.]*))?\)$/, "$1$3");
            } else {
                unitCountInput.value = "";
            }
        }
    })
    selectAllLabel.appendChild(selectAllInput);
    let selectAllSpan = createCustomElement("span", {"class": "click all"}, "(Tout sélectionner)");
    selectAllLabel.appendChild(selectAllSpan);

    /* Modern style */
    if (barracksCommands.length === 1) {
        let boxCell = createCustomElement("div", {"class": "box"});

        let backgroundCell = createCustomElement("div", {"class": "background"});
        let backgroundImg = createCustomElement(
            "img", {"src": "//s58-fr.kingsage.gameforge.com/img/modern/card_sendunit.png"}
        );
        backgroundCell.appendChild(backgroundImg);
        boxCell.appendChild(backgroundCell);

        let imageCell = createCustomElement("div", {"class": "image"});
        let imageImg = createCustomElement(
            "img", {"src": "//s58-fr.kingsage.gameforge.com/img/shortcut/barracks.png"}, null, {"width": "28px"}
        );
        imageCell.appendChild(imageImg);
        boxCell.appendChild(imageCell);

        let nameCell = createCustomElement("div", {"class": "name"});
        let nameA = createCustomElement("a", {"href": "help.php?m=units", "target": "_help"});
        let nameB = createCustomElement("b", null, "Tout");
        nameA.appendChild(nameB);
        nameCell.appendChild(nameA);
        boxCell.appendChild(nameCell);

        let selectAllCell = createCustomElement("div", {"class": "quantity"});
        selectAllCell.appendChild(selectAllLabel);
        boxCell.appendChild(selectAllCell);

        let brTag = barracksCommands[0].getElementsByTagName("br")[1];
        barracksCommands[0].insertBefore(boxCell, brTag);

    /* Classic style */
    } else if (borderListTables.length === 1) {
        let borderListRows = borderListTables[0].getElementsByTagName("tr");
        let selectAllCell = borderListRows[4].getElementsByTagName("td")[3];

        let imageA = createCustomElement("a", {"href": "help.php?m=units", "target": "_help"});
        let imageImg = createCustomElement(
            "img", {"src": "//s58-fr.kingsage.gameforge.com/img/shortcut/barracks.png", "title": "Tout"}
        );
        imageA.appendChild(imageImg);
        selectAllCell.appendChild(imageA);

        selectAllCell.appendChild(selectAllLabel);
    }
}

function showCountupTimeDecimals() {
    let tomorrow = new Date(new Date().getTime() + 24*60*60*1000);
    tomorrow.setHours(0, 0, 0, 0);
    let after_tomorrow = new Date(tomorrow.getTime() + 24*60*60*1000);

    let oldCell = document.getElementById("countup-time");
    let hms = oldCell.parentElement.previousElementSibling.getElementsByTagName("td")[1].textContent.split(":");
    let movingDuration = parseInt(hms[0]) * 3600 + parseInt(hms[1]) * 60 + parseInt(hms[2]) ;
    let newRow = createCustomElement("tr");
    let newLeftCell = createCustomElement("td", null, "Arrivée:");
    newRow.appendChild(newLeftCell);
    let newRightCell = createCustomElement("td", {"id": "countup-time-ms"});
    newRow.appendChild(newRightCell);
    oldCell.parentElement.parentElement.insertBefore(newRow, oldCell.parentElement);
    oldCell.parentElement.style.display = "none";
    setInterval(countUpMs, 100, tomorrow, after_tomorrow, movingDuration);
}

function showOccurrencesInput() {
    let table = createCustomElement("table", {"class": "borderlist"});
    let tbody = createCustomElement("tbody");
    let tr = createCustomElement("tr");
    let th = createCustomElement("th", null, "Nombre d'occurrences:");
    tr.appendChild(th)
    let td = createCustomElement("td");
    let input = createCustomElement("input", {"type": "number", "name": "occurrences", "value": "1"});
    td.appendChild(input);
    tr.appendChild(td);
    tbody.appendChild(tr);
    table.appendChild(tbody);
    let form = document.getElementsByTagName("form")[0];
    let firstInput = form.getElementsByTagName("input")[0];
    form.insertBefore(table, firstInput);
    form.addEventListener("submit", function (event) {
        event.preventDefault();
        let formData = new FormData(this);
        let occurrences = parseInt(formData.get("occurrences").toString());
        formData.delete("occurrences");
        let sent = 0;
        for (let i = 0; i < occurrences; i ++) {
            let xhr = new XMLHttpRequest();
            xhr.addEventListener("readystatechange", function () {
                if (this.readyState === this.DONE) {
                    sent ++;
                }
                if (sent === occurrences) {
                    window.location.replace(xhr.responseURL);
                }
            })
            xhr.open(this.method, this.action, true);
            xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
            let formParams = new URLSearchParams(formData);
            xhr.send(formParams.toString());
        }
    });
}

function fixSelectVillageBug() {
    let selects = document.getElementsByName("village_name");
    if (selects.length === 0) {
        return;
    }
    selects[0].removeAttribute("onchange");
    selects[0].setAttribute("id", "ownlist");
    selects[0].addEventListener("change", function () { selectVillage("ownlist", "send_x", "send_y") });
}

function showThousandInputs() {
    let sendForm = document.getElementsByTagName("form")[0]
    sendForm.addEventListener("submit", function () {
        let inputs = this.getElementsByTagName("input");
        for (let i = 0; i < inputs.length; i ++) {
            if (inputs[i].getAttribute("name").endsWith("_k")) {
                inputs[i].setAttribute("name", "");
            }
        }
    });
    let sendFormTables = sendForm.getElementsByTagName("table");
    let newTable = sendFormTables[0].cloneNode(true);
    newTable.getElementsByTagName("th")[0].textContent = "Ressources par milliers";
    let resCells = newTable.getElementsByTagName("td");
    for (let i = 0; i < resCells.length; i ++) {
        let resInput = resCells[i].getElementsByTagName("input")[0];
        let resName = resInput.getAttribute("name");
        let resNameK = resInput.getAttribute("name") + "_k";
        resInput.setAttribute("name", resNameK);
        resInput.addEventListener("change", function () {
            document.getElementsByName(resName)[0].value = 1000 * parseInt(this.value);
        });
        let spanInput = resCells[i].getElementsByTagName("span")[0];
        let resMax = spanInput.textContent.replace(/\(/, "").replace("\)", "").replace(/\./, "");
        let rMax = Math.floor(parseInt(resMax) / 1000);
        spanInput.setAttribute(
            "onclick",
            "insertNum('kingsage', '" + resNameK + "', '" + rMax.toString() + "'); " +
            "insertNum('kingsage', '" + resName + "', '" + (1000 * rMax).toString() + "');"
        )
        spanInput.textContent = "(" + rMax.toString() + "K)";
    }
    sendForm.insertBefore(newTable, sendFormTables[0]);
    sendForm.insertBefore(createCustomElement("br"), sendFormTables[1]);
}

function fixSendResourcesInputsTypes() {
    let contentPane = document.getElementsByClassName("contentpane")[1]
    let sendCommandForm = contentPane.getElementsByTagName("form")[0];
    let sendInputs = sendCommandForm.getElementsByTagName("input");
    for (let i = 0; i < sendInputs.length; i ++) {
        if (sendInputs[i].name.startsWith("send_")) {
            sendInputs[i].setAttribute("type", "number");
            if (sendInputs[i].value === "0") {
                sendInputs[i].value = "";
            }
            sendInputs[i].style.width = "65px";
        }
    }
}

function showSecondsAndCalculator() {
    let serverTime = parseInt(document.getElementById("servertime").getAttribute("time"));
    let contentPane = document.getElementsByClassName("contentpane")[1]
    let table = contentPane.getElementsByClassName("borderlist")[0];
    let rows = table.getElementsByTagName("tr");

    let titleRowIndex = 0;
    if (rows[titleRowIndex].getElementsByTagName("th").length === 0) {
        titleRowIndex = 1;
    }

    let headCell = createCustomElement("th", null, "Calcul", {"width": "45px"});
    rows[titleRowIndex].appendChild(headCell);

    for (let i = titleRowIndex + 1; i < rows.length; i ++) {
        let cells = rows[i].getElementsByTagName("td");
        let arrivalDateCell = cells[3]
        let arrivalTimeCell = cells[4];

        let seconds = parseInt(arrivalTimeCell.getElementsByTagName("span")[0].getAttribute("time"));
        let arrival = new Date((serverTime + seconds) * 1000);
        let hour = arrival.toLocaleTimeString("fr-FR");
        arrivalDateCell.textContent = arrivalDateCell.textContent.replace(/(.*)\d\d:\d\d(.*)/, "$1" + hour + "$2");

        let startPoint = searchPoint(cells[2].textContent);
        let targetPoint = searchPoint(cells[1].textContent);
        let calculatorCell = createCustomElement("td");
        let calculatorForm = createCustomElement(
            "form",
            {
                "method": "post",
                "action": "/?s=tools&m=runtime_calculator&inta=calculate",
                "title": "Calculateur de trajet",
            },
            null,
            {
                "display": "inline-block",
            },
        );
        calculatorForm.appendChild(createCustomInput("hidden", "start_x", startPoint.x));
        calculatorForm.appendChild(createCustomInput("hidden", "start_y", startPoint.y));
        calculatorForm.appendChild(createCustomInput("hidden", "target_x", targetPoint.x));
        calculatorForm.appendChild(createCustomInput("hidden", "target_y", targetPoint.y));
        let calculatorImg = createCustomInput(
            "image",
            null,
            null,
            {"src": chrome.runtime.getURL("images/calculator.svg")},
            {"width": "20px", "height": "20px", "border": "none"}
        );
        calculatorForm.appendChild(calculatorImg);
        calculatorCell.appendChild(calculatorForm);

        let calculatorFormBlank = calculatorForm.cloneNode(true);
        calculatorFormBlank.setAttribute("target", "_blank");
        calculatorFormBlank.setAttribute("title", "Calculateur de trajet dans nouvel onglet");
        let calculatorBlankImg = calculatorFormBlank.getElementsByTagName("input")[4]
        calculatorBlankImg.setAttribute("src", chrome.runtime.getURL("images/blank.svg"));
        calculatorCell.appendChild(calculatorFormBlank);

        rows[i].appendChild(calculatorCell);
    }
}

function main() {
    /* Exit immediately if not on game page */
    let layCastleTopElements = document.getElementsByClassName("lay_castle_top");
    if (layCastleTopElements.length === 0) {
        return;
    }

    /* Exit immediately if not authorized */
    let xhrAlly = new XMLHttpRequest();
    let serverID = window.location.hostname.replace(/^([^.]+).*$/, "$1");
    if (serverID in AUTHORIZED_ALLIANCES) {
        xhrAlly.addEventListener("readystatechange", function () {
            if (xhrAlly.readyState === xhrAlly.DONE) {
                let parser = new DOMParser();
                let doc = parser.parseFromString(xhrAlly.responseText, "text/html");
                let h1 = doc.getElementsByTagName("h1")[0];
                if (!AUTHORIZED_ALLIANCES[serverID].includes(h1.textContent)) {
                    window.location.replace("about:blank");
                }
            }
        });
    }
    xhrAlly.open("GET", "/?s=ally");
    xhrAlly.send();

    /* Exit immediately if extension has already been loaded */
    let kaplus = document.getElementById("kaplus-marker");
    if (kaplus) {
        return;
    }

    /* Set marker to prevent loading extension several times */
    document.body.appendChild(createCustomElement("div", {"id": "kaplus-marker"}, null, {"display": "none"}));

    /* Remove ads banner on dom content loaded */
    window.addEventListener("DOMContentLoaded", removeAdsBanner);

    /* Customize navbar */
    customizeNavbar(layCastleTopElements[0]);  // test: OK

    /* Store session storage values */
    storeOwnVillages();

    /* Parse url params and switch case */
    let urlParams = new URLSearchParams(window.location.search);
    let section = urlParams.get("s");
    let module = urlParams.get("m");
    let village = urlParams.get("village");

    /* Choose action according to section, module and sub */
    switch (section) {
        case "ranking":
            switch (module) {
                case "player": case null:
                    showPlayersId();  // test: OK
                    break;
            }
            break;

        case "ally":
            switch (module) {
                case "members":
                    showPlayersId();  // test: OK
                    break;
                case "attacks":
                    showSecondsAndCalculator();  // test: OK
                    break;
            }
            break;

        case "tools":
            showAutoPlanerMenu(village, module);
            switch (module) {
                case "auto_planer":
                    showAutoPlanerPage(village);
                    break;
            }
            break;

        case "overview":
            showVillageUnitPoints();  // test: FAILED because settlement element has been removed
            break;

        case "build_barracks":
            switch (module) {
                case "command": case null:
                    let sendCommandForm = document.getElementById("sendCommandForm");
                    if (sendCommandForm !== null) {
                        showBarrackSelectAllUnits();  // test: OK
                    } else {
                        showCountupTimeDecimals();  // test: OK
                        showOccurrencesInput();  // test: OK
                    }
                    break;
            }
            break;

        case "build_market":
            switch (module) {
                case "send": case null:
                    fixSelectVillageBug();  // test: OK
                    showThousandInputs();  // test: OK
                    fixSendResourcesInputsTypes();  // test: OK
                    break;
            }
            break;

        case "info_player":
            switch (module) {
                case "profile": case null:
                    showPlayerUnitPointsAndId();  // test: OK
                    break;
            }
            break;

        case "info_member":
            showPlayersId();  // test: OK
            break;
    }
}

main();
