/**
 * @license
 * Copyright 2012 Fred Lin
 * SPDX-License-Identifier: Apache-2.0
 */

/**
 * @fileoverview Basics board command blocks for Blockly.
 * @author gasolin@gmail.com (Fred Lin)
 * @author scanet@libreduc.cc (Sébastien Canet)
 */

'use strict';

//To support syntax defined in http://arduino.cc/en/Reference/HomePage

goog.provide('Blockly.Constants.board_base');

goog.require('Blockly.Blocks');
goog.require('Blockly');

var mediaFolder = "./blocklyduino/media/";

const bitOrderDropdown = [
    [Blockly.Msg.ARDUINO_MSB, 'MSBFIRST'],
    [Blockly.Msg.ARDUINO_LSB, 'LSBFIRST']
];

Blockly.Blocks['board_base_inout_buildin_led'] = {
    init: function () {
        this.setHelpUrl(Blockly.Msg.ARDUINO_INOUT_BUILDIN_LED_HELPURL);
        this.appendDummyInput()
                .appendField(Blockly.Msg.ARDUINO_INOUT_BUILDIN_LED_INPUT)
                .appendField(new Blockly.FieldDropdown(Blockly.Msg.FIELDDROPDOWN), 'STAT');
        this.setPreviousStatement(true, null);
        this.setNextStatement(true, null);
        this.setTooltip(Blockly.Msg.ARDUINO_INOUT_BUILDIN_LED_TOOLTIP);
        this.setStyle('io_blocks');
    }
};

function attachAnalogPinWarning(workspace, blockId, analogPinValues) {
    workspace.addChangeListener(function (event) {
        if (
            event.type === Blockly.Events.BLOCK_CHANGE &&
            event.blockId === blockId &&
            event.name === "PIN" &&
            event.element === "field"
        ) {
            const pinValue = event.newValue;

            // Проверяем, является ли выбранный пин аналоговым
            if (!analogPinValues.includes(pinValue)) return;

            // Ищем другие блоки с тем же значением пина
            const duplicateExists = workspace.getAllBlocks(false).some(block => {
                return (
                    block.id !== blockId &&
                    typeof block.getField === "function" &&
                    block.getField('PIN') &&
                    block.getFieldValue('PIN') === pinValue
                );
            });

            if (!duplicateExists) {
                Blockly.alert(Blockly.Msg.ARDUINO_INOUT_DIGITAL_ANALOG_ALERT);
            }
        }
    });
}

Blockly.Blocks['board_base_inout_digital_write'] = {
    init: function () {
        const filteredDigital  = profile.default.dropdownDigital.filter(function (item) {
            return item[1] !== 'LED_BUILTIN' && item[1] !== 'BTN_BUILTIN';; // в кнопку писать не дадим, а для светодиода есть своя функция
        });
        // аналоговые пины тоже можно использовать как цифровые, добавим их в список
        const allPins = filteredDigital.concat(profile.default.dropdownAnalog || []);
        const analogPinValues = (profile.default.dropdownAnalog || []).map(item => item[1]);

        this.appendDummyInput()
                .appendField(Blockly.Msg.ARDUINO_INOUT_DIGITAL_WRITE_INPUT1)
                .appendField(new Blockly.FieldDropdown(allPins), "PIN")
                .appendField(Blockly.Msg.ARDUINO_INOUT_DIGITAL_WRITE_INPUT2)
                .appendField(new Blockly.FieldDropdown(Blockly.Msg.FIELDDROPDOWN), 'STAT');
        this.setPreviousStatement(true, null);
        this.setNextStatement(true, null);
        this.setTooltip(Blockly.Msg.ARDUINO_INOUT_DIGITAL_WRITE_TOOLTIP);
        this.setHelpUrl(Blockly.Msg.ARDUINO_INOUT_DIGITAL_WRITE_HELPURL);
        this.setStyle('io_blocks');

        // Привязываем обработчик, который будет выдавать предупреждение, если используется новый аналоговый вывод
        attachAnalogPinWarning(this.workspace, this.id, analogPinValues);
    }
};

Blockly.Blocks['board_base_inout_digital_read'] = {
    init: function () {
        // аналоговые пины тоже можно использовать как цифровые, добавим их в список
        const allPins = profile.default.dropdownDigital.concat(profile.default.dropdownAnalog || []);
        const analogPinValues = (profile.default.dropdownAnalog || []).map(item => item[1]);

        this.appendDummyInput()
                .appendField(Blockly.Msg.ARDUINO_INOUT_DIGITAL_READ_INPUT)
                .appendField(new Blockly.FieldDropdown(allPins), "PIN");
        this.setOutput(true, 'Number');
        this.setTooltip(Blockly.Msg.ARDUINO_INOUT_DIGITAL_READ_TOOLTIP);
        this.setHelpUrl(Blockly.Msg.ARDUINO_INOUT_DIGITAL_READ_HELPURL);
        this.setStyle('io_blocks');

        // Привязываем обработчик, который будет выдавать предупреждение, если используется новый аналоговый вывод
        attachAnalogPinWarning(this.workspace, this.id, analogPinValues);
    }
};

Blockly.Blocks['board_base_inout_digital_read_with_pullup'] = {
    init: function () {
        // аналоговые пины тоже можно использовать как цифровые, добавим их в список
        const allPins = profile.default.dropdownDigital.concat(profile.default.dropdownAnalog || []);
        const analogPinValues = (profile.default.dropdownAnalog || []).map(item => item[1]);

        this.appendDummyInput()
                .appendField(Blockly.Msg.ARDUINO_INOUT_DIGITAL_READ_INPUT)
                .appendField(new Blockly.FieldDropdown(allPins), "PIN")
                .appendField(Blockly.Msg.ARDUINO_INOUT_DIGITAL_READ_WITH_PULLUP_INPUT);
        this.setOutput(true, 'Number');
        this.setTooltip(Blockly.Msg.ARDUINO_INOUT_DIGITAL_READ_WITH_PULLUP_TOOLTIP);
        this.setHelpUrl(Blockly.Msg.ARDUINO_INOUT_DIGITAL_READ_HELPURL);
        this.setStyle('io_blocks');

        // Привязываем обработчик, который будет выдавать предупреждение, если используется новый аналоговый вывод
        attachAnalogPinWarning(this.workspace, this.id, analogPinValues);
    }
};

Blockly.Blocks['board_base_inout_highlow'] = {
    init: function () {
        this.appendDummyInput()
                .appendField(new Blockly.FieldDropdown(Blockly.Msg.FIELDDROPDOWN), 'BOOL')
        this.setOutput(true, 'Number');
        this.setTooltip(Blockly.Msg.ARDUINO_INOUT_ONOFF_TOOLTIP);
        this.setHelpUrl(Blockly.Msg.ARDUINO_INOUT_ONOFF_HELPURL);
        this.setStyle('io_blocks');
    }
};

Blockly.Blocks['board_base_inout_analog_write'] = {
    init: function () {
        this.appendDummyInput()
                .appendField(Blockly.Msg.ARDUINO_INOUT_ANALOG_WRITE_INPUT1)
                .appendField(new Blockly.FieldDropdown(profile.default.dropdownPWM), "PIN");
        this.appendValueInput("PWM", 'Number')
                .appendField(Blockly.Msg.ARDUINO_INOUT_ANALOG_WRITE_INPUT2)
                .setCheck(numberCompatibility);
        this.setInputsInline(true);
        this.setPreviousStatement(true, null);
        this.setNextStatement(true, null);
        this.setTooltip(Blockly.Msg.ARDUINO_INOUT_ANALOG_WRITE_TOOLTIP);
        this.setHelpUrl(Blockly.Msg.ARDUINO_INOUT_ANALOG_WRITE_HELPURL);
        this.setStyle('io_blocks');
    }
};

Blockly.Blocks['board_base_inout_analog_read'] = {
    init: function () {
        this.appendDummyInput()
                .appendField(Blockly.Msg.ARDUINO_INOUT_ANALOG_READ_INPUT)
                .appendField(new Blockly.FieldDropdown(profile.default.dropdownAnalog), "PIN");
        this.setOutput(true, numberCompatibility);
        this.setTooltip(Blockly.Msg.ARDUINO_INOUT_ANALOG_READ_TOOLTIP);
        this.setHelpUrl(Blockly.Msg.ARDUINO_INOUT_ANALOG_READ_HELPURL);
        this.setStyle('io_blocks');
    }
};

Blockly.Blocks['board_base_delay'] = {
    init: function () {
        this.appendValueInput("DELAY_TIME", 'Number')
                .appendField(Blockly.Msg.ARDUINO_BASE_DELAY_DELAY_TIME)
                .setCheck(numberCompatibility);
        this.setInputsInline(true);
        this.setPreviousStatement(true, null);
        this.setNextStatement(true, null);
        this.setTooltip(Blockly.Msg.ARDUINO_BASE_DELAY_TOOLTIP);
        this.setHelpUrl(Blockly.Msg.ARDUINO_BASE_DELAY_HELPURL);
        this.setStyle('delay_blocks');
    }
};

Blockly.Blocks['board_base_delay_us'] = {
    init: function () {
        this.appendValueInput("DELAY_TIME_US", 'Number')
                .appendField(Blockly.Msg.ARDUINO_BASE_DELAY_US_DELAY_TIME)
                .setCheck(numberCompatibility);
        this.setInputsInline(true);
        this.setPreviousStatement(true, null);
        this.setNextStatement(true, null);
        this.setTooltip(Blockly.Msg.ARDUINO_BASE_DELAY_US_TOOLTIP);
        this.setHelpUrl(Blockly.Msg.ARDUINO_BASE_DELAY_US_HELPURL);
        this.setStyle('delay_blocks');
    }
};


Blockly.Blocks['board_base_angle'] = {
    init: function () {
        this.appendDummyInput()
                .appendField(Blockly.Msg.ARDUINO_BASE_ANGLE)
                .appendField(new Blockly.FieldAngle(90), 'ANGLE');
        this.setOutput(true, numberCompatibility);
        this.setTooltip(Blockly.Msg.ARDUINO_BASE_ANGLE_TOOLTIP);
        this.setHelpUrl(Blockly.Msg.ARDUINO_BASE_ANGLE_HELPURL);
        this.setStyle('io_blocks');
    }
};

Blockly.Blocks['board_base_inout_tone'] = {
    init: function () {
        const filteredDropdown = profile.default.dropdownDigital.filter(function (item) {
            return item[1] !== 'LED_BUILTIN' && item[1] !== 'BTN_BUILTIN';
        });
        this.appendDummyInput()
                .appendField(Blockly.Msg.ARDUINO_TONE_INPUT1)
                .appendField(new Blockly.FieldDropdown(filteredDropdown), "PIN");
        this.appendValueInput("NUM", "Number")
                .appendField(Blockly.Msg.ARDUINO_TONE_INPUT2)
                .setCheck('Number');
        this.appendValueInput("DUR", "Number")
                .appendField(Blockly.Msg.ARDUINO_TONE_INPUT3)
                .setCheck('Number');
        this.appendDummyInput()
                .appendField(Blockly.Msg.ARDUINO_TONE_INPUT4)

        this.setInputsInline(true);
        this.setPreviousStatement(true, null);
        this.setNextStatement(true, null);
        this.setTooltip(Blockly.Msg.ARDUINO_TONE_TOOLTIP);
        this.setHelpUrl(Blockly.Msg.ARDUINO_TONE_HELPURL);
        this.setStyle('io_util_blocks');
    }
};

Blockly.Blocks['board_base_inout_notone'] = {
    init: function () {
        const filteredDropdown = profile.default.dropdownDigital.filter(function (item) {
            return item[1] !== 'LED_BUILTIN' && item[1] !== 'BTN_BUILTIN';
        });
        this.appendDummyInput()
                .appendField(Blockly.Msg.ARDUINO_NOTONE_INPUT)
                .appendField(new Blockly.FieldDropdown(filteredDropdown), "PIN");
        this.setInputsInline(true);
        this.setPreviousStatement(true, null);
        this.setNextStatement(true, null);
        this.setTooltip(Blockly.Msg.ARDUINO_NOTONE_TOOLTIP);
        this.setHelpUrl(Blockly.Msg.ARDUINO_NOTONE_HELPURL);
        this.setStyle('io_util_blocks');
    }
};

Blockly.Blocks['board_base_inout_shiftIn'] = {
    init: function () {
        // исключить выводы светодиода и кнопки
        const filteredDropdown = profile.default.dropdownDigital.filter(item =>
            item[1] !== 'LED_BUILTIN' && item[1] !== 'BTN_BUILTIN'
        );

        this.appendDummyInput()
            .appendField(Blockly.Msg.ARDUINO_SHIFT_IN_1)
            .appendField(new Blockly.FieldDropdown(() => {
                const clock = this.getFieldValue("CLOCK");
                return filteredDropdown.filter(item => item[1] !== clock);
            }), "DATA");
        this.appendDummyInput()
            .appendField(Blockly.Msg.ARDUINO_SHIFT_IN_2)
            .appendField(new Blockly.FieldDropdown(() => {
                const data = this.getFieldValue("DATA");
                return filteredDropdown.filter(item => item[1] !== data);
            }), "CLOCK");
        this.appendDummyInput()
            .appendField(Blockly.Msg.ARDUINO_SHIFT_IN_3)
            .appendField(new Blockly.FieldDropdown(bitOrderDropdown), "ORDER")
            .appendField(Blockly.Msg.ARDUINO_SHIFT_IN_4);
            
        this.setInputsInline(true);
        this.setOutput(true, 'Number');
        this.setTooltip(Blockly.Msg.ARDUINO_SHIFT_IN_TOOLTIP);
        this.setHelpUrl(Blockly.Msg.ARDUINO_SHIFT_IN_HELPURL);
        this.setStyle('io_util_blocks');
    }
};

Blockly.Blocks['board_base_inout_shiftOut'] = {
    init: function () {
        // исключить выводы светодиода и кнопки
        const filteredDropdown = profile.default.dropdownDigital.filter(item =>
            item[1] !== 'LED_BUILTIN' && item[1] !== 'BTN_BUILTIN'
        );

        this.appendValueInput("VAL", "Number")
            .appendField(Blockly.Msg.ARDUINO_SHIFT_OUT_INPUT1)
            .setCheck("Number");
        this.appendDummyInput()
            .appendField(Blockly.Msg.ARDUINO_SHIFT_OUT_INPUT2)
            .appendField(new Blockly.FieldDropdown(() => {
                const clock = this.getFieldValue("CLOCK");
                return filteredDropdown.filter(item => item[1] !== clock);
            }), "DATA");
        this.appendDummyInput()
            .appendField(Blockly.Msg.ARDUINO_SHIFT_OUT_INPUT3)
            .appendField(new Blockly.FieldDropdown(() => {
                const data = this.getFieldValue("DATA");
                return filteredDropdown.filter(item => item[1] !== data);
            }), "CLOCK");
        this.appendDummyInput()
            .appendField(Blockly.Msg.ARDUINO_SHIFT_OUT_INPUT4)
            .appendField(new Blockly.FieldDropdown(bitOrderDropdown), "ORDER")
            .appendField(Blockly.Msg.ARDUINO_SHIFT_OUT_INPUT5);
            
        this.setInputsInline(true);
        this.setPreviousStatement(true);
        this.setNextStatement(true);
        this.setTooltip(Blockly.Msg.ARDUINO_SHIFT_OUT_TOOLTIP);
        this.setHelpUrl(Blockly.Msg.ARDUINO_SHIFT_OUT_HELPURL);
        this.setStyle('io_util_blocks');
    }
};