/**
 * Class definitions for BFD Splash page.
 * 
 * @category Webserver
 * @package ATProcessor
 * @author Cameron Guest <cameron@aandtinstruments.com>
 * @version 0.1
 * 
 */

const MAX_WIDTH = 1280;  // Max image width.
const MAX_HEIGHT = 1280; // Max image height.
const IMAGE_TYPES = [ 'jpg', 'jpeg', 'png', 'xbm' ]; // Valid image extensions.

class SplashModel extends ObservableModel {
    
    get configuration()
    {
        return this.displayData[this.activeDisplay] || DEFAULT_CONFIG;
    }

    constructor(serial)
    {
        super();

        this.activeDisplay = serial || "0"; //!< The display being configured
        this.displays = [];
        this.displayData = {};
        this.bfdDisplayNames = new Object();          //!< BFD Friendly Names (serial number -> user-given name)

        this.init();
    }

    init()
    {
        let self = this;

        $.when(
            readSection("Display"),
            readSection("BFDPageDef"),
            readSection("BFDNames"),
            getServerMillis()
        ).done(function(displayData, pageData, bfdNamesSection, timeData)
        {
            let displays = JSON.parse(displayData[0]);
            let pages = JSON.parse(pageData[0]);
            let bfdNames = JSON.parse(bfdNamesSection[0]);
            let millis = JSON.parse(timeData[0]);

            self.displays = ParseConnectedDisplays(displays, millis);
            self.displayData[0] = ParseConfig('0', pages);

            $.each(self.displays, function(_idx, display)
            {
                self.displayData[display.device] = ParseConfig(display.device.toLowerCase(), pages);
            });

            for (let serial in self.displayData) 
            {
                if (bfdNames[serial.toLowerCase()] !== undefined)
                    self.bfdDisplayNames[serial] = bfdNames[serial.toLowerCase()];
            }

            self.notifyAll();
        });
    }

    persistData()
    {
        let dbArray = [];

        $.each(this.displayData, function(key, value)
        {
            dbArray.push({ 'section': 'BFDPageDef', 'key': key, 'value': JSON.stringify(value) });
        })

        return writeToDatabase(dbArray, 'PageDefs');
    }
}

class SplashController extends BasicController 
{
    // Send AJAX request to set the splash on the display matching this serial number.
    sendToggleSplash(display, toggle)
    {
        $.ajax({
            type: 'POST',
            url: '/helpers.php',
            data: {
                action: 'queryProcessor',
                query: 'splash=' + toggle + '&display=' + display
            }
        });
    }

    // Show the splash screen on the selected display.
    clickShow(e)
    {
        let display = $('#display-select').val();
        if (display !== '0')
            this.sendToggleSplash(display, true);
    }

    // Hide the splash screen on the selected display.
    clickHide(e)
    {
        let display = $('#display-select').val();
        if (display !== '0')
            this.sendToggleSplash(display, false);
    }

    // Show the splash screen on all displays.
    clickShowAll(e)
    {
        let self = this;

        $('#display-select option').each(function()
        {
            let display = $(this).val();

            if (display !== '0')
                self.sendToggleSplash(display, true);
        });
    }

    // Hide the splash screen on all displays.
    clickHideAll(e)
    {
        let self = this;

        $('#display-select option').each(function()
        {
            let display = $(this).val();

            if (display !== '0')
                self.sendToggleSplash(display, false);
        });
    }

    // Upload a new splash image.
    clickUpload(e)
    {
        if ($('#imageToUpload').prop('files').length > 0)
        {
            let file = $('#imageToUpload').prop('files')[0];
            let mime = file.name.split('.').pop().toLowerCase();

            if (IMAGE_TYPES.includes(mime))
            {
                // Read the file.
                let reader = new FileReader();
                reader.onload = function(event)
                {
                    let image = new Image();
                    image.src = event.target.result;
                    image.onload = function(event2)
                    {
                        // Check dimensions.
                        if (image.height <= MAX_HEIGHT && image.width <= MAX_WIDTH)
                        {   
                            let formData = new FormData();
                            
                            formData.append('fileToUpload', file);
                            formData.append('action', 'Splash');

                            $.ajax({
                                url: 'upload.php',
                                type: 'POST',
                                data: formData,
                                processData: false,
                                contentType: false,
                                cache: false
                            }).done(function()
                            {
                                writeSingle('BFD', 'Splash', "splash_" + file.name, 'Splash').done(function()
                                {
                                    $('#splash-set').show();
                                    $('#image-preview').prop('src', image.src);
                                });
                            });
                        }
                        else
                        {
                            alert("Image is too large.")
                        }
                    }
                }

                reader.readAsDataURL(file);
            }
            else
            {
                alert("Invalid file type.")
            }
        }
        else
        {
            alert("Please select a file to upload.");
        }

    }

    // Send the uploaded image to the selected BFD.
    clickSet(e)
    {
        if ($('#image-preview').prop('src'))
        {
            // Prompt processor
            let serial = $('#display-select').val();
            let address = $('#display-select').find(':selected').attr('device-ip');

            $.ajax({
                type: 'POST',
                url: '/helpers.php',
                data: {
                    action: 'queryProcessor',
                    query: 'BFD=SP&display=' + serial + '&ipaddress=' + address
                }
            });
        }
        else
        {
            alert("Please upload an image first.");
        }
    }

    // Change the selected BFD.
    changeActiveDisplay(e)
    {
        this.model.activeDisplay = $(e.target).val();
        this.model.notifyAll();
    }

    // Change if splash visible on data timeout.
    changeEnableTimeout(e)
    {
        this.model.configuration.splashscreen.enabled = $(e.target).prop('checked');
    }

    // Change data timeout delay.
    changeTimeoutDelay(e)
    {
        validateRange($(e.target), 0, 1, 120, 30);
        this.model.configuration.splashscreen.delay = $(e.target).val() * 1000; // convert to ms
    }

    // Change splash background colour.
    changeBackgroundColour(e)
    {
        let sync = new ColourSync();
        this.model.configuration.splashscreen.splashbackground = sync.getColour($('#config-background'));
    }

}

class SplashView extends BasicView 
{

    constructor(controller)
    {
        super(controller);
        $('#splash-set').hide();
    }

    bindEvents()
    {
        super.bindEvents();

        $('#splash-show').click(this.controller.clickShow.bind(this.controller));
        $('#splash-hide').click(this.controller.clickHide.bind(this.controller));
        $('#splash-show-all').click(this.controller.clickShowAll.bind(this.controller));
        $('#splash-hide-all').click(this.controller.clickHideAll.bind(this.controller));

        $('#splash-upload').click(this.controller.clickUpload.bind(this.controller));
        $('#splash-set').click(this.controller.clickSet.bind(this.controller));

        $('#splash-timeout-enable').change(this.controller.changeEnableTimeout.bind(this.controller));
        $('#splash-timeout-delay').change(this.controller.changeTimeoutDelay.bind(this.controller));
        $('#config-background').change(this.controller.changeBackgroundColour.bind(this.controller));
        $('#display-select').change(this.controller.changeActiveDisplay.bind(this.controller));

        this.colourSync = new ColourSync();
        this.colourSync.addWidget($('#config-background'));
    }

    update(model)
    {
        // Populate display select.
        $('#display-select').empty();

        // Include "Internal" device (serial number equals "0") in the list of select options
        let selectOptions = [{device: "0"}].concat(model.displays);
        $.each(selectOptions, function(_idx, display) {
            let deviceName;
            if (model.bfdDisplayNames.hasOwnProperty(display.device)) {
                // Set friendly name
                deviceName = model.bfdDisplayNames[display.device]; 
            }
            else if (display.device == "0") {
                // Special-case: default to "Internal" rather than serial number
                // deviceName = "Internal";
                // But we don't want to list configurations for the internal display
                return;
            }
            else {
                // Default to serial number if friendly name isn't available
                deviceName = display.device; 
            }

            $('#display-select').append('<option value="' + display.device + '">' + deviceName + '</option>');
        });

        if ($('#display-select option[value="' + model.activeDisplay + '"]').length > 0)
        {
            $('#display-select option[value="' + model.activeDisplay + '"]').prop('selected', true);
            $('#display-select').css('box-shadow', 'initial');
        }
        else
        {
            $('#display-select').append('<option value="" selected>Unknown Display</option>');
            $('#display-select').css('box-shadow', '0 0 3px #CC0000');
        }

        // Set the configuration.
        let splash = model.configuration.splashscreen;

        $('#splash-timeout-enable').prop('checked', splash.enabled);
        $('#splash-timeout-delay').val(splash.delay / 1000); // convert to ms.
        this.colourSync.setColour($('#config-background'), splash.splashbackground);
    }

}