const headingSourcePrefix = "HeadingSource";

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

        this.availableInputs = [];
        this.availableSources = [];

        this.maxInputNumber = 1;
        this.currentSelectedInput = "HeadingSource0";
        this.data = {};

        this.listOfCanDevices = [];
    }

    get inputName() {
        return this.data[this.currentSelectedInput].name;
    }

    set inputName(inputName) {
        this.data[this.currentSelectedInput].name = inputName;
    }

    get instance() {
        return this.data[this.currentSelectedInput].instance;
    }

    get source() {
        return this.data[this.currentSelectedInput].source;
    }

    set source(source) {
        this.data[this.currentSelectedInput].source = source;
        this.notifyAll();
    }

    set instance(instance) {
        this.data[this.currentSelectedInput].instance = instance;
    }

    get uniqueid()
    {
        return this.data[this.currentSelectedInput].uniqueid;
    }

    set uniqueid(uniqueid)
    {
        this.data[this.currentSelectedInput].uniqueid = uniqueid;
    }

    get offset() {
        return this.data[this.currentSelectedInput].offset;
    }

    set offset(offset) {
        this.data[this.currentSelectedInput].offset = offset;
    }

    init() {
        let self = this;

        $.when(readSingle("Heading", "SourceCount"),
               readSingle("Heading", "Default"), 
               getSources("Heading")).done(function(sourceCount, defaultHeading, getSourcesArray) {
            
            let async = [];
            
            // readSingle("Heading", "sourcecount") ---------------------------------------------------------------------
            self.maxInputNumber = Math.max(sourceCount[0], 1);
            for (let i = 0; i < self.maxInputNumber; i++) {
                async.push(readSection(headingSourcePrefix + i).done(function(HeadingSourceSection) {
                    let obj = JSON.parse(HeadingSourceSection);
                    
                    if ($.isEmptyObject(obj))
                        obj = {};

                    if (!obj.hasOwnProperty("name"))
                        obj.name = "";
                    
                    if (!obj.hasOwnProperty("instance"))
                        obj.instance = "";

                    if (!obj.hasOwnProperty("source"))
                        obj.source = "No source";
                    
                    if (!obj.hasOwnProperty("type"))
                        obj.type = "Magnetic";

                    if (!obj.hasOwnProperty("offset"))
                        obj.offset = "0";

                    if (!obj.hasOwnProperty("uniqueid"))
                        obj.uniqueid = "0";

                    self.data[headingSourcePrefix +  i] = obj;
                }));
            }

            // readSingle("Heading", "default") -------------------------------------------------------------------------
            if (defaultHeading[0].toLowerCase().startsWith(headingSourcePrefix.toLowerCase())) {
                let currentSelectedInputNumber = parseInt(defaultHeading[0].slice(headingSourcePrefix.length), 10);
                self.currentSelectedInput = headingSourcePrefix + currentSelectedInputNumber;
            }

            // getSources("Heading") ------------------------------------------------------------------------------------
            self.availableSources = getSourcesArray[0];
            self.availableSources.unshift(
                { displayName: "No Source", internalName: "no source" },
                { displayName: "ATPilot", internalName: "atpilot" }
            );

            self.listOfCanDevices = getSourcesArray[1];
            
            // ----------------------------------------------------------------------------------------------------------
            $.when.apply($, async).done(function() {

                Object.keys(self.data).forEach(source => {
                    // If uniqueid for source isn't stored in listOfCanDevices, it is probably not connected. Add it to the list.
                    if (self.data[source].uniqueid !== "" && self.data[source].uniqueid !== "0") {
                        if (self.listOfCanDevices.find(device => device.uniqueid === self.data[source].uniqueid) === undefined) {
                            self.listOfCanDevices.push({ 
                                "uniqueid" : self.data[source].uniqueid,
                                "model" : "",
                                "address" : "0",
                                "serialNumber" : "",
                                "displayName": "Unconnected Device [ID:" + self.data[source].uniqueid + "]",
                                "isConnected" : false
                            });
                        }
                    }                    
                }); 

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

    persistData() {

        var databaseArray = new Array();
        let self = this;

        // Store heading data
        for (let i = 0; i < self.maxInputNumber; i++) {
            $.each(this.data[headingSourcePrefix + i], function(key, value) {
                databaseArray.push(
                    {'section': headingSourcePrefix + i, 'key': key, 'value': value}
                );
            });
        }
        
        // Store selected heading identifier
        databaseArray.push(
            {'section': 'Heading', 'key': 'default', 'value': self.currentSelectedInput}
        );

        return writeToDatabase(databaseArray, "Heading");
    }
}

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

    changeInstance(e) {
        this.model.instance = $(e.target).val();
        this.model.notifyAll();
    }

    canbusRedirect(e) {
        window.location.href = "canFilter.php";
    }

    changeSource(e) {
        this.model.source = $(e.target).val();
        this.model.notifyAll();
    }

    nmeaRedirect(e) {
        window.location.href = "nmeaFilter.php";
    }

    changeInput(e) {
        this.model.currentSelectedInput = $(e.target).val();
        this.model.notifyAll();
    }

    changeInputName(e) {
        this.model.inputName = $(e.target).val();
    }

    changeCanbusDevice(e) {
        this.model.uniqueid = $(e.target).val();
        this.model.notifyAll();
    }

    compassCalibrationRedirect(e) {
        window.location.href = '/headingCorrections.php?src=' + this.model.currentSelectedInput.slice(headingSourcePrefix.length);
    }

    changeOffset(e) {
        validateRange( $('#offset'), 1, -180, 180, 0 );
        this.model.offset = $('#offset').val();
    }
}

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

        this.controller.model.init();
    }

    bindEvents()
    {
        super.bindEvents();

        $('#input-select-container').on('change', '#input-select', this.controller.changeInput.bind(this.controller));

        $('#input-type-select').on('change', this.controller.changeSource.bind(this.controller));

        $('#source-config-container').on('click', '#nmea-configuration-redirect', this.controller.nmeaRedirect.bind(this.controller));
        $('#source-config-container').on('change', '#nmea-instance-select', this.controller.changeInstance.bind(this.controller));

        $('#input-name').on('change', this.controller.changeInputName.bind(this.controller));

        $('#source-config-container').on('change', '#can-devices', this.controller.changeCanbusDevice.bind(this.controller));

        $('#compass-calibration').on('click', this.controller.compassCalibrationRedirect.bind(this.controller));
        
        $('#offset').on('change', this.controller.changeOffset.bind(this.controller));
    }

    drawCanbusContainer(model)
    {
        $('#source-config-container').empty();

        let optionString = "<option value='0' data-address='0'>No Device</option>";
        model.listOfCanDevices.forEach(function(device)
        {
            optionString += "<option value='" + device.uniqueid + "' data-address='" + device.address + "'>" + device.displayName + "</option>";
        });

        $('#source-config-container').append(
                '<div>'
            +       '<div class="flex-row">'
            +           '<div class="flex-heading">'
            +               '<h2>CANbus Device:</h2>'
            +           '</div>'
            +           '<select id="can-devices">'
            +               optionString
            +           '<select>'
            +       '</div>'
            +   '</div>'
        );
        
        $('#headingTrue').attr('data-sender', 'canbus');
        $('#headingMag').attr('data-sender', 'canbus');
        
        // Set selected option as the one that has been read from the database
        $('#can-devices').find('option[value="' + model.uniqueid + '"]').prop('selected', true);

        const canDevice = model.listOfCanDevices.find(device => {
            return device.uniqueid === model.uniqueid;
        });

        let address = "0";
        if (canDevice !== undefined)
        {
            address = canDevice.address;

            if (!canDevice.isConnected) $('#can-devices').addClass('bad-source');
        }
        else $('#can-devices').addClass('bad-source');

        $('#headingTrue').attr('data-instance', address);
        $('#headingMag').attr('data-instance', address);

        $('#source-config-container').show();
    }

    drawNMEAContainer(model)
    {
        $('#source-config-container').empty();
        $('#source-config-container').append(
                '<div class="flex-half">'
            +       '<div class="flex-row">'
            +           '<div class="flex-heading">'
            +               '<h2>NMEA0183 Channel:</h2>'
            +           '</div>'
            +           '<select id="nmea-instance-select"></select>'
            +       '</div>'
            +       '<a id="nmea-configuration-redirect" class="button button-gray button-medium redirect-button">NMEA0183 Settings</a>'
            +   '</div>'
        );
        $('#source-config-container').show();

        let device = model.availableSources.find(source => (source.internalName == dataSouceDisplayNames.NMEA.toLowerCase()));
        device.ports.forEach(function(port) {
            $('#nmea-instance-select').append(
                '<option value="' + port.internalName + '">' + port.displayName + '</option>'
            );
        });

        let selectedOptionObj = $('#nmea-instance-select').find('option[value="' + model.instance + '"]');
        
        if (selectedOptionObj.length == 0) {
            model.instance = $('#nmea-instance-select').val();
            selectedOptionObj = $('#nmea-instance-select').find('option[value="' + model.instance + '"]');
        }

        selectedOptionObj.prop('selected', true);
        
        $('#headingTrue').attr('data-sender', 'nmea0183');
        $('#headingMag').attr('data-sender', 'nmea0183');

        $('#headingTrue').attr('data-instance', model.instance);
        $('#headingMag').attr('data-instance', model.instance);
    }

    update(model)
    {        
        let optionString = "";
        for (let i = 0; i < model.maxInputNumber; i++) {
            optionString += "<option value='" + headingSourcePrefix + i + "'>" + "Heading " + (i + 1) + " - " + model.data[headingSourcePrefix + i].name + "</option>";
        };

        $('#input-select-container').empty();
        $('#input-select-container').append(
                '<div>'
            +       '<div class="flex-row">'
            +           '<select id="input-select">'
            +               optionString
            +           '<select>'
            +       '</div>'
            +   '</div>'
        );

        $('#input-select').find('option[value="' + model.currentSelectedInput + '"]').prop('selected', true);

        $('#input-name').val(model.inputName);

        $('#input-type-select').empty();
        model.availableSources.forEach(function(source) {
            if (source.hasOwnProperty("internalName") && source.hasOwnProperty("displayName")) {
                $('#input-type-select').append(
                    '<option value="' + source.internalName + '">' + source.displayName + '</option>'
                );
            }
        });
        let source = $('#input-type-select').find('option[value="' + model.source.toLowerCase() + '"]');
        if (source.length == 0) {
            $('#input-type-select').css('outline', '1px solid red');
        } else {
            source.prop('selected', true);
        }

        switch (model.source.toLowerCase())
        {
            case "canbus":
                this.drawCanbusContainer(model);
                break;

            case "nmea0183":
                this.drawNMEAContainer(model);
                break;

            case "atpilot":
            case "fastnet":
            default:
                $('#source-config-container').hide();
                if (model.source.includes("main interface") || model.source.includes("analogue")) {

                    $('#headingTrue').attr('data-sender',  "Processor");
                    $('#headingMag').attr('data-sender',  "Processor");

                    $('#headingTrue').attr('data-instance', 0);
                    $('#headingMag').attr('data-instance', 0);
                }
                else {
                    $('#headingTrue').attr('data-sender', model.source);
                    $('#headingMag').attr('data-sender', model.source);

                    $('#headingTrue').attr('data-instance', 0);
                    $('#headingMag').attr('data-instance', 0);
                }
                break;
        }

        $('#offset').val(model.offset);
    }
}