@{
    Authorization.Require(Claims.Config.Enrolment.ShowStatus);

    ViewBag.Title = Html.ToBreadcrumb("Configuration", MVC.Config.Config.Index(), "Device Enrolment", MVC.Config.Enrolment.Index(), "Status");
    Html.BundleDeferred("~/ClientScripts/Modules/Knockout");
    Html.BundleDeferred("~/ClientScripts/Modules/jQuery-SignalR");
    Html.BundleDeferred("~/ClientScripts/Modules/jQuery-Isotope");
}
<div id="enrolStatus">
    @Html.AntiForgeryToken()
    <div id="noSessions" data-bind="visible: noSessions">
        <h2>No enrolment sessions today</h2>
    </div>
    <div id="sessions" data-bind="visible: !noSessions(), foreach: { data: sessions, afterRender: sessionRendered, afterAdd: sessionAdded }" style="display: none">
        <div class="session" data-bind="style: { backgroundImage: deviceModelImageUrl }, click: select">
            <h3>
                <span data-bind="text: title"></span>
                <span class="details" data-bind="text: '(' + deviceModelDescription() + ')'"></span>
                <span class="pending" data-bind="visible: isPending"><code data-bind="text: pendingIdentifier"></code> <i class="fa fa-exclamation-circle"></i></span>

            </h3>
            <p class="sessionStart" data-bind="text: startTime"></p>
            <p class="sessionStatus" data-bind="text: progressStatus"></p>
            <div data-bind="visible: !sessionEnded() && progressValue >= 0, progressValue: progressValue" class="sessionProgress"></div>
        </div>
    </div>
    <div id="dialogSession" data-bind="with: currentSession">
        <div class="sessionProgress clearfix">
            <p class="sessionStart" data-bind="text: startTime"></p>
            <p class="sessionStatus" data-bind="text: progressStatus"></p>
            <div data-bind="visible: !sessionEnded() && progressValue >= 0, progressValue: progressValue"></div>
            <div id="formResolveSessionPending" data-bind="visible: isPending">
                @using (Html.BeginForm(MVC.API.Enrolment.ResolveSessionPending(), FormMethod.Post))
                {
                    <code data-bind="text: pendingIdentifier"></code>
                    @Html.AntiForgeryToken();
                    <input type="hidden" name="sessionId" data-bind="value: id" />
                    <div class="reason">
                        <input type="text" name="reason" placeholder="Reason (optional)" />
                    </div>
                    <div class="buttons">
                        <button type="button" value="True" class="button">Approve</button>
                        <button type="button" value="False" class="button">Reject</button>
                    </div>
                }
            </div>
        </div>
        <div class="sessionHeader clearfix" data-bind="style: { backgroundImage: deviceModelImageUrl }">
            <h2><a href="" target="_blank" data-bind="text: title, attr: { href: deviceUrl }"></a></h2>
            <h3 data-bind="text: deviceModelDescription"></h3>
            <table data-bind="if: sessionDeviceInfo">
                <tr>
                    <th style="width: 128px">Computer Name:</th>
                    <td data-bind="text: sessionDeviceInfo().Arguments[3]"></td>
                </tr>
                <tr>
                    <th style="width: 128px">UUID:</th>
                    <td data-bind="text: sessionDeviceInfo().Arguments[2]"></td>
                </tr>
                <tr>
                    <th style="width: 128px">LAN Mac Address:</th>
                    <td data-bind="text: sessionDeviceInfo().Arguments[4]"></td>
                </tr>
                <tr>
                    <th style="width: 128px">WLAN Mac Address:</th>
                    <td data-bind="text: sessionDeviceInfo().Arguments[5]"></td>
                </tr>
                <tr>
                    <th style="width: 128px">Manufacturer/Model:</th>
                    <td data-bind="text: sessionDeviceInfo().Arguments[6] + ' ' + sessionDeviceInfo().Arguments[7]"></td>
                </tr>
            </table>
        </div>
        <div class="sessionInfoContainer clearfix">
            <div class="sessionInfoMessages">
                <table class="logEventsViewport">
                    <thead>
                        <tr>
                            <th class="icon">&nbsp;</th>
                            <th class="message">Message</th>
                        </tr>
                    </thead>
                </table>
                <div class="logEventsViewportContainer">
                    <div class="logEventsViewportNoLogs" data-bind="visible: messages().length == 0" style="display: none">No logs</div>
                    <table class="logEventsViewport" data-bind="visible: messages().length > 0" style="display: none">
                        <tbody data-bind="foreach: messages">
                            <tr>
                                <td class="icon"><i class="fa" data-bind="css: { 'fa-info-circle': EventTypeSeverity == 0, 'fa-exclamation-triangle': EventTypeSeverity == 1, 'fa-exclamation-circle': EventTypeSeverity == 2 }"></i></td>
                                <td class="message" data-bind="text: FormattedMessage, attr: { title: EventTypeName }"></td>
                            </tr>
                        </tbody>
                    </table>
                </div>
            </div>
            <div class="sessionInfoConsole" data-bind="foreach: console">
                <span data-bind="text: Arguments[1]"></span>
            </div>
        </div>
    </div>
</div>
<script type="text/javascript">
    ko.bindingHandlers.progressValue = {
        update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
            var v = ko.utils.unwrapObservable(valueAccessor());
            var vInt = parseInt(v);
            if (vInt >= 0) {
                $element = $(element);
                if (!$element.is('.ui-progressbar'))
                    $element.progressbar();
                $(element).progressbar('option', 'value', vInt);
            }
        }
    };
</script>
<script type="text/javascript">
    $(function () {
        var vm;
        var host = $('#enrolStatus');
        var hostSessions = $('#sessions');
        var hostDialogSessions = $('#dialogSession');
        //var hostDialogSessionsProgress = $('#dialogSession').find('.sessionProgress');
        var deviceModels = {};
        var logHub;
        var deviceBaseUrl = '@(Url.Action(MVC.Device.Show()))/'
        var deviceModelImageUrl = '@(Url.Action(MVC.API.DeviceModel.Image()))/'
        var iconWarningUrl = 'url(@(Links.ClientSource.Style.Images.Status.warning32_png))';
        var iconErrorUrl = 'url(@(Links.ClientSource.Style.Images.Status.fail32_png))';

        function pageViewModel() {
            var self = this;

            self.noSessions = ko.observable(true);
            self.sessions = ko.observableArray();
            self.sessionIndex = {};

            self.isotopeInited = false;

            self.currentSession = ko.observable();

            self.sessionRendered = function (e, d) {
                if (!d.sessionEnded()) {
                    d.progressbar = $(e).find('.sessionProgress').progressbar();
                }
            };
            self.sessionAdded = function (e, d) {
                if (self.isotopeInited) {
                    hostSessions.isotope('reloadItems').isotope({ sortBy: 'original-order' });
                }
            };
        }
        function sessionViewModel(id) {
            var self = this;

            self.id = id;
            self.title = ko.observable(id);
            self.isPending = ko.observable(false);
            self.pendingIdentifier = ko.observable();
            self.messages = ko.observableArray();
            self.console = ko.observableArray();
            self.serialNumber = ko.observable();
            self.sessionDeviceInfo = ko.observable();
            self.progressStatus = ko.observable();
            self.progressValue = ko.observable();
            self.startTime = ko.observable();
            self.sessionEnded = ko.observable(false);
            self.progressbar = null;
            self.hasError = ko.observable(false);
            self.hasWarning = ko.observable(false);
            self.deviceModelId = ko.observable();
            self.deviceModelDescription = ko.computed(function () {
                var deviceModelId = self.deviceModelId();
                var sessionDeviceInfo = self.sessionDeviceInfo();
                if (deviceModelId) {
                    var dm = deviceModels[deviceModelId];
                    if (dm) {
                        if (dm.Description)
                            return dm.Description;
                        else
                            return dm.Manufacturer + ' ' + dm.Model;
                    }
                }
                if (sessionDeviceInfo) {
                    return sessionDeviceInfo.Arguments[6] + ' ' + sessionDeviceInfo.Arguments[7];
                }
            });
            self.deviceUrl = ko.computed(function () {
                var serialNumber = self.serialNumber();
                if (serialNumber)
                    return deviceBaseUrl + serialNumber;
                else
                    return null;
            });
            self.deviceModelImageUrl = ko.computed(function () {
                var deviceModelImage;
                if (self.deviceModelId())
                    deviceModelImage = 'url(' + deviceModelImageUrl + self.deviceModelId() + ')';
                else
                    deviceModelImage = 'url(' + deviceModelImageUrl + ')';
                if (self.hasError())
                    return iconErrorUrl + ', ' + deviceModelImage;
                else
                    if (self.hasWarning())
                        return iconWarningUrl + ', ' + deviceModelImage;
                    else
                        return 'none, ' + deviceModelImage;
            });
            self.select = function (e, d) {
                vm.currentSession(self);
                hostDialogSessions.dialog('open');
                hostDialogSessions.dialog('option', 'title', 'Device Enrolment: ' + self.title());
            }
        }

        function parseLog(log) {
            if (log.ModuleId === 50 && log.Arguments && log.Arguments.length > 0) {
                // find session
                var sessionId = log.Arguments[0];
                var session = vm.sessionIndex[sessionId];
                if (!session && log.EventTypeId === 10) { // Starting Session (Ignore 'partial' sessions)
                    session = new sessionViewModel(sessionId);
                    vm.sessionIndex[sessionId] = session;
                    vm.sessions.unshift(session);
                    vm.noSessions(false);
                }
                if (session) {
                    switch (log.EventTypeId) {
                        case 10: // SessionStarting
                            session.title(log.Arguments[1]);
                            session.startTime(log.FormattedTimestamp.substring(log.FormattedTimestamp.indexOf(' ') + 1));
                            session.messages.unshift(log);
                            break;
                        case 11: // SessionProgress
                            //session.progressbar.progressbar('option', 'value', log.Arguments[1]);
                            session.progressValue(log.Arguments[1]);
                            session.progressStatus(log.Arguments[2]);
                            break;
                        case 12: // SessionDevice
                            session.title(log.Arguments[1]);
                            session.serialNumber(log.Arguments[1]);
                            if (log.Arguments.length >= 3 && log.Arguments[2])
                                session.deviceModelId(log.Arguments[2]);
                            break;
                            break;
                        case 13: // SessionDeviceInfo
                            session.title(log.Arguments[1]);
                            session.serialNumber(log.Arguments[1]);
                            session.sessionDeviceInfo(log);
                            if (log.Arguments.length >= 10 && log.Arguments[9])
                                session.deviceModelId(log.Arguments[9]);
                            break;
                        case 14: // SessionPending
                            session.isPending(true);
                            session.pendingIdentifier(log.Arguments[4]);
                            session.messages.unshift(log);
                            session.progressValue(-1);
                            session.progressStatus('Pending enrolment approval');
                            break;
                        case 15: // SessionPendingApproved
                            session.isPending(false);
                            session.messages.unshift(log);
                            session.progressValue(-1);
                            session.progressStatus('Enrolment approval, waiting for client');
                            break;
                        case 16: // SessionPendingRejected
                            session.isPending(false);
                            session.messages.unshift(log);
                            session.progressValue(-1);
                            session.progressStatus('Enrolment rejected, waiting for client');
                            break;
                        case 17: // SessionContinuing
                            session.isPending(false);
                            session.messages.unshift(log);
                            break;
                        case 20: // SessionFinished
                            session.sessionEnded(true);
                            session.isPending(false);
                            if (session.hasError())
                                session.progressStatus('Enrolment Finished with an Error');
                            else
                                if (session.hasWarning())
                                    session.progressStatus('Enrolment Finished with a Warning');
                                else
                                    session.progressStatus('Enrolment Finished Successfully');
                            session.messages.unshift(log);
                            break;
                        case 21: // SessionDiagnosticInformation
                            session.console.push(log);
                            break;
                        case 22: // SessionWarning
                            session.hasWarning(true);
                            session.messages.unshift(log);
                            break;
                        case 23: // SessionError
                        case 24: // SessionErrorWithInner
                        case 25: // SessionClientError
                            session.hasError(true);
                            session.messages.unshift(log);
                            break;
                        default:
                            session.messages.unshift(log);
                    }
                }
            }
        }
        function init() {
            hostDialogSessions.dialog({
                modal: true,
                height: 574,
                width: 900,
                resizable: false,
                autoOpen: false
            });
            //hostDialogSessionsProgress.progressbar();

            // Create View Model
            vm = new pageViewModel();
            $.ajax({
                url: '@(Url.Action(MVC.API.DeviceModel.Index()))',
                dataType: 'json',
                type: 'POST',
                success: init_loadedDeviceModels,
                error: function (jqXHR, textStatus, errorThrown) {
                    alert('Unable to retrieve device models: ' + errorThrown);
                }
            });
        }
        function init_loadedDeviceModels(models) {
            for (var i = 0; i < models.length; i++) {
                var m = models[i];
                deviceModels[m.Id] = m;
            }

            // Load Logs
            var d = new Date();
            var loadData = {
                Format: "json",
                Start: d.getFullYear() + '-' + (d.getMonth() + 1) + '-' + d.getDate(),
                End: null,
                ModuleId: 50,
                Take: 2000,
                '__RequestVerificationToken': host.find('input[name="__RequestVerificationToken"]').val()
            };
            $.ajax({
                url: '@(Url.Action(MVC.API.Logging.RetrieveEvents()))',
                dataType: 'json',
                type: 'POST',
                traditional: true,
                data: loadData,
                success: init_loadedLogs,
                error: function (jqXHR, textStatus, errorThrown) {
                    alert('Unable to retrieve logs: ' + errorThrown);
                }
            });
        }
        function init_loadedLogs(logs) {
            logs.reverse();
            for (var i = 0; i < logs.length; i++) {
                parseLog(logs[i]);
            }
            // Bind
            ko.applyBindings(vm);

            // Isotope
            hostSessions.isotope({
                itemSelector: '.session',
                layoutMode: 'fitRows'
            });
            vm.isotopeInited = true;

            // Init Persistent Connection
            logHub = $.connection.logNotifications;
            logHub.client.receiveLog = parseLog

            $.connection.hub.qs = { LogModules: '@(Disco.Services.Devices.Enrolment.EnrolmentLog.Current.LiveLogGroupName)' };
            $.connection.hub.error(onHubFailed);

            $.connection.hub.start()
                .done(function () { isLive = true; })
                .fail(onHubFailed);

            function onHubFailed(error) {
                // Show Dialog Message
                if ($('.disconnected-dialog').length == 0) {
                    $('<div>')
                        .addClass('dialog disconnected-dialog')
                        .html('<h3><span class="fa-stack fa-lg"><i class="fa fa-wifi fa-stack-1x"></i><i class="fa fa-ban fa-stack-2x error"></i></span>Disconnected from the Disco ICT Server</h3><div>This page is not receiving live updates. Please ensure you are connected to the server, then refresh this page to enable features.</div>')
                        .dialog({
                            resizable: false,
                            title: 'Disconnected',
                            width: 400,
                            modal: true,
                            buttons: {
                                'Refresh Now': function () {
                                    $(this).dialog('option', 'buttons', null);
                                    window.location.reload(true);
                                },
                                'Close': function () {
                                    $(this).dialog('destroy');
                                }
                            }
                        });
                }
            }
        }
        $('#dialogSession').on('click', '#formResolveSessionPending button', function (e) {
            const $button = $(this);
            const $form = $button.closest('form');
            const body = new FormData($form[0]);
            body.append('approve', $button.val());
            fetch($form.attr('action'), {
                method: 'POST',
                body: body
            }).then(function (response) {
                if (!response.ok) {
                    alert('Failed to resolve pending session: ' + response.statusText);
                }
            });
        });
        init();
    });
</script>
