/**
 * Model, View, Controller for system time page.
 * 
 * @category    Webserver
 * @package     ATProcessor
 * @author      Cameron Guest <cameron@aandtinstruments.com>
 * @version     0.1
 */

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

        this.data = 
        {
            "auto": "",
            "source": "",
            "instance": "1",
            "timezoneoffset": "0",
            "uniqueid": "0"
        };

        this.nmeaPorts = [];
        this.listOfCanDevices = [];
    }

    get instance()
    {
        return this.data.instance;
    }
    set instance(instance)
    {
        this.data.instance = instance;
    }

    get offset()
    {
        return this.data.timezoneoffset;
    }
    set offset(offset)
    {
        this.data.timezoneoffset = parseInt(offset);
    }

    get source()
    {
        return this.data.source;
    }
    set source(source)
    {
        this.data.source = source;
    }

    get sync()
    {
        return Boolean(this.data.auto);
    }

    set sync(sync)
    {
        this.data.auto = Boolean(sync);
    }

    get uniqueid() { return this.data.uniqueid; }
    set uniqueid(id) { this.data.uniqueid = id; }

    init()
    {
        let self = this;

        $.when(readSection("Time Source"), readSingle("NMEA", "Channels"),
            readSingle("CanSource", "System Time")).done(
            function(timeResponse, nmeaResponse, canResponse)
        {
            let async = [];

            if (timeResponse)
            {
                try
                {
                    self.data = $.extend({}, self.data, JSON.parse(timeResponse[0]));
                }
                catch (e)
                {
                    // Just use the default data
                }
            }

            if (nmeaResponse)
            {
                let ports = nmeaResponse[0].split(';');

                ports.forEach(function(port)
                {
                    async.push(readSingle("NMEA" + port, "Name").done(function(nameResponse)
                    {
                        self.nmeaPorts.push(
                            {
                                "instance" : port,
                                "name": (nameResponse || "Unknown Port " + port)
                            }
                        )
                    }));
                })
            }

            if (canResponse)
            {
                let devices = canResponse[0].split(';');

                devices.forEach(function(device)
                {
                    if (device == "") return;

                    async.push(readSection("CanDevices:" + device).done(function(deviceResponse)
                    {
                        try
                        {
                            let p = JSON.parse(deviceResponse);

                            self.listOfCanDevices.push({
                                "uniqueid": device,
                                "model": p.model,
                                "address": p.address,
                                "serial": p.serialnumber
                            });
                        }
                        catch (e)
                        {
                            // Just don't store the device
                        }
                    }));
                });
            }

            $.when.apply($, async).then(function()
            {
                // Sort NMEA ports alphanumerically
                self.nmeaPorts.sort(function(a, b)
                {
                    return a.name.toLowerCase() > b.name.toLowerCase();
                })

                // If selected uniqueid isn't present, add a dummy device
                if (self.data.uniqueid && self.listOfCanDevices.find(device => device.uniqueid === self.data.uniqueid) === undefined)
                {
                    self.listOfCanDevices.push({
                        "uniqueid": self.data.uniqueid,
                        "model": "Unconnected Device",
                        "address": "0",
                        "serial": self.data.uniqueid
                    })
                }
                
                self.notifyAll();
            })
        });
    }

    persistData()
    {
        let databaseArray = [];

        databaseArray.push({'section': 'Time Source', 'key': 'auto', 'value': this.data.auto});
        databaseArray.push({'section': 'Time Source', 'key': 'instance', 'value': this.data.instance});
        databaseArray.push({'section': 'Time Source', 'key': 'source', 'value': this.data.source});
        databaseArray.push({'section': 'Time Source', 'key': 'timezoneoffset', 'value': this.data.timezoneoffset});
        databaseArray.push({'section': 'Time Source', 'key': 'uniqueid', 'value': this.data.uniqueid});

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

class TimeController extends BasicController {

    constructor(model) {
        super(model);
    }

    changeCANDevice(e)
    {
        this.model.uniqueid = $(e.target).val();
        // Notify so that field instances are updated
        this.model.notifyAll();
    }

    changeNMEAPort(e)
    {
        this.model.instance = $(e.target).val();

        this.model.notifyAll();
    }

    changeOffset(e)
    {
        validateRange( $(e.target), 0, -12, 14, 0 );
        this.model.offset = $(e.target).val();
    }

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

        this.model.notifyAll();
    }

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

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

    setTime(e)
    {
        let newDate;
        let newTime;

        if ($('#date-input').inputmask("isComplete"))
        {
            $('#date-input').css('border-color', '');
            newDate = $('#date-input').val();
        }
        else
        {
            $('#date-input').css('border-color', 'red');
            newDate = undefined;
        }

        if ($('#time-input').inputmask("isComplete"))
        {
            $('#time-input').css('border-color', '');
            newTime = $('#time-input').val();
        }
        else
        {
            $('#time-input').css('border-color', 'red');
            newTime = undefined;
        }

        if (newDate && newTime)
        {
            $.ajax({
                url: '/helpers.php',
                type: 'POST',
                data: {
                    action: 'queryProcessor',
                    query: 'Time=' + newTime + '&Date=' + newDate
                },
                success: function(response)
                {
                    if (response.includes('OK'))
                    {
                        $('#dialog-text').text('System date and time updated. You may \
                        notice a momentary loss of data as the system synchronises.');
                        $('#dialog').dialog( {
                        title: "Date/Time Updated",
                        buttons:
                        {
                            Ok : function()
                            {
                                $(this).dialog("close");
                            }
                        }
                        }).dialog( "open" );
                    }
                    else
                    {
                        $('#dialog-text').text('Failed to update system date and time.');
                        $('#dialog').dialog( {
                            title: "Date/Time Update Failed",
                            buttons: 
                            {
                                Ok : function()
                                {
                                    $(this).dialog("close");
                                }
                            }
                        }).dialog( "open" );
                    }
                }
            });
        }
    }

    toggleSync(e)
    {
        this.model.sync = $(e.target).prop('checked');

        this.model.notifyAll();
    }
}

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

        $(':input').inputmask();

        this.controller.model.init();
    }

    bindEvents()
    {
        super.bindEvents();

        $('#set-time').on('click', this.controller.setTime.bind(this.controller));
        $('#sync-enable').on('change', this.controller.toggleSync.bind(this.controller));
        $('#timezone-offset').on('change', this.controller.changeOffset.bind(this.controller));

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

        $('#input-type-container').on('change', '#nmea-port-select', this.controller.changeNMEAPort.bind(this.controller));
        $('#input-type-container').on('click', '#nmea-configuration-redirect', this.controller.redirectNMEA.bind(this.controller));
        $('#input-type-container').on('change', '#can-devices', this.controller.changeCANDevice.bind(this.controller));
    }

    drawCanbusContainer(model)
    {
        let optionString = "<option value='0' data-address='0'>No Device</option>";
        model.listOfCanDevices.forEach(function(device)
        {
            let name = (device.model || "") + " [" + (device.serial || "") + "]";

            optionString += "<option value='" + device.uniqueid + "' data-address='" + device.address + "'>" + name + "</option>";
        });

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

        let selected = model.listOfCanDevices.find(device => device.uniqueid == model.uniqueid);
        let address = selected ? selected.address : "";

        $('#source-time').attr('data-instance', address);

        $('#input-type-container').show();
    }

    drawNMEAContainer(model)
    {
        let optionString = "<option value='0'>No Interface</option>";
        if (model.nmeaPorts.length > 0)
        {
            optionString = "";
            model.nmeaPorts.forEach(function(port)
            {
                optionString += "<option value='" + port.instance + "'>" + port.name + "</option>"
            });
        }

        $('#input-type-container').append(
                '<div class="flex-heading">'
            +       '<h2>NMEA Port:</h2>'
            +   '</div>'
            +   '<select id="nmea-port-select">'
            +       optionString
            +   '<select>'
            +   '<a class="button button-gray button-medium redirect-button" id="nmea-configuration-redirect">NMEA0183 Settings</a>'
        );
        $('#nmea-port-select').children('option[value="' + model.instance + '"]').prop('selected', true);

        $('#source-time').attr('data-instance', $('#nmea-port-select option:selected').val());

        $('#input-type-container').show();
    }

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

        $('#timezone-offset').val(model.offset);
        $('#sync-enable').prop('checked', model.sync);

        $('#input-source option[value="' + model.source + '"]').prop('selected', true);
        $('#source-time').attr('data-sender', model.source);

        $('#input-type-container').empty();
        switch (model.source)
        {
            case "NMEA0183":
                this.drawNMEAContainer(model);
                break;

            case "CANbus":
                this.drawCanbusContainer(model);
                break;

            default:
                $('#input-type-container').hide();
                break;
        }

        if (model.sync)
        {
            $('#time-input').val('');
            $('#time-input').prop('disabled', 'disabled');
            $('#date-input').val('');
            $('#date-input').prop('disabled', 'disabled');
            $('#set-time').prop('disabled', 'disabled');
        }
        else
        {
            $('#time-input').prop('disabled', '');
            $('#date-input').prop('disabled', '');
            $('#set-time').prop('disabled', '');
        }
    }
}