/**
 * Detect connected BFDs/QBDs and determine if they have webservers
 * 
 * @category Webserver
 * @package ATProcessor
 * @author Caio Borgo
 * @version 0.1
 * 
 */

class BFDServerStatusModel extends ObservableModel 
{
    constructor() 
    {
        super();

        this.displays = []; // Connected displays
    }

    deviceConnected(serial)
    {
        const device = this.displays.find((element) => element.device.toLowerCase() == serial.toLowerCase());
        if (device)
        {
            if (device.type == "QBD")
            {
                // Enough that we recieved a response to the version request
                return device.software.length > 0;
            }
            else if (device.type == "BFD")
            {
                // Must have a response from the webserver
                if (device.hasOwnProperty('webserver') && device.webserver)
                {
                    let version = device.software.split('.');
                    if (version.length >= 2)
                    {
                        // Software version must be higher than 2.24
                        return (parseInt(version[0]) >= 2) && (parseInt(version[1]) >= 24);
                    }
                }
            }
        }

        return false;
    }

    init() 
    {
        let self = this;

        $.when(readSection("Display"), readSection("BFDNames"), getServerMillis()).done(
            function(displaySection, bfdNamesSection, milliJSON) 
        {
            const displays = JSON.parse(displaySection[0]);
            const names = JSON.parse(bfdNamesSection[0]);
            const milliseconds = JSON.parse(milliJSON[0]);

            // Returns are array of device objects
            // { device: <serial>, instance: <instance>, type: <QBD/BFD>, ipaddress: <IP> }
            let availableDisplays = ParseConnectedDisplays(displays, milliseconds);
            let async = [];
            for (let display of availableDisplays)
            {
                let address = 'http://' + display.ipaddress;

                if (display.type == "BFD")
                {
                    // Detect whether a BFD has a webserver (that is, operating system is updated to include lighttpd)
                    // There are not many without, but they do exist
                    async.push($.ajax( 
                    {
                        url: 'bfdServerFinder.php',
                        type: 'GET',
                        data:
                        {
                            action: 'isWebServerAvailable', 
                            query: address 
                        },
                        success: function(responseJSON)
                        {
                            let response = JSON.parse(responseJSON);
        
                            if (response.status && response.result)
                            {
                                display.webserver = true;
                            }
                        },
                        error: function(jqXHR, textStatus, errorThrown)
                        {
                            console.log("Error sending HTTP request to check BFD status!");
                            console.log("" + errorThrown + ": " + textStatus);
                        }
                    }));
                }
                else display.webserver = true; // QBDs always have a webserver

                async.push($.ajax(
                {
                    url: 'helpers.php',
                    type: 'POST',
                    data: { 
                        action: 'queryBFD', 
                        bfdAddress: address,
                        query: 'version=true'
                    },
                    success: function(response)
                    {
                        display.software = response;
                    },
                    error: function(jqXHR, textStatus, errorThrown)
                    {
                        console.log("Error sending HTTP request to check BFD version!");
                        console.log("" + errorThrown + ": " + textStatus);
                    }
                }));    
            }

             // Ensure the loading box appears for at least 1.5 seconds
            let deferred = new $.Deferred();
            setTimeout(deferred.resolve, 1500);
            async.push(deferred.promise());

            $.when.apply($, async).always(function()
            {
                for (let display of availableDisplays)
                {
                    const serial = display.device.toLowerCase();
                    if (names.hasOwnProperty(serial))
                    {
                        display.name = names[serial];
                    }
                }

                self.displays = availableDisplays;

                $('#display-configuration-loading-box').hide();

                self.notifyAll();
            });
        });
    }

    writeBFDNameToDatabase(serial) 
    {
        const device = this.displays.find((element) => element.device.toLowerCase() == serial.toLowerCase());
        if (device)
        {
            return writeToDatabase([{'section': 'BFDNames', 'key': serial, 'value': device.name}], "");
        }
    }
}

class BFDServerStatusController extends BasicController 
{
    constructor(model) 
    {
        super(model);
    }

    changeBFDName(e) 
    {
        let serial = $(e.target).attr('data-serial');

        let device = this.model.displays.find((element) => element.device.toLowerCase() == serial.toLowerCase());
        if (device)
        {
            device.name = $(e.target).val();
        }
    }

    applyNewBFDName(e)
    {
        let serial = $(e.target).attr('data-serial');
        this.model.writeBFDNameToDatabase(serial);
    }

    goToBFDPage(e)
    {
        let serial = $(e.target).attr('data-serial');
        let device = this.model.displays.find((element) => element.device.toLowerCase() == serial.toLowerCase());
        if (device)
        {
            let serverAddressArr = device.ipaddress ? device.ipaddress.split("."): [];    
            let redirectLink; 
            
            if (device.type == "QBD")
            {
                // We're expecting to always redirect
                // But if we don't receive a response from the QBD webserver we whould throw an error instead
                if (serverAddressArr.length == 4 && this.model.deviceConnected(serial))
                {
                    redirectLink = "/bfd/" + serverAddressArr[2] + "/" + serverAddressArr[3] + "/";
                }
                else
                {
                    // Display user message
                    $('#dialog-text').text("Communication Error: Unable to load display configuration.\n"
                        + "If error persists, restart display."
                    );
                    $('#dialog').dialog( {
                        title: "Communication Error",
                        buttons: {
                            Ok : function() {
                                $(this).dialog("close");
                            }
                        }
                    }).dialog( "open" );

                    return;
                }
            }  
            else if (serverAddressArr.length == 4 && this.model.deviceConnected(serial))
            {
                redirectLink = "/bfd/" + serverAddressArr[2] + "/" + serverAddressArr[3] + "/";
            }
            else
            {
                redirectLink = "dataPages.php?bfd=" + serial;
            }

            window.location.assign(redirectLink);
        }
    }
}

class BFDServerStatusView extends BasicView 
{
    constructor(controller) 
    {
        super(controller);

        this.controller.model.init();
    }

    bindEvents() 
    {
        super.bindEvents();

        $('#bfd-configuration').on('change', '.bfd-name-input', this.controller.changeBFDName.bind(this.controller));
        $('#bfd-configuration').on('click', '.bfd-name-apply-button', this.controller.applyNewBFDName.bind(this.controller));
        $('#bfd-configuration').on('click', '.bfd-configure-button', this.controller.goToBFDPage.bind(this.controller));
    }

    update(model) 
    {
        console.log(model);

        if (model.displays.length == 0)
        {
            $('#bfd-configuration').append(
                    '<div id="no-bfd" class="box loading-box">'
                +       '<div>No Displays Detected</div>'
                +   '</div>'
            );
        }
        else
        {
            model.displays.forEach(function(display)
            {
                // If display has a webserver, and version >= 2.24
                let bfdName = display.name || display.device;
                let bfdSoftwareVer = display.software || "Unknown";

                let bfdInfo = '<div class="box box top-wrapper bfd-info-container">'
                            +   '<fieldset class="bfd-info-box">' 
                            +       '<div class="bfd-info-row">'
                            +           '<h2> Serial Number: ' + display.device + '</h2>'
                            +           '<h2> Software Version: ' + (bfdSoftwareVer || 'n/a') + '</h2>'
                            +       '</div>'
                            +       '<div class="bfd-info-row">'
                            +           '<div class="bfd-info-name-item">'
                            +               '<h2> Friendly Name:</h2>'
                            +               '<input type="text" class="bfd-name-input" data-serial="' + display.device + '" value="' + bfdName + '">'
                            +               '<a class="button button-gray button-medium bfd-name-apply-button" data-serial="' + display.device + '">Apply</a>'
                            +           '</div>'
                            +           '<a class="button button-gray button-large bfd-configure-button" data-serial="' + display.device + '">Configure</a>'
                            +       '</div>'
                            +   '</fieldset>'
                            + '</div>';

                $('#bfd-configuration').append(bfdInfo);
            });
        }
    }
}
