(function () {
    var chosenServer = IO_SERVERS[0]; // Is the array even necessary for the ACP?

    var opts = {
        secure: chosenServer.secure,
        withCredentials: true // needed for sio cookie to work
    };

    window.socket = io.connect(chosenServer.url, opts);

    window.socket.on("connect", function () {
        window.socket.emit("initACP");
        window.socket.emit("acp-list-activechannels");
        readEventlog();
    });

    window.socket.on("errMessage", function (data) {
        alert(data.msg);
    });
})();

function addMenuItem(target, text) {
    var ul = $("#nav-acp-section ul");
    var li = $("<li/>").appendTo(ul);
    var a = $("<a/>").attr("href", "javascript:void(0)")
        .text(text)
        .appendTo(li)
        .click(function () {
            $(".acp-panel").hide();
            $(target).show();
        });
};

addMenuItem("#acp-logview", "Log Viewer");
addMenuItem("#acp-announcements", "Announcements");
addMenuItem("#acp-global-bans", "Global Bans");
addMenuItem("#acp-user-lookup", "Users");
addMenuItem("#acp-channel-lookup", "Channels");
addMenuItem("#acp-loaded-channels", "Active Channels");
addMenuItem("#acp-eventlog", "Event Log");

/* Log Viewer */
function readSyslog() {
    $.ajax(location.protocol + "//" + location.host + "/acp/syslog").done(function (data) {
        $("#acp-log").text(data);
        $("#acp-log").scrollTop($("#acp-log").prop("scrollHeight"));
    });
}

function readErrlog() {
    $.ajax(location.protocol + "//" + location.host + "/acp/errlog").done(function (data) {
        $("#acp-log").text(data);
        $("#acp-log").scrollTop($("#acp-log").prop("scrollHeight"));
    });
}

function readHttplog() {
    $.ajax(location.protocol + "//" + location.host + "/acp/httplog").done(function (data) {
        $("#acp-log").text(data);
        $("#acp-log").scrollTop($("#acp-log").prop("scrollHeight"));
    });
}

function readEventlog() {
    $.ajax(location.protocol + "//" + location.host + "/acp/eventlog").done(function (data) {
        handleEventLog(data);
    });
}

function readChanlog(name) {
    $.ajax(location.protocol + "//" + location.host + "/acp/chanlog/" + name).done(function (data) {
        $("#acp-log").text(data);
        $("#acp-log").scrollTop($("#acp-log").prop("scrollHeight"));
    });
}

$("#acp-syslog-btn").click(readSyslog);
$("#acp-errlog-btn").click(readErrlog);
$("#acp-httplog-btn").click(readHttplog);
$("#acp-chanlog-name").keyup(function (ev) {
    if (ev.keyCode === 13) {
        readChanlog($("#acp-chanlog-name").val());
    }
});

/* Announcements */
$("#acp-announce-submit").click(function () {
    socket.emit("acp-announce", {
        title: $("#acp-announce-title").val(),
        content: $("#acp-announce-content").val()
    });
});

socket.on("announcement", function (data) {
    $("#acp-announcements").find(".announcement").remove();

    var signature = "<br>\u2014" + data.from;
    var al = makeAlert(data.title, data.text + signature)
        .removeClass("col-md-12")
        .addClass("announcement")
        .insertAfter($("#acp-announcements h3")[0]);

    al.find(".close").click(function () {
        socket.emit("acp-announce-clear");
    });

    $("#acp-announce-title").val(data.title);
    $("#acp-announce-content").val(data.text);
});

/* Global bans */
$("#acp-gban-submit").click(function () {
    socket.emit("acp-gban", {
        ip: $("#acp-gban-ip").val(),
        note: $("#acp-gban-note").val()
    });
});

socket.on("acp-gbanlist", function (bans) {
    var tbl = $("#acp-global-bans table");
    tbl.find("tbody").remove();

    bans.forEach(function (b) {
        var tr = $("<tr/>").appendTo(tbl);
        var td = $("<td/>").appendTo(tr);
        var del = $("<button/>").addClass("btn btn-xs btn-danger")
            .html("<span class='glyphicon glyphicon-trash'></span>")
            .click(function () {
                socket.emit("acp-gban-delete", b);
            })
            .appendTo(td);

        td = $("<td/>").appendTo(tr).html("<code>" + b.ip + "</code>");
        td = $("<td/>").appendTo(tr).text(b.note);
    });
});

/* User listing */
(function () {
    var doSearch = function () {
        if ($("#acp-ulookup-query").val().trim() === "") {
            if (!confirm("You are about to list the entire users table. " +
                         "This table might be very large and take a long " +
                         "time to query.  Continue?")) {
                return;
            }
        }
        socket.emit("acp-list-users", {
            value: $("#acp-ulookup-query").val(),
            field: $(this).data()["field"]
        });
    };

    $("#acp-ulookup-btn-name").click(doSearch);
    $("#acp-ulookup-btn-email").click(doSearch);
    $("#acp-ulookup-query").keyup(function (ev) {
        if (ev.keyCode === 13) {
            $("#acp-ulookup-btn-name").click();
        }
    });
})();

socket.on("acp-list-users", function (users) {
    var tbl = $("#acp-user-lookup table");
    tbl.data("entries", users);
    var p = tbl.data("paginator");
    if (p) {
        p.paginator.remove();
    }

    var opts = {
        preLoadPage: function () {
            tbl.find("tbody").remove();
        },

        generator: function (u, page, index) {
            var tr = $("<tr/>").appendTo(tbl);
            tr.attr("title", u.name + " joined on " + new Date(u.time) + " from IP " + u.ip);
            $("<td/>").text(u.id).appendTo(tr);
            $("<td/>").text(u.name).appendTo(tr);
            var rank = $("<td/>").text(u.global_rank).appendTo(tr);
            $("<td/>").text(u.email).appendTo(tr);
            var reset = $("<td/>").appendTo(tr);

            // Rank editor
            rank.click(function () {
                if (rank.find(".rank-edit").length > 0) {
                    return;
                }

                var old = rank.text();
                rank.text("");

                var editor = $("<input/>").addClass("rank-edit form-control")
                    .attr("type", "text")
                    .attr("placeholder", old)
                    .appendTo(rank)
                    .focus();

                var save = function () {
                    var newrank = editor.val();
                    if (newrank.trim() === "") {
                        newrank = old;
                    }

                    rank.text(old);
                    if (newrank === old) {
                        return;
                    }

                    socket.emit("acp-set-rank", {
                        name: u.name,
                        rank: parseInt(newrank)
                    });

                };

                editor.blur(save);
                editor.keydown(function (ev) {
                    if (ev.keyCode === 13) {
                        save();
                    }
                });
            });

            // Password reset
            $("<button/>").addClass("btn btn-xs btn-danger")
                .text("Reset password")
                .click(function () {
                    if (!confirm("Really reset password for " + u.name + "?")) {
                        return;
                    }
                    socket.emit("acp-reset-password", {
                        name: u.name,
                        email: u.email
                    }, function (result) {
                        if (result.error) {
                            modalAlert({
                                title: "Error",
                                textContent: result.error
                            });
                        } else {
                            var link = new URL("/account/passwordrecover/" + result.hash,
                                    new URL(location));
                            modalAlert({
                                title: "Reset Link",
                                textContent: link
                            });
                        }
                    });
                }).appendTo(reset);
        }
    };

    p = Paginate(users, opts);
    p.paginator.css("margin-top", "20px");
    p.paginator.insertBefore(tbl);
    tbl.data("paginator", p);
});

socket.on("acp-set-rank", function (data) {
    var table = $("#acp-user-lookup table");
    var p = table.data("paginator");
    var e = table.data("entries");
    if (e) {
        for (var i = 0; i < e.length; i++) {
            if (e[i].name === data.name) {
                e[i].rank = data.rank;
                break;
            }

        }
        if (p) {
            p.items = e;
        }
    }

    table.find("td:contains('" + data.name + "')")
        .parent()
        .children()[2]
        .innerHTML = data.rank;
});

/* Channel listing */
(function () {
    var doSearch = function () {
        if ($("#acp-clookup-value").val().trim() === "") {
            if (!confirm("You are about to list the entire channels table. " +
                         "This table might be very large and take a long " +
                         "time to query.  Continue?")) {
                return;
            }
        }
        socket.emit("acp-list-channels", {
            field: $("#acp-clookup-field").val(),
            value: $("#acp-clookup-value").val()
        });
    };

    $("#acp-clookup-submit").click(doSearch);
    $("#acp-clookup-value").keyup(function (ev) {
        if (ev.keyCode === 13) {
            doSearch();
        }
    });
})();

socket.on("acp-list-channels", function (channels) {
    var tbl = $("#acp-channel-lookup table");
    tbl.data("entries", channels);
    var p = tbl.data("paginator");
    if (p) {
        p.paginator.remove();
    }

    var opts = {
        preLoadPage: function () {
            tbl.find("tbody").remove();
        },

        generator: function (c, page, index) {
            var tr = $("<tr/>").appendTo(tbl);
            tr.attr("title", c.name + " was registered on " + new Date(c.time));
            $("<td/>").text(c.id).appendTo(tr);
            $("<td/>").text(c.name).appendTo(tr);
            $("<td/>").text(c.owner).appendTo(tr);
            $("<td/>").text(c.last_loaded).appendTo(tr);
            $("<td/>").text(c.owner_last_seen).appendTo(tr);
            var remove = $("<td/>").appendTo(tr);

            // Drop channel
            $("<button/>").addClass("btn btn-xs btn-danger")
                .text("Delete channel")
                .click(function () {
                    if (!confirm("Really delete " + c.owner + "/" + c.name + "?")) {
                        return;
                    }
                    socket.emit("acp-delete-channel", {
                        name: c.name,
                    });
                }).appendTo(remove);
        }
    };

    p = Paginate(channels, opts);
    p.paginator.css("margin-top", "20px");
    p.paginator.insertBefore(tbl);
    tbl.data("paginator", p);
});

socket.on("acp-delete-channel", function (data) {
    var table = $("#acp-channel-lookup table");
    var p = table.data("paginator");
    var e = table.data("entries");
    var found = -1;
    if (e) {
        for (var i = 0; i < e.length; i++) {
            if (e[i].name === data.name) {
                found = i;
                break;
            }

        }

        if (found > 0) {
            e.splice(found, 1);
        }

        if (p) {
            p.items = e;
        }
    }

    table.find("td:contains('" + data.name + "')")
        .parent()
        .remove();
});

/* Active channels */

function showChannelDetailModal(c) {
    var wrap = $("<div/>").addClass("modal fade").appendTo($("body"));
    var dialog = $("<div/>").addClass("modal-dialog").appendTo(wrap);
    var content = $("<div/>").addClass("modal-content").appendTo(dialog);
    var head = $("<div/>").addClass("modal-header").appendTo(content);
    $("<button/>").addClass("close")
        .attr("data-dismiss", "modal")
        .attr("data-hidden", "true")
        .html("&times;")
        .appendTo(head);
    $("<h4/>").addClass("modal-title").text(c.name).appendTo(head);

    var body = $("<div/>").addClass("modal-body").appendTo(content);

    var table = $("<table/>").addClass("table table-striped table-compact")
        .appendTo(body);
    var tr;

    tr = $("<tr/>").appendTo(table);
    $("<td/>").text("Page Title").appendTo(tr);
    $("<td/>").text(c.pagetitle).appendTo(tr);

    tr = $("<tr/>").appendTo(table);
    $("<td/>").text("Current Media").appendTo(tr);
    $("<a/>").attr("href", c.mediaLink).text(c.mediatitle).appendTo(
        $("<td/>").appendTo(tr)
    );

    tr = $("<tr/>").appendTo(table);
    $("<td/>").text("User Count").appendTo(tr);
    $("<td/>").text(c.usercount).appendTo(tr);

    tr = $("<tr/>").appendTo(table);
    $("<td/>").text("User List").appendTo(tr);
    $("<td/>").text(c.users.join(" ")).appendTo(tr);

    tr = $("<tr/>").appendTo(table);
    $("<td/>").text("Registered").appendTo(tr);
    $("<td/>").text(c.registered).appendTo(tr);

    tr = $("<tr/>").appendTo(table);
    $("<td/>").text("Public").appendTo(tr);
    $("<td/>").text(c.public).appendTo(tr);

    tr = $("<tr/>").appendTo(table);
    $("<td/>").text("ActiveLock Count").appendTo(tr);
    $("<td/>").text(c.activeLockCount).appendTo(tr);

    tr = $("<tr/>").appendTo(table);
    $("<td/>").text("Chat Filter Count").appendTo(tr);
    $("<td/>").text(c.chatFilterCount).appendTo(tr);

    tr = $("<tr/>").appendTo(table);
    $("<td/>").text("Emote Count").appendTo(tr);
    $("<td/>").text(c.emoteCount).appendTo(tr);

    $("<h3/>").text("Recent Chat").appendTo(body);
    $("<pre/>").text(c.chat.map(function (data) {
        var msg = "<" + data.username;
        if (data.addClass) {
            msg += "." + data.addClass;
        }
        msg += "> " + data.msg;

        msg = "[" + new Date(data.time).toTimeString().split(" ")[0] + "] " + msg;
        return msg;
    }).join("\n")).appendTo(body);

    wrap.on("hidden.bs.modal", function () {
        wrap.remove();
    });

    wrap.modal();
}

socket.on("acp-list-activechannels", function (channels) {
console.log(channels[0]);
    var tbl = $("#acp-loaded-channels table");
    tbl.find("tbody").remove();

    channels.sort(function (a, b) {
        if (a.usercount === b.usercount) {
            var x = a.name.toLowerCase();
            var y = b.name.toLowerCase();
            return x === y ? 0 : (x > y ? 1 : -1);
        }

        return a.usercount > b.usercount ? -1 : 1;
    });

    var count = 0;
    channels.forEach(function (c) {
        var tr = $("<tr/>").appendTo(tbl);
        var name = $("<td/>").appendTo(tr);
        $("<a/>").attr("href", `/${CHANNELPATH}/${c.name}`)
            .text(c.pagetitle + ` (/${CHANNELPATH}/${c.name})`)
            .appendTo(name);
        var usercount = $("<td/>").text(c.usercount).appendTo(tr);
        count += c.usercount;
        var nowplaying = $("<td/>").text(c.mediatitle).appendTo(tr);
        var registered = $("<td/>").text(c.registered).appendTo(tr);
        var public = $("<td/>").text(c.public).appendTo(tr);
        var controlOuter = $("<td/>").appendTo(tr);
        var controlInner = $("<div/>").addClass("btn-group").appendTo(controlOuter);
        $("<button/>").addClass("btn btn-default btn-xs")
            .html("<span class='glyphicon glyphicon-list-alt'></span>")//.text("Details")
            .attr("title", "Details")
            .appendTo(controlInner)
            .click(function () {
                showChannelDetailModal(c);
            });
        $("<button/>").addClass("btn btn-danger btn-xs")
            .html("<span class='glyphicon glyphicon-remove'></span>")//.text("Force Unload")
            .attr("title", "Unload")
            .appendTo(controlInner)
            .click(function () {
                if (confirm(`Are you sure you want to unload /${CHANNELPATH}/${c.name}?`)) {
                    socket.emit("acp-force-unload", {
                        name: c.name
                    });
                }
            });
    });

    var total = $("<tr/>").appendTo(tbl);
    $("<td/>").html("<strong>Total</strong>").appendTo(total);
    $("<td/>").html("<strong>" + count + "</strong>").appendTo(total);
    $("<td/>").appendTo(total);
    $("<td/>").appendTo(total);
    $("<td/>").appendTo(total);
    $("<td/>").appendTo(total);
});

$("#acp-lchannels-refresh").click(function () {
    socket.emit("acp-list-activechannels");
});

/* Event log */

function getEventKey(line) {
    var left = line.indexOf("[", 1);
    var right = line.indexOf("]", left);
    return line.substring(left+1, right);
}

function handleEventLog(data) {
    data = data.split("\n").filter(function (ln) { return ln.indexOf("[") === 0; });
    var keys = {};
    data.forEach(function (ln) {
        keys[getEventKey(ln)] = true;
    });

    $("#acp-eventlog-text").data("lines", data);

    $("#acp-eventlog-filter").html("");
    for (var k in keys) {
        $("<option/>").attr("value", k)
            .text(k)
            .appendTo($("#acp-eventlog-filter"));
    }

    filterEventLog();
}

function filterEventLog() {
    var selected = $("#acp-eventlog-filter").val();
    var all = selected == null || selected.length === 0;
    var lines = $("#acp-eventlog-text").data("lines");
    var show = [];
    lines.forEach(function (ln) {
        if (all || selected.indexOf(getEventKey(ln)) !== -1) {
            show.push(ln);
        }
    });

    $("#acp-eventlog-text").text(show.join("\n"));
    $("#acp-eventlog-text").scrollTop($("#acp-eventlog-text").prop("scrollHeight"));
}

$("#acp-eventlog-filter").change(filterEventLog);
$("#acp-eventlog-refresh").click(readEventlog);

/* Initialize keyed table sorts */
$("table").each(function () {
    var table = $(this);
    var sortable = table.find("th.sort");
    sortable.each(function () {
        var th = $(this);
        th.click(function () {
            var p = table.data("paginator");
            if (!p) {
                return;
            }
            var key = th.attr("data-key");
            if (!key) {
                return;
            }
            var asc = -th.attr("data-sort-direction") || -1;
            th.attr("data-sort-direction", asc);
            var entries = table.data("entries") || [];
            entries.sort(function (a, b) {
                return a[key] === b[key] ? 0 : asc*(a[key] > b[key] ? 1 : -1);
            });
            table.data("entries", entries);
            p.items = entries;
            p.loadPage(0);
        });
    });
});
