/**
 * Display handlers for sensor inputs.
 * 
 * @category Webserver
 * @package ATProcessor
 * @author Sam Meredith <sam@aandtinstruments.com>
 * @version 0.1
 * 
 */

/**
 * Common sensor functionality
 */
class SensorView extends BasicView {
    constructor(controller) {
        super(controller);

	    $('.page-title > h1').html(this.controller.model.sensorType + " Input " +  (parseInt(this.controller.model.sensorNumber) + 1));

        //Capture default widget states
        this.canbusDeviceWidget = $('#canbus-device-container').clone();
        this.nmeaPortSelectionWidget = $('#nmea-instance-selection-container').clone();
        this.sourceSelectionWidget = $('#source-selection-container').clone();

        this.controller.model.init();
    }

    bindEvents() {
        super.bindEvents();

        $('#canbus-device-container').on('click', '#canbus-configuration-redirect', this.controller.canbusRedirect.bind(this.controller));
        $('#source-selection-container').on('change', '#sensor-name', this.controller.changeName.bind(this.controller));
        $('#source-selection-container').on('change', '#sensor-source-select', this.controller.changeSource.bind(this.controller));
        $('#nmea-instance-selection-container').on('click', '#nmea-configuration-redirect', this.controller.nmeaRedirect.bind(this.controller));
        $('#nmea-instance-selection-container').on('change', '#nmea-instance-select', this.controller.changeInstance.bind(this.controller));
    
        $('#canbus-device-container').on('change', '#can-devices', this.controller.changeCanbusDevice.bind(this.controller));
    }

    // Displays the currently selected CANbus device, highlights if the device is not available
    drawCANbusDeviceWidget(model) {
        $('#canbus-device-container').html(this.canbusDeviceWidget.html());

        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>";
        });

        $('#canbus-device-container').append(
                '<div>'
            +       '<div class="flex-row">'
            +           '<div class="flex-heading">'
            +               '<h2>CANbus Device:</h2>'
            +           '</div>'
            +           '<select id="can-devices">'
            +               optionString
            +           '<select>'
            +       '</div>'
            +   '</div>'
        );

        $('#can-devices').find('option[value="' + model.uniqueid + '"]').prop('selected', true);

        // Note: this assumes that "0" is not a valid address (which is the value of sensorInstance, in this case), 
        // implying that it could only be the result of selecting "No Device" or an "Unconnected Device".
        if (model.sensorInstance === "0")
            $('#can-devices').addClass('bad-source');

        $('#canbus-device-container').show();
    }

    // Populate available NMEA0183 devices
    drawNMEAPortSelectionWidget(model) {
        $('#nmea-instance-selection-container').html(this.nmeaPortSelectionWidget.html());

        var nmeaDevice = model.availableSources.find(source => (source.internalName == dataSouceDisplayNames.NMEA.toLowerCase()));
        nmeaDevice.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);

        $('#nmea-instance-select').find('option[value="' + model.sensorInstance + '"]').prop('selected', true);
        $('#nmea-instance-selection-container').show();
    }

    // Populate sensor names and sources
    drawSourceSelectionWidget(model) {
        $('#source-selection-container').html(this.sourceSelectionWidget.html());

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

    // Clear widgets ready for redraw
    resetView() {
        $('#canbus-device-container').empty();
        $('#nmea-instance-selection-container').empty();
        $('#source-selection-container').empty();
    }

    update(model) {
        this.resetView();

        if (model.widgets['displaySourceSelection']) {
            this.drawSourceSelectionWidget(model);
        }
        if (model.widgets['displayNMEAPortSelection']) {
            this.drawNMEAPortSelectionWidget(model);
        }
        if (model.widgets['displayCANbusDevice']) {
            this.drawCANbusDeviceWidget(model);
        }
    }
}

/**
 * Speed sensor-specific functionality
 */
class SpeedSensorView extends SensorView {
    constructor(controller) {
        super(controller);

        //Capture default widget state
        this.dataCalibrationWidget = $('#data-calibration-container').clone();
        this.pulseCalibrationWidget = $('#pulse-calibration-container').clone();
        this.sogWidget = $('#sog-container').clone();
    }

    bindEvents() {
        super.bindEvents();

        $('#data-calibration-container').on('change', '#calibration-factor', this.controller.changeCalibrationFactor.bind(this.controller));
        $('#speed-page').on('click', '[name="advanced-calibration"]', this.controller.correctionRedirect.bind(this.controller));
        $('#pulse-calibration-container').on('change', '#pulse-calibration', this.controller.changePulseCalibration.bind(this.controller));
        $('#pulse-calibration-container').on('change', '#computation-estimator', this.controller.changeComputationEstimator.bind(this.controller));
        $('#sog-container').on('click', '#use-sog', this.controller.toggleSoG.bind(this.controller));
    }

    // Shared functionality for CANbus and NMEA0183 inputs - speed arrives as a value in kts
    drawDataCalibrationWidget(model) {
        $('#data-calibration-container').html(this.dataCalibrationWidget.html());

        $('#calibration-factor').val(model.calibrationFactor);

        $('#calibrated-speed').attr('data-field', '0x26' + (parseInt(model.sensorNumber) + 1) + '1');
        $('#data-calibration-container .field-container').not('#calibrated-speed').attr('data-sender', model.sensorSource);
        $('#data-calibration-container .field-container').not('#calibrated-speed').attr('data-instance', model.sensorInstance);

        $('#data-calibration-container').show();
    }

    // Functionality for direct inputs Speed/SpeedDepth boards - speed arrives as pulses
    drawPulseCalibrationWidget(model) {
        $('#pulse-calibration-container').html(this.pulseCalibrationWidget.html());

        $('#pulse-calibration').val(model.pulseCalibration);
        $('#computation-estimator').val(model.computationEstimator);

        $('#displayed-speed').attr('data-field', '0x26' + (parseInt(model.sensorNumber) + 1) + '1');
        $('#pulse-frequency').attr('data-field', '0x26' + (parseInt(model.sensorNumber) + 1) + '2');
        $('#pulse-calibration-container .field-container').not('#displayed-speed, #pulse-frequency').attr('data-sender', model.sensorSource);
        $('#pulse-calibration-container .field-container').not('#displayed-speed, #pulse-frequency').attr('data-instance', model.sensorInstance);

        $('#pulse-calibration-container').show();
    }

    // Use SOG as boat speed. If selected, other configuration is disabled
    drawSoGWidget(model) {
        $('#sog-container').html(this.sogWidget.html());

        $('#use-sog').prop('checked', model.useSoG);
        if (model.useSoG == true) {
            $('input, select').not('#use-sog').prop('disabled', true);
            $('#use-sog').css('outline', '1px solid red');
        }
        $('#sog-container').show();
    }

    // Clear widgets ready for redraw
    resetView() {
        super.resetView();

        $('#data-calibration-container').empty();
        $('#pulse-calibration-container').empty();
        $('#sog-container').empty();
    }

    update(model) {
        super.update(model);
        
        if (model.widgets['displayPulseCalibration']) {
            this.drawPulseCalibrationWidget(model);
        }
        if (model.widgets['displayDataCalibration']) {
            this.drawDataCalibrationWidget(model);
        }
        if (model.widgets['displaySoGToggle']) {
            this.drawSoGWidget(model);
        }
    }
}

/**
 * Depth sensor-specific functionality
 */
class DepthSensorView extends SensorView {
    constructor(controller) {
        super(controller);
        this.minDepthWidget = $('#min-depth-container').clone();
    }

    bindEvents() {
        super.bindEvents();
        $('#source-selection-container').on('change', '#offset', this.controller.changeDatumValue.bind(this.controller));
        $('#min-depth-container').on('change', '#min-depth', this.controller.changeMinDepth.bind(this.controller));
    }

    drawSourceSelectionWidget(model) {
        super.drawSourceSelectionWidget(model);
        $('#offset').val(model.datum);
    }

    drawMeasuredDataWidget(model) {
        $('#measured-value-container .field-container').attr('data-sender', model.sensorSource.split(':')[0]);
        $('#measured-value-container .field-container').attr('data-instance', model.sensorInstance);  
    }

    drawMinDepthWidget(model) {
        $('#min-depth-container').html(this.minDepthWidget.html());
        $('#min-depth').val(model.activeSource.minDepth);
    }

    resetView() {
        super.resetView();
        $('#min-depth-container').empty();
    }

    update(model) {
        super.update(model);
        this.drawMeasuredDataWidget(model);

        if (model.widgets['displayMinDepth']) {
            this.drawMinDepthWidget(model);
        }
    }
}


/**
 * Wind sensor-specific functionality
 */
class WindSensorView extends SensorView {
    constructor(controller) {
        super(controller);

        //Capture default widget state
        this.heelCorrectionWidget = $('#heel-correction-container').clone();
        this.measuredDataWidget = $('#measured-value-container').clone();
        this.modalContainer = $('#modal-container').clone();
        this.pulseCalibrationWidget = $('#pulse-calibration-container').clone();
    }

    bindEvents() {
        super.bindEvents();

        $('#pulse-calibration-container').on('change', '#pulse-calibration', this.controller.changePulseCalibration.bind(this.controller));
        $('#pulse-calibration-container').on('change', '#calc-time', this.controller.changeComputationEstimator.bind(this.controller));
        $('#measured-value-container').on('change', '#calibration-factor', this.controller.changeCalibrationFactor.bind(this.controller));
        $('#measured-value-container').on('change', '#speed-offset', this.controller.changeSpeedOffset.bind(this.controller));
        $('#measured-value-container').on('change', '#mhu-offset', this.controller.changeMHUOffset.bind(this.controller));
        $('#measured-value-container').on('change', '#wind-shear', this.controller.changeWindShear.bind(this.controller));
        $('#measured-value-container').on('change', '#motion-speed-checkbox', this.controller.toggleMastMotionSpeedCorrection.bind(this.controller));
        $('#measured-value-container').on('change', '#motion-angle-checkbox', this.controller.toggleMastMotionAngleCorrection.bind(this.controller));
        $('#modal-container').on('change', '#mast-rotation-source', this.controller.changeMastRotationSource.bind(this.controller));
        $('#modal-container').on('change', '#sensor-height', this.controller.changeSensorHeight.bind(this.controller));
        $('#modal-container').on('click', '#mast-rotation-checkbox', this.controller.toggleMastRotation.bind(this.controller));
        $('#measured-value-container').on('click', '#mast-motion-button', this.controller.mastMotionRedirect.bind(this.controller));
        $('#heel-correction-container').on('click', '#heel-speed-checkbox', this.controller.toggleHeelSpeedCorrection.bind(this.controller));
        $('#heel-correction-container').on('click', '#heel-angle-checkbox', this.controller.toggleHeelAngleCorrection.bind(this.controller));
        $('#wind-measured').on('click', '[name="advanced-calibration"]', this.controller.correctionRedirect.bind(this.controller));
    }

    // Heel correction configuration - common to all sensor types
    drawHeelCorrectionWidget(model) {
        $('#heel-correction-container').html(this.heelCorrectionWidget.html());

        $('#heel-speed-checkbox').prop('checked', model.heelSpeedCorrection);
        $('#heel-angle-checkbox').prop('checked', model.heelAngleCorrection);

        $('#heel-correction-container .field-container').not('#heel-angle').attr('data-sender', model.sensorSource.split(':')[0]);
        $('#heel-correction-container .field-container').not('#heel-angle').attr('data-instance', model.sensorInstance);

        $('#heel-correction-container').show();
    }

    // Raw data calibration 
    drawMeasuredDataWidget(model) {
        $('#measured-value-container').html(this.measuredDataWidget.html());

        $('#speed-offset').val(model.speedOffset);
        $('#mhu-offset').val(model.mhuOffset);
        $('#wind-shear').val(model.windShear);
        $('#calibration-factor').val(model.calibrationFactor);

        if (model.widgets['displayPulseCalibration']) {
            $('#speed-offset-container').removeClass('hidden');
        }

        //Mast Rotation
        $('#modal-container').html(this.modalContainer.html());
        $('#mast-rotation-checkbox').prop('checked', model.mastRotation);
        model.mastRotationSources.forEach(function(source) {
            $('#mast-rotation-source').append(
                '<option value="' + source.internalName + '">' + source.displayName + '</option>'
            );
        });
        $('#mast-rotation-source option[value="' + model.mastRotationSource.internalName + '"]').prop('selected', true);

        $('#motion-angle-checkbox').prop('checked', model.mastMotionAWAEnabled);
        $('#motion-speed-checkbox').prop('checked', model.mastMotionAWSEnabled);

        $('#sensor-height').val(model.mastHeight);
        $('#modal-container').show();

        $('#mast-rotation').attr('data-field', model.mastRotationSource.mastRotationField);
        $('#mast-rotation').attr('data-sender', model.mastRotationSource.internalName.split(':')[0]);
        if (model.mastRotation) {
            $('#mast-rotation').attr('data-instance', model.mastRotationSource.internalName.split(':')[1]);
        } else {
            $('#mast-rotation').attr('data-instance', -1);
        }
        
        //Non-mast rotation fields
        $('#measured-value-container .field-container').not('#mast-rotation').attr('data-sender', model.sensorSource.split(':')[0]);
        $('#measured-value-container .field-container').not('#mast-rotation').attr('data-instance', model.sensorInstance);

        $('#measured-value-container').show();
    }

    // Initial pulse calibration - specific to direction speed inputs
    drawPulseCalibrationWidget(model) {
        $('#pulse-calibration-container').html(this.pulseCalibrationWidget.html());

        $('#pulse-calibration').val(model.pulseCalibration);
        $('#calc-time').val(model.computationEstimator);

        $('#pulse-calibration-container .field-container').attr('data-sender', model.sensorSource.split(':')[0]);
        $('#pulse-calibration-container .field-container').attr('data-instance', model.sensorInstance);

        $('#pulse-calibration-container').show();
    }

    // Clear widgets ready for redraw
    resetView() {
        super.resetView();

        $('#heel-correction-container').empty().hide();
        $('#measured-value-container').empty().hide();
        $('#modal-container').empty().hide();
        $('#pulse-calibration-container').empty().hide();
    }

    update(model) 
    {
        super.update(model);

        if (model.widgets['displayPulseCalibration']) {
            this.drawPulseCalibrationWidget(model);
        }
        if (model.widgets['displayMeasuredData']) {
            this.drawMeasuredDataWidget(model);
        }
        if (model.widgets['displayHeelCorrection']) {
            this.drawHeelCorrectionWidget(model);
        }
        if (model.widgets['displayNonPulseCalibration']) {
            $('#calibration-factor-container').css('display', 'flex');
            $('#speed-offset-container').css('display', 'none');
        }
        if (model.widgets['displayMastMotion']) {
            $('#motion-correction-container').show();
            $('.mast-motion-row').css('display', 'flex');
        }
    }
}