/**
 * Class definitions for Wind Corrections page.
 * 
 * @category Webserver
 * @package ATProcessor
 * @author Sam Meredith <sam@aandtinstruments.com>
 * @version 1.07
 * 
 */

const WIND_TABLE_COLUMN_COUNT = 7;
const WIND_TABLE_ROW_COUNT = 8;
const DEFAULT_WIND_CORRECTIONS = [
    [45, 45, 45, 45, 45, 45, 45],
    [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
    [90, 90, 90, 90, 90, 90, 90],
    [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
    [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
    [145, 145, 145, 145, 145, 145, 145],
    [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
    [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
];

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

        this.correctionData = [];
        // The index of the sensor being displayed
        this.currentSensorIndex = 0;
        this.sensors = [];
    }

    get currentSensorSource()
    {
        // split() handles wind boards which are saved as "Wind Board:<Instance>"
        return this.sensors[this.currentSensorIndex]["source"].split(':')[0];
    }

    get currentSensorInstance()
    {
        return this.sensors[this.currentSensorIndex]["instance"];
    }

    init()
    {
        let self = this;

        readSection('settings').done(function(settingsSection)
        {
            let settings = JSON.parse(settingsSection);

            let sensorCount = 1;
            if (settings.windinputs !== undefined) sensorCount = parseInt(settings.windinputs) || 1;

            let async = [];
            for (let i = 0; i < sensorCount; i++)
            {
                // Read the sensor configuration and correction table for each source
                let sensorSection = "windsource" + i;
                let correctionTableSection = "wind correction table:" + i;

                async.push($.when(readSection(sensorSection), readSection(correctionTableSection)).done(function(sensorResult, correctionResult)
                {
                    if (sensorResult && sensorResult[0])
                    {
                        try
                        {
                            self.sensors[i] = JSON.parse(sensorResult[0]);
                        }
                        catch (e)
                        {
                            console.log(e);
                        }
                    }

                    if (correctionResult && correctionResult[0])
                    {
                        try
                        {
                            let parsed = JSON.parse(correctionResult[0]);
                            let columnArray = [
                                parsed["otws.5"].split(';'),
                                parsed["otws.10"].split(';'),
                                parsed["otws.15"].split(';'),
                                parsed["otws.20"].split(';'),
                                parsed["otws.25"].split(';'),
                                parsed["otws.30"].split(';'),
                                parsed["otws.35"].split(';')
                            ];

                            // Transpose the column-wise array (and convert to floats at the same time)
                            self.correctionData[i] = columnArray[0].map((_, i) => columnArray.map((_, j) => parseFloat(columnArray[j][i]) || 0.0));
                        }
                        catch (e)
                        {
                            self.correctionData[i] = DEFAULT_WIND_CORRECTIONS;
                        }
                    }
                    else
                    {
                        self.correctionData[i] = DEFAULT_WIND_CORRECTIONS;
                    }
                }));
            }

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

    persistData()
    {
        let databaseArray = new Array();
        let self = this;

        self.correctionData.forEach(function(data, sensorIndex)
        {
            // Transpose the array back to columns
            let transposed = data[0].map((_, i) => data.map((_, j) => data[j][i]));
            transposed.forEach(function(column, columnIndex)
            {
                let key = "otws." + ((columnIndex + 1) * 5);
                databaseArray.push(
                    { 
                        'section': "Wind Correction Table:" + sensorIndex,
                        'key': "otws." + ((columnIndex + 1) * 5),
                        'value': column.join(';')
                    }
                )
            });
        });

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

class WindCorrectionController extends BasicController
{
    constructor(model)
    {
        super(model)
    }

    changeCorrection(e)
    {
        // Ignore the title row
        let row = $(e.target).closest('tr').index() - 1;
        // Ignore the first two columns
        let column = $(e.target).parent().index() - 2;

        if ((row >= 0 && row < WIND_TABLE_ROW_COUNT) &&
         (column >= 0 && column < WIND_TABLE_COLUMN_COUNT))
        {
            // Validate the input based on row
            if (row == 4 || row == 7)
            {
                // TWS % correction
                validateRange($(e.target), 1, -30, 30, 0);
            } 
            else if (row == 0)
            {
                // Upwind is between 0 and 90
                validateRange($(e.target), 1, 0, 89, 45);
            } 
            else if (row == 2)
            {
                // Reaching is always 90
                validateRange($(e.target), 1, 90, 90, 90);
            }
            else if (row == 5)
            {
                // Downwind is between 91 and 180
                validateRange($(e.target), 1, 91, 180, 145);
            }
            else if (row == 1 || row == 3 || row == 6)
            {
                // TWA correction
                validateRange($(e.target), 1, -20, 20, 0);
            }

            // Deliberately split up this way to handle the (erroneous) case where the row does not exist
            let rowData = this.model.correctionData[this.model.currentSensorIndex][row] || [ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 ];
            rowData[column] = $(e.target).val();
            this.model.correctionData[this.model.currentSensorIndex][row] = rowData;
        }
    }

    changeCurrentSensor(e)
    {
        this.model.currentSensorIndex = $(e.target).val();
        this.model.notifyAll();
    }
}

class WindCorrectionView extends BasicView
{
    constructor(controller)
    {
        super(controller)

        this.controller.model.init();
    }

    bindEvents()
    {
        super.bindEvents();

        $('#correction-container').on('change', '#input-select', this.controller.changeCurrentSensor.bind(this.controller));
        $('#correction-container').on('change', '#wind-table input', this.controller.changeCorrection.bind(this.controller));
    }

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

        $('#title').text('Wind Calculations');

        // Draw the sensor select
        if (model.sensors.length > 1)
        {
            $('#input-select').empty();

            model.sensors.forEach(function(sensor, index)
            {
                $('#input-select').append(
                    '<option value="' + index + '">Wind Input ' + (index + 1) + ' - ' + sensor.name + '</option>'
                );
            });

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

        // Populate the table
        $('#wind-table input').each(function(index, element)
        {
            // Ignore the title row
            let row = $(element).closest('tr').index() - 1;
            // Ignore the first two columns
            let column = $(element).parent().index() - 2;

            if ((row >= 0 && row < WIND_TABLE_ROW_COUNT) &&
             (column >= 0 && column < WIND_TABLE_COLUMN_COUNT))
            {
                let corrections = model.correctionData[model.currentSensorIndex];
                // Old versions of the processor only had 7 rows
                // Although the extra row should be added by the processor, it is safer to explicitly check here
                let correctionRow = corrections[row] || [ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 ];
                $(element).val(correctionRow[column]);
            }
        });

        // Update Fields
        $('.field-container[data-source="source"]').attr('data-sender', model.currentSensorSource);
        $('.field-container[data-source="source"]').attr('data-instance', model.currentSensorInstance);
    }
}
