/**
 * BFD Settings MVC
 * 
 * Allow modification of general BFD settings. 
 * 
 * @category    Webserver
 * @package     ATProcessor
 * @author      Cameron Guest <cameron@aandtinstruments.com>
 * @version     0.1
 */

class BFDSettingsModel extends ObservableModel {

    get displayConfig() {
        return this.displayData[this.activeDisplay] || DEFAULT_CONFIG;
    }

    get lightingConfig() {
        return this.displayConfig.lighting;
    }

    get orientation() {
        return this.displayConfig.orientation;
    }
    set orientation(value) {
        this.displayConfig.orientation = value;
    }

    constructor(serial) 
    {
        super();

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

        this.init();
    }

    init() {

        let async = [];
        let self = this;

        async.push($.when(readSection("Display"), readSection("BFDPageDef"), readSection("BFDNames"), getServerMillis()).done(function(displaySection, pageSection, bfdNamesSection, milliJSON) {
            let displays = JSON.parse(displaySection[0]);
            let definitions = JSON.parse(pageSection[0]);
            let bfdNames = JSON.parse(bfdNamesSection[0]);
            let millis = JSON.parse(milliJSON[0]);

            // Get the connected displays.
            self.displays = ParseConnectedDisplays(displays, millis);

            // Get the configurations for each display.
            self.displayData[0] = ParseConfig('0', definitions);

            for (let i = 0; i < self.displays.length; i++) {
                let display = self.displays[i];
                self.displayData[display.device] = ParseConfig(display.device.toLowerCase(), definitions);
            }

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

        $.when.apply($, async).then(function() {
            self.notifyAll();
        });
    }

    persistData() {
        let self = this;
        let deferred = new $.Deferred();

        // Write configurations to database.
        if (this.configChanged) {
            let dbArray = [];

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

            writeToDatabase(dbArray, 'PageDefs').done(function() {
                deferred.resolve();
            });
        }
        else {
            deferred.resolve();
        }

        this.configChanged = false;
        return deferred.promise();
    }

    // Get a the percentage value of a lighting level.
    getLightingPercent(level) {

        let result = 0;

        $.each(this.lightingConfig, function(_idx, field) {
            if (field.level == level) {
                result = field.percent;
                return false; // Break the loop.
            }
        });
        return result;
    }

    // Set the percentage value of a lighting level.
    setLightingPercent(level, value) {
        $.each(this.lightingConfig, function(_idx, field) {
            if (field.level == level) {
                field.percent = value;
                return false; // Break the loop.
            }
        });
    }
}

class BFDSettingsController extends BasicController {

    constructor(model) {
        super(model);
    }

    onChangeActiveDisplay(e) {
        this.model.activeDisplay = $(e.target).val();
        this.model.notifyAll();
    }

    onChangeLightingLevel(e) {
        if (validateRange($(e.target), 0, 0, 100, 0)) {
            let percent = parseInt($(e.target).val());
            this.model.setLightingPercent($(e.target).attr('level'), percent);
            this.model.configChanged = true;
        }
    }

    onChangeOrientation(e) {
        this.model.orientation = $(e.target).val();
        this.model.configChanged = true;
    }

    clickSetLighting(e) {
        let display = $('#display-select').val();
        let level = $('#lighting-level-select').val();

        $.ajax({
            url: 'helpers.php',
            type: 'POST',
            data: {
                'action': 'queryProcessor',
                'query': 'lighting=' + level + '&display=' + display
            }
        });
    }
}

class BFDSettingsView extends BasicView {

    constructor(controller) {
        super(controller);
    }

    bindEvents() {

        super.bindEvents();
        $('#orientation-select').on('change', this.controller.onChangeOrientation.bind(this.controller));
        $('#display-select').on('change', this.controller.onChangeActiveDisplay.bind(this.controller));
        $('#set-lighting-level').on('click', this.controller.clickSetLighting.bind(this.controller));
        $('.input-lighting').on('change', this.controller.onChangeLightingLevel.bind(this.controller));
    }

    update(model) 
    {
        console.log(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 orientation.
        $('#orientation-select').val(model.orientation);

        // Set the lighting levels.
        $.each($('.input-lighting'), function(_idx, field) {
            $(field).val(model.getLightingPercent($(field).attr('level')));
        });
    }

}