
const offlineText = "Offline"
const missingPlayerText = "Leer"

const elementIdActionBar = "action-bar"
const elementIdTableName = "table-name-label"
const elementIdAvailableGamesList = "available-games-list"
const elementIdGameSummary = "game-summary"

// The web socket to connect to the server
var socket = null;

function closeSocketIfNeeded() {
    if (socket) {
        socket.close()
        didCloseSocket()
    }
}

function didCloseSocket() {
    socket = null
}

function showAlertWithError(error) {
    window.alert(error.message)
}

function showLoginPage() {
    deleteSessionToken();
    deleteTableId();
    closeSocketIfNeeded();
    window.location.href = "login.html";
}

function showListPage() {
    deleteTableId();
    closeSocketIfNeeded();
    window.location.href = "list.html";
}

function logoutUser() {
    const token = loadSessionToken()
    if (token == null) {
        showLoginPage();
        return
    }
    performLogoutRequest(token)
    .then(function() {
        showLoginPage();
    }).catch(showAlertWithError)
}

function loadExistingSession() {
    const token = loadSessionToken()
    if (token == null) {
        showLoginPage();
        return
    }
    resumeSessionRequest(token)
    .then(function(name) {
        storePlayerName(name);
        loadCurrentTable(token)
    }).catch(function(error) {
        console.log("Failed to resume session");
        console.log(error);
        showLoginPage();
    })
}

function loadCurrentTable(token) {
    performGetCurrentTableRequest(token)
    .then(function(table) {
        if (table == null) {
            showListPage();
        } else {
            storeTableId(table.id);
            updateTableInfo(table);
            openSocket(token);
        }
    })
    .catch(showAlertWithError)
}

function leaveTable() {
    const token = loadSessionToken()
    if (token == null) {
        showLoginPage();
        return
    }
    performLeaveTableRequest(token)
    .then(function() {
        showListPage();
    })
    .catch(showAlertWithError)
}

function openSocket(token) {
    const socketPath = webSocketPath()
    socket = new WebSocket(socketPath)

    socket.onopen = function(e) {
        socket.send(token);
        showConnectedState()
    };

    socket.onmessage = function(event) {
        const table = convertJsonResponse(event.data)
        updateTableInfo(table)
    };

    socket.onclose = function(event) {
        if (event.wasClean) {

        } else {
            // e.g. server process killed or network down
            // event.code is usually 1006 in this case
            // TODO: Retry several times to open socket,
            // stop after too many failed attempts
        }
        didCloseSocket()
        showDisconnectedState()
    };

    socket.onerror = function(error) {
        // error.message
    };
}

function refreshTables() {
    const token = loadSessionToken()
    if (token == null) {
        showLoginPage()
        return
    }
    performGetPublicTablesRequest(token)
    .then(processTableList)
    .catch(showAlertWithError)
}

function processTableList(tables) {
    var html = createTableRow
    for (let i = 0, len = tables.length; i < len; i++) {
        tableInfo = tables[i]
        html += "<div class=\"table-row\">"
        if (tableInfo.players.length < 4) {
            html += "<button class=\"table-join-btn\" onclick=\"joinTable('" + tableInfo.id + "')\">Join</button>"
        } else {
            html += "<button class=\"table-join-btn\" disabled>Full</button>"
        }
        html += "<div class=\"table-title\">" + tableInfo.name + "</div>"
        if (tableInfo.players.length == 0) {
            html += "<div class=\"table-subtitle\">No players</div>"
        } else {
            const names = tableInfo.players.join(", ")
            html += "<div class=\"table-subtitle\">" + names + "</div>"
        }
        html += "</div>" // table-row
    }
    setTableListContent(html)
}

function dealCards() {
    const token = loadSessionToken()
    if (token == null) {
        showLoginPage()
        return
    }
    performDealCardsRequest(token)
    .catch(showAlertWithError)
}

function playCard(card) {
    const token = loadSessionToken()
    if (token == null) {
        showLoginPage()
        return
    }
    performPlayCardRequest(token, card)
    .catch(function(error) {
        console.log(error)
    })
}

function setDisplayStyle(id, style) {
    document.getElementById(id).style.display = style
}

function hide(elementId) {
    setDisplayStyle(elementId, "none")
}

function showTableName(name) {
    document.getElementById(elementIdTableName).innerHTML = name
}

function showConnectedState() {
    showPlayerState("bottom", "")
}

function showDisconnectedState() {
    showPlayerDisconnected("bottom")
}

function setEmptyPlayerInfo(position) {
    setTablePlayerName(position, null, false)
    showPlayerState(position, "")
    setTableCard(position, "", 1)
}

function setTablePlayerName(position, name, active) {
    const nameElement = document.getElementById("table-player-name-" + position)
    if (name == null) {
        nameElement.style.color = "var(--secondary-text-color)"
        nameElement.innerHTML = missingPlayerText
    } else {
        nameElement.style.color = active ?  "var(--button-color)" : "var(--text-color)"
        nameElement.innerHTML = name
    }
}

function showPlayerDisconnected(position) {
    setPlayerState(position, "var(--alert-color)", offlineText)
}

function showPlayerState(position, state) {
    setPlayerState(position, "var(--secondary-text-color)", state)
}

function setPlayerState(position, color, text) {
    const connectionElement = "table-player-state-" + position
    const element = document.getElementById(connectionElement)
    element.style.color = color
    element.innerHTML = text
}

function setTableCard(position, card, layer) {
    const id = "table-player-card-" + position
    setCard(id, card, layer)
}

function setHandCard(index, card, playable) {
    const id = "player-card" + index.toString()
    setCard(id, card, 1)
    const button = document.getElementById(id)
    if (playable) {
        button.disabled = false
        button.onclick = function() {
            playCard(card)
        }
    } else {
        button.disabled = true
        button.onclick = function() { }
    }
}

function setCard(id, card, layer) {
    const element = document.getElementById(id)
    if (card == "") {
        element.style.backgroundColor = "var(--element-background)"
        element.style.backgroundImage = ""
        element.style.zIndex = 0

    } else {
        element.style.backgroundColor = ""
        element.style.backgroundImage = "url('cards/" + card + ".jpeg')"
        element.style.zIndex = layer + 1
    }
}

function updateTableInfo(table) {
    showTableName(table.name)
    // Set own cards
    const cardCount = table.cards.length
    for (let i = 0; i < cardCount; i += 1) {
        const card = table.cards[i]
        setHandCard(i+1, card.card, card.playable)
    }
    for (let i = cardCount; i < 8; i += 1) {
        setHandCard(i+1, "", false)
    }

    let playedGame = null
    if (table.hasOwnProperty("game")) {
        playedGame = textForAction(table.game)
    }

    // Show player info
    console.log(table)
    setInfoForPlayer(table.player, "bottom", playedGame)
    if (table.playerSelectsGame) {
        setActionsForOwnPlayer(table.playableGames)
        showAvailableGames([])
    } else {
        if (table.player.active) {
            showAvailableGames(table.playableGames)
        } else {
            showAvailableGames([])
        }
        setActionsForOwnPlayer(table.actions)
    }
    if (table.hasOwnProperty("playerLeft")) {
        setInfoForPlayer(table.playerLeft, "left", playedGame)
    } else {
        setEmptyPlayerInfo("left")
    }
    if (table.hasOwnProperty("playerAcross")) {
        setInfoForPlayer(table.playerAcross, "top", playedGame)
    } else {
        setEmptyPlayerInfo("top")
    }
    if (table.hasOwnProperty("playerRight")) {
        setInfoForPlayer(table.playerRight, "right", playedGame)
    } else {
        setEmptyPlayerInfo("right")
    }
    if (table.hasOwnProperty("summary")) {
        setGameSummary(table.summary)
    } else {
        hideGameSummary()
    }
}

function setGameSummary(summary) {
    document.getElementById(elementIdGameSummary).innerHTML = summary.text
    setDisplayStyle(elementIdGameSummary, "inherit")
}

function hideGameSummary() {
    hide(elementIdGameSummary)
}

function setInfoForPlayer(player, position, game) {
    var card = ""
    if (player.hasOwnProperty("card")) {
        card = player.card
    }
    const layer = player.position
    setTableCard(position, card, layer)
    setTablePlayerName(position, player.name, player.active)

    var state = player.state
    if (game != null && state.indexOf("selects") > -1) {
        const i = state.indexOf("selects")
        state[i] = game
    }

    const text = state.map(x => convertStateToString(x)).join("<br>")
    showPlayerState(position, text)
}

function doubleText(doubles) {
    if (doubles == 0) {
        return null
    }
    if (doubles == 1) {
        return "gedoppelt"
    }
    return doubles.toString() + "x gedoppelt"
}

function clearInfoForPlayer(position) {
    setEmptyPlayerInfo(position)
}

function setActionsForOwnPlayer(actions) {
    var len = actions.length
    var html = ""
    for (let i = 0; i < len; i += 1) {
        const action = actions[i]
        const content = textForAction(action)
        html += "<button class=\"standard-button action-button\" " +
        "onclick=\"performAction('" + action + "')\">" + content + "</button>"
    }
    document.getElementById(elementIdActionBar).innerHTML = html
}

function textForAction(action) {
    switch (action) {
        /// The player can request cards to be dealt
        case "deal":
        return "Austeilen"

        /// The player doubles on the initial four cards
        case "double":
        return "Legen"

        /// The player does not double on the initial four cards
        case "skip":
        return "Nicht legen"

        /// The player offers a wedding (one trump card)
        case "wedding":
            return "Hochzeit anbieten"

        /// The player can choose to accept the wedding
        case "accept":
            return "Hochzeit akzeptieren"

        /// The player matches or increases the game during auction
        case "bid":
            return "Spielen"

        /// The player does not want to play
        case "out":
            return "Weg"

        /// The player claims to win and doubles the game cost ("schießen")
        case "raise":
        return "Schießen"

        case "ruf":
        return "Ruf"
        case "ruf-eichel":
        return "Ruf Eichel"
        case "ruf-blatt":
        return "Ruf Blatt"
        case "ruf-schelln":
        return "Ruf Schelln"
        case "bettel":
        return "Bettel"
        case "wenz":
        return "Wenz"
        case "geier":
        return "Geier"
        case "solo":
        return "Solo"
        case "solo-eichel":
        return "Eichel Solo"
        case "solo-blatt":
        return "Blatt Solo"
        case "solo-herz":
        return "Herz Solo"
        case "solo-schelln":
        return "Schelln Solo"
    }
    return action
}

function performAction(action) {
    const token = loadSessionToken()
    if (token == null) {
        showBlankLogin()
        return
    }
    performPlayerActionRequest(token, action)
    // TODO: Handle errors and success
}

function showAvailableGames(games) {
    var len = games.length
    var html = ""
    for (let i = 0; i < len; i += 1) {
        const game = games[i]
        const content = textForAction(game)
        html += "<div class=\"standard-button available-game\">" + content + "</div>"
    }
    document.getElementById(elementIdAvailableGamesList).innerHTML = html
}
