{{@include("header", it)/}}


<style>
    /* Chart stuff */
    #d3-container {
        height: 340px;
        margin: auto;
        overflow: hidden;
        /* DEBUG */
        /* background-color: rgb(207, 233, 255);  */
    }
    #d3-container svg {
        height: 340px;
        width: 100%;
        margin: auto;
        overflow: hidden;
    }
    #x-axis path{
        stroke: none;
        fill: none;
    }
    #tickBucketsAxis path,
    #tickBucketsAxis line {
        stroke: none;
        fill: none;
    }
    .axis {
        color: dimgrey;
    }
    .axisTitle {
        color: dimgrey;
        font-size: 16px;
        font-weight: 500;
        margin: 2px calc(45px + 10px) 0px calc(27px + 10px);
        line-height: 1;
    }
    .axisTitle .tickTimeLabel{
        min-width: 2em;
        height: 18px;
        border: dimgrey 2px solid;
        background: rgb(35,23,27);
        /* background: linear-gradient(90deg, rgba(35,23,27,1) 10%, rgba(45,161,243,1) 35%, rgba(69,246,139,1) 65%, rgba(224,69,19,1) 90%); */
        background: linear-gradient(90deg, #482475 10%, #2f6c8e 35%, #2fb47c 65%, #bddf26 90%);
    }
    .axisTitle .clientsLabel{
        min-width: 2em;
        height: 18px;
        width: 6px;
        border: dimgrey 2px solid;
        background: rgb(204, 203, 203);
    }
    .axisTitle .labelText {
        
        margin-left: 0.2rem;
        margin-right: 1.2rem;
    }
    #chartThreadSelectBtn{
        padding: .1rem .4rem;
        font-size: .7rem;
    }
    .axisTitle .threadSelectDropdown{
        margin: 0px; position: absolute;
        inset: 0px auto auto 0px;
        transform: translate(0px, 26px);
        min-width: unset;
    }
    #d3-container-message {
        font-size: 2.25em;
        margin-top: 2em;
    }

    /* Other stuff */
    #status-card{
        font-size: 1.15rem;
        font-weight: 500;
        line-height: 2;
    }

    .dashboard-chart {
        width: 100% !important; 
        max-width: 890px !important;
    }
</style>

<!-- Title & outdated message: -->
<div class="text-center {{[(it.isWebInterface || it.txAdminOutdated), 'mb-4', '']|ternary}}">
    {{@if(it.isWebInterface)}}
        <h2>{{it.serverName}} Dashboard</h2>
    {{/if}}
    {{@if(it.txAdminOutdated)}}
        <h2 class="text-danger">This version of txAdmin is outdated. Please update now.</h2>
        <h5 class="text-muted">
            Updating is <i>very</i> easy! Support Discord:
            <a href="https://discord.gg/uAmsGa2" target="_blank" style="vertical-align: text-bottom;">
                <img src="https://discordapp.com/api/guilds/577993482761928734/widget.png?style=shield"></img>
            </a>
        </h5>
    {{/if}}
</div>


<!-- Chart stuff -->
<div class="row justify-content-center">
    <div class="dashboard-chart">
        <div class="card card-accent-info">
            <div class="card-body p-1">
                <div class="text-center axisTitle d-flex">
                    <div class="mt-1x">
                        <span class="badge clientsLabel">&nbsp;</span>
                        <span class="labelText">Players</span>
                        <span class="badge tickTimeLabel">&nbsp;</span>
                        <span class="labelText">Tick Time (at bottom is better)</span>
                    </div>

                    <div class="btn-group ml-auto">
                        <button class="btn btn-secondary btn-sm dropdown-toggle" type="button" 
                            data-toggle="dropdown" aria-haspopup="true" aria-expanded="true" id="chartThreadSelectBtn">svMain</button>
                        <div class="dropdown-menu threadSelectDropdown bg-secondary" data-popper-placement="bottom-start">
                            <a class="dropdown-item bg-secondary text-dark" href="#" id="chartThreadSelectBtn-svMain">svMain</a>
                            <a class="dropdown-item bg-secondary text-dark" href="#" id="chartThreadSelectBtn-svSync">svSync</a>
                            <a class="dropdown-item bg-secondary text-dark" href="#" id="chartThreadSelectBtn-svNetwork">svNetwork</a>
                        </div>
                    </div>
                </div>
                
                <div id="d3-container">
                    <div class="text-center text-muted p-4" id="d3-container-message">loading chart...</div>
                </div>
            </div>
        </div>
    </div>
</div>



<div class="row justify-content-center">
    <!-- Server Control -->
    <div class="col-lg-8 col-xl-6 dashboard-card mw-col6">
        <div class="card card-accent-danger" style="min-height: 200px;">
            <div class="card-header text-center">
                <h5 class="d-inline">Server Control</h5>
            </div>
            <div class="card-body text-center align-middle">
                <button onclick="controlAction('start')"
                    class="btn btn-outline-{{it.perms.controlsClass}} btn-lg mx-auto m-2" type="button" id="ctrl-start"
                    {{it.perms.controls}}>START</button> &nbsp;
                <button onclick="controlAction('restart')"
                    class="btn btn-outline-{{it.perms.controlsClass}} btn-lg mx-auto m-2" type="button"
                    id="ctrl-restart" {{it.perms.controls}}>RESTART</button> &nbsp;
                <button onclick="controlAction('stop')"
                    class="btn btn-outline-{{it.perms.controlsClass}} btn-lg mx-auto m-2" type="button" id="ctrl-stop"
                    {{it.perms.controls}}>STOP</button>
                <br>

                {{@if(it.isWebInterface)}}
                <button onclick="controlCommand('admin_broadcast')" class="btn btn-outline-dark btn-md mx-auto m-2"
                    type="button" id="ctrl-stop" {{it.perms.commandMessage}}>Announcement</button> &nbsp;
                <button onclick="controlCommand('kick_all')" class="btn btn-outline-dark btn-md mx-auto m-2"
                    type="button" id="ctrl-stop" {{it.perms.commandKick}}>Kick All Players</button>
                {{/if}}
            </div>
        </div>
    </div>

    <!-- Status Info-->
    <div class="col-lg-8 col-xl-6 dashboard-card mw-col6">
        <div class="card card-accent-danger" style="min-height: 200px;">
            <div class="card-header text-center">
                <h5 class="d-inline">Status Info</h5>
            </div>
            <div class="card-body" id="status-card">
                <br>
                <div class="text-center">
                    Loading...
                </div>
            </div>
        </div>
    </div>

</div>


<!-- Benchmark, update, pre-release messages -->
<div class="row justify-content-md-center">
    <div class="col-md-6 text-center">
        <small id="perfDiagnosticsMessage" class="text-muted"></small>
        <br>
        {{@if(it.versionData.message)}}
            <div class="alert alert-{{it.versionData.color}} border-{{it.versionData.color}}" role="alert">
                <a href="{{it.versionData.artifactsLink}}" target="_blank" class="alert-link">{{it.versionData.message}}</a>
                <br>
                {{it.versionData.subtext}}
            </div>
        {{/if}}
        {{@if(it.txAdminVersion.includes('-'))}}
            <span class="text-danger font-weight-bold">
                You are using a pre-release version of txAdmin destined for developers and beta testers only! <br>
                Your server stability might be impacted by this.
            </span>
        {{/if}}
    </div>
</div>


{{@include("footer", it)/}}

<script src="https://d3js.org/d3.v6.min.js"></script>
<script type="module">
    import { drawHeatmap } from "{{it.basePath}}js/txadmin/chart.js";

    //Elements & vars
    let perfData;
    const chartThreadSelectBtn = document.getElementById('chartThreadSelectBtn');
    const perfDiagnosticsMessage = document.getElementById('perfDiagnosticsMessage');
    const d3Container = document.getElementById('d3-container');
    const chartOptions = {
        // colorScheme: d3[`{{[it.uiTheme, 'interpolateViridis', 'interpolateTurbo']|ternary}}`],
        // colorScheme: d3.interpolateInferno,
        // colorScheme: d3.interpolateTurbo,
        colorScheme: d3.interpolateViridis,
    }

    //Draws the chart or sets the message
    const draw = (data) => {
        if(Array.isArray(data)){
            const tsStart = Date.now();
            const rects = drawHeatmap(d3Container, perfData, chartOptions);
            const duration = Date.now() - tsStart;
            perfDiagnosticsMessage.textContent = `Took ${duration}ms to draw ${rects} rects from ${perfData.length} snapshots.`;
        }else if(typeof data == 'string'){
            perfDiagnosticsMessage.textContent = '';
            d3Container.innerHTML = `<div class="text-center text-muted p-4" id="d3-container-message">${data}</div>`;
        }else{
            perfDiagnosticsMessage.textContent = '';
            d3Container.innerHTML = `<div class="text-center text-muted p-4" id="d3-container-message">unknown data type</div>`;
        }
        d3Container.style.opacity = 1;
    }

    //Sets the chart data
    const setChartThread = async (thread) => {
        console.log(`Fetching data for ${thread}`);
        chartThreadSelectBtn.textContent = thread;
        perfData = false;
        try {
            const rawPerfData = await fetch(TX_BASE_PATH + `chartData/${thread}`);
            const parsedPerfData = JSON.parse(await rawPerfData.text());
            if(Array.isArray(parsedPerfData)){
                perfData = parsedPerfData;
                draw(parsedPerfData);
            }else{
                if(parsedPerfData.failReason == 'not_set'){
                    draw('chart database still loading');
                }else if(parsedPerfData.failReason == 'not_enough_data'){
                    draw('Players & Performance chart will be available in an hour.');
                }else if(parsedPerfData.failReason == 'data_processing'){
                    draw('chart data processing failed');
                }else if(parsedPerfData.failReason == 'rate_limiter'){
                    draw('too many chart requests');
                }else{
                    draw('invalid chart data');
                }
            }
        } catch (error) {
            draw('failed to load chart data');
        }
    }
    setChartThread('svMain');
    document.getElementById('chartThreadSelectBtn-svMain').addEventListener('click', () => setChartThread('svMain'), false);
    document.getElementById('chartThreadSelectBtn-svSync').addEventListener('click', () => setChartThread('svSync'), false);
    document.getElementById('chartThreadSelectBtn-svNetwork').addEventListener('click', () => setChartThread('svNetwork'), false);

    //Every 2.5 minutes
    setInterval(() => {
        setChartThread(chartThreadSelectBtn.textContent);
    }, 2.5*60*1000);

    //Renders it again when redized
    let redrawTimeout;
    window.addEventListener("resize", () => {
        if(!perfData) return;
        clearTimeout(redrawTimeout);
        d3Container.style.opacity = 0.5;
        redrawTimeout = setTimeout(() => {
            draw(perfData);
        }, 250);
    });
</script>

<script>
    //============================================== Controls (start/restart/stop)
    async function controlAction(action) {
        const confirmOptions = {content: `Are you sure you would like to <b>${action}</b> the server?`};
        if(action !== 'start' && !await txAdminConfirm(confirmOptions)){
            return;
        }

        const notify = $.notify({ message: '<p class="text-center">Executing Command...</p>' }, {});
        txAdminAPI({
            url: '/fxserver/controls/' + action,
            type: "GET",
            dataType: "json",
            timeout: REQ_TIMEOUT_LONG,
            success: function (data) {
                if (data.logout) {
                    window.location = '/auth?logout';
                    return;
                }
                notify.update('progress', 0);
                notify.update('type', data.type);
                notify.update('message', data.message);
            },
            error: function (xmlhttprequest, textstatus, message) {
                notify.update('progress', 0);
                notify.update('type', 'danger');
                notify.update('message', message);
            }
        });
    }


    //============================================== Commands
    function controlCommand(action) {
        let message = null;
        if(action == 'admin_broadcast'){
            message = prompt('Type the message to be broadcasted to all players');
            if(message.length <= 6){
                $.notify({ message: 'This message is too short!'}, {type: 'danger'});
                return;
            }
        }else if(action == 'kick_all'){
            message = prompt('Type the kick reason or leave it blank (press enter)');
        }else{
            return;
        }
        if(message == null) return;

        const notify = $.notify({ message: 'Executing Command...' }, {});
        txAdminAPI({
            type: "POST",
            url: '/fxserver/commands',
            data: {
                action,
                parameter: message
            },
            success: function (data) {
                notify.update('progress', 0);
                notify.update('type', data.type);
                notify.update('message', data.message);
            },
            error: function (xmlhttprequest, textstatus, message) {
                notify.update('progress', 0);
                notify.update('type', 'danger');
                notify.update('message', message);
            }
        });
    }
</script>
