vehicle_gui.mjs

// window.B2_top.Circle(Widget.GREEN, true, 20, 10, 50);
// window.B2_top.category = Widget.CATEGORY_ENTITY;
// CATEGORY_UNSEL_ALL
// CATEGORY_SEL_ALL// - green
// CATEGORY_UPDATE
// GETEGORY_GENERIC_2 //latent

import {
    add_new_occupant,
    filter_version_drop_down,
    gui,
    set_selected_widget_item,
    update_occupant_names_combobox
} from "../../pre/pre_automotive_assessment.js";
import { OccupantVersion } from "./occupant_version.mjs";
import { ProtocolVehicle, VehicleOccupant } from "./vehicle.mjs";
import { WorkflowOccupant } from "./workflow_occupant.mjs";

export { VehicleGUI };

//AddVehicleToGUI(window,95,16);

class VehicleGUI {
    /**
     * Class to define a Vehicle GUI and button behaviour with a name supplier product and version number
     * to extract the data for the measurement
     * @param {any} window Window to place vehicle gui on
     * @param {number} x left coordinate of vehicle (on parent window)
     * @param {number} y top coordinate of vehicle (on parent window)
     * @param {string} [drive_side = VehicleOccupant.LHD] left hand drive (VehicleOccupant.LHD) by default or right hand drive (VehicleOccupant.RHD).
     * @example
     * let vehicle = new VehicleGUI(gui.wdw_pre_automotive, 97, 16);
     */
    constructor(window, x, y, drive_side = VehicleOccupant.LHD) {
        this.window = window;
        this.x = x;
        this.y = y;
        this.drive_side = drive_side;

        VehicleGUI.AddVehicleToGUI(window, x, y); //should only be called once so put in constructor
        this.Update();
    }

    /**
     * occupant buttons are set based on the current protocol selected and the existing
     * occupant(s) defined.
     *
     *
     */

    Update(vehicle) {
        if (vehicle) {
            this.UpdateOccupantButtons(vehicle);
        } else {
            ErrorMessage(`Gui not updated`);
        }
    }

    /**
     *
     * @param {ProtocolVehicle} vehicle Protocol vehicle
     */
    UpdateOccupantButtons(vehicle) {
        // Message(`vehicle ${Object.keys(vehicle)}`);
        // Message(`vehicle JSON ${JSON.stringify(vehicle, null, 4)}`);

        for (let vehicle_occupant of vehicle.Occupants()) {
            let button = this.GetButton(vehicle_occupant.GetSide(this.drive_side), vehicle_occupant.front_rear);

            // Ignore squiggles below because Widget objects can have user defined properties added
            // @ts-ignore
            button.vehicle_occupant = vehicle_occupant;

            let category = this.GetCategory(vehicle_occupant);

            Message(
                `Category =  ${category}, side = ${vehicle_occupant.GetSide(this.drive_side)}, front_rear = ${
                    vehicle_occupant.front_rear
                }`
            );

            VehicleGUI.UpdateOccupantButton(button, category);
        }
    }

    /**
     * get the category of the button based on if an existing occupant has been defined for the
     * corresponding seat and if it is a valid (and supported) occupant
     * @param {VehicleOccupant} vehicle_occupant
     * @returns {string}
     */
    GetCategory(vehicle_occupant) {
        //first check if there is an occupant defined for the current seat

        for (let wf_occupant of gui.occupants) {
            if (
                //wf_occupant.position == vehicle_occupant.position &&
                wf_occupant.side == vehicle_occupant.GetSide(this.drive_side) &&
                wf_occupant.front_rear == vehicle_occupant.front_rear
            ) {
                //now check if the seat should be empty
                if (vehicle_occupant.Empty()) return Category.NOT_REQUIRED;

                //now check if defined occupant is of the correct type

                var valid_occupant_names = OccupantVersion.GetOnly(
                    "ALL",
                    vehicle_occupant.product,
                    vehicle_occupant.physiology
                );

                //once we have a list of valid occupant names we check if the name of the occupant
                //defined for the current seat is in the list - if so it is valid, else it is invlaid

                if (valid_occupant_names.indexOf(wf_occupant.name) != -1) {
                    return Category.VALID;
                } else {
                    return Category.INVALID;
                }
            }
        }

        //if no occupant is defined for the current seat then it should either be empty or latent

        if (vehicle_occupant.Empty()) return Category.EMPTY;
        else return Category.LATENT;
    }

    /**
     * returns the button widget based on the seat side and row
     * @param {string} side
     * @param {string} front_rear
     * @returns {Widget}
     */
    GetButton(side, front_rear) {
        // FRONT
        if (front_rear == WorkflowOccupant.FRONT) {
            if (side == WorkflowOccupant.LEFT) return this.window.B_FrontL;
            return this.window.B_FrontR;
        } //REAR
        else {
            if (side == WorkflowOccupant.LEFT) return this.window.B_RearL;
            if (side == WorkflowOccupant.RIGHT) return this.window.B_RearR;
            return this.window.B_RearM;
        }
    }

    /**
     * @param {any} window gui window on which to place the vehicle gui
     * @param {number} x left coordinate of vehicle (on parent window)
     * @param {number} y top coordinate of vehicle (on parent window)
     */
    static AddVehicleToGUI(window, x, y) {
        let bonnet = 12;
        let boot = 12;
        let mid_space = 4;
        let side_space = 2;
        let tween_space = 1;

        let size = 7;

        let driver_row = y + bonnet;
        let rear_row = driver_row + mid_space + size;

        let left_col = x + side_space;
        let mid_col = left_col + size + tween_space;
        let right_col = mid_col + size + tween_space;

        //vehicle outer body
        //10,10 to 60,100

        window.L_CAR = new Widget(window, Widget.LABEL, x, right_col + size + side_space, y, rear_row + size + boot);
        // window.L_CAR.Rectangle(Widget.BLACK, false, 0, 0, 100, 100);

        window.L_CAR.xResolution = 1000;
        window.L_CAR.yResolution = 1000;
        window.L_CAR.lineWidth = 1;
        window.L_CAR.Polygon(
            Widget.WHITE,
            true,
            200,
            0, //top left
            800,
            0, //top right
            950,
            50, //top right corner
            1000,
            300, //right top
            1000,
            700, //right bottom
            950,
            950, //bottom right corner
            800,
            1000, //bottom right
            200,
            1000, //bottom left
            50,
            950, //bottom left corner
            0,
            700, //left bottom
            0,
            300, //left top
            50,
            50, //left top corner
            200,
            0 //top left
        );

        //left light
        window.L_CAR.Polygon(
            Widget.YELLOW,
            true,
            200,
            0, //top left
            220,
            30, //light corner 2
            90,
            60, //left bot corner 2
            50,
            50, //left top corner
            200,
            0 //top left
        );

        //right light
        window.L_CAR.Polygon(
            Widget.YELLOW,
            true,
            1000 - 200,
            0, //top left
            1000 - 220,
            30, //light corner 2
            1000 - 90,
            60, //left bot corner 2
            1000 - 50,
            50, //left top corner
            1000 - 200,
            0 //top left
        );

        window.L_CAR.Line(
            Widget.GREY,
            0,
            300, //left top
            90,
            60 //left bot corner 2
        );

        window.L_CAR.Line(
            Widget.GREY,
            90,
            60, //left bot corner 2
            220, //light corner 2
            30
        );

        window.L_CAR.Line(
            Widget.GREY,
            220, //light corner 2
            30,
            1000 - 220, //left bot corer 2
            30
        );

        window.L_CAR.Line(
            Widget.GREY,
            1000 - 220, //left bot corer 2
            30,
            1000 - 90,
            69
        );

        window.L_CAR.Line(
            Widget.GREY,
            1000 - 90,
            69,
            1000 - 0,
            300 //right top
        );

        window.B_FrontL = new Widget(window, Widget.BUTTON, left_col, left_col + size, driver_row, driver_row + size);
        window.B_FrontR = new Widget(window, Widget.BUTTON, right_col, right_col + size, driver_row, driver_row + size);
        window.B_RearL = new Widget(window, Widget.BUTTON, left_col, left_col + size, rear_row, rear_row + size);
        window.B_RearR = new Widget(window, Widget.BUTTON, right_col, right_col + size, rear_row, rear_row + size);
        window.B_RearM = new Widget(window, Widget.BUTTON, mid_col, mid_col + size, rear_row, rear_row + size);

        //set button side
        window.B_FrontL.side = WorkflowOccupant.LEFT;
        window.B_FrontR.side = WorkflowOccupant.RIGHT;
        window.B_RearL.side = WorkflowOccupant.LEFT;
        window.B_RearR.side = WorkflowOccupant.RIGHT;
        window.B_RearM.side = WorkflowOccupant.MIDDLE;

        //assign onClick callbacks
        window.B_FrontL.onClick = OccupantButtonOnClick;
        window.B_FrontR.onClick = OccupantButtonOnClick;
        window.B_RearL.onClick = OccupantButtonOnClick;
        window.B_RearR.onClick = OccupantButtonOnClick;
        window.B_RearM.onClick = OccupantButtonOnClick;
    }

    static UpdateOccupantButton(widget, category = Category.EMPTY) {
        widget.Clear();

        Category.SetButtonCategory(widget, category);

        if (!widget.vehicle_occupant.Empty()) {
            //draw passenger
            widget.xResolution = 500;
            widget.yResolution = 500;
            widget.Circle(Widget.GREY, true, 250, 370, 180);
            widget.Rectangle(Widget.GREY, true, 0, 0, 100, 400);
            widget.Rectangle(Widget.GREY, true, 400, 0, 500, 400);

            if (widget.vehicle_occupant.position == WorkflowOccupant.DRIVER) {
                widget.Rectangle(Widget.BLACK, true, 50, 0, 450, 75);
            }

            widget.hover += ` (${widget.vehicle_occupant.product}-${widget.vehicle_occupant.physiology})`;
        }

        gui.wdw_pre_automotive.Redraw();
    }
}

/**
 * update the filters on the occupant window to only allow valid occupants
 */
function OccupantButtonOnClick() {
    let wdw = gui.wdw_occupant;
    let button = this;
    let vehicle_occupant = button.vehicle_occupant;

    if (vehicle_occupant && vehicle_occupant.product && vehicle_occupant.physiology) {
        wdw.cbx_occupant_name.active = true;
        wdw.cbx_occupant_supplier.active = true;
        wdw.cbx_occupant_product.active = true;
        wdw.cbx_occupant_physiology.active = true;
        set_selected_widget_item(wdw.cbx_occupant_supplier, "all");
        Message(`Sellected supplier: ${wdw.cbx_occupant_supplier.text}`);
        set_selected_widget_item(wdw.cbx_occupant_product, vehicle_occupant.product);
        set_selected_widget_item(wdw.cbx_occupant_physiology, vehicle_occupant.physiology);

        set_selected_widget_item(wdw.cbx_occupant_position, vehicle_occupant.position);
        set_selected_widget_item(wdw.cbx_occupant_side, button.side);
        set_selected_widget_item(wdw.cbx_occupant_front_rear, vehicle_occupant.front_rear);

        //once all the widget items have been set call update filters to update the drop-down
        //list of occupant names
        let occupant_names = filter_version_drop_down();
        update_occupant_names_combobox(occupant_names);

        add_new_occupant();
    }
}

class Category {
    /** empty - no occupant defined and no occupant required
     * @type {string} */
    static get EMPTY() {
        return "empty";
    }
    /** not empty - occupant is defined for this seat but is not required (should be empty)
     * @type {string} */
    static get NOT_REQUIRED() {
        return "not required";
    }
    /** valid - occupant is defined and matched required tyoed
     * @type {string} */
    static get VALID() {
        return "valid";
    }
    /** invalid - occupant defined but not valid (for selected protocol)
     * @type {string} */
    static get INVALID() {
        return "invalid";
    }
    /** latent - occupant should be defined
     * @type {string} */
    static get LATENT() {
        return "latent";
    }

    static SetButtonCategory(widget, category_status, seat_status) {
        switch (category_status) {
            case Category.EMPTY:
                widget.hover = category_status;
                widget.category = Widget.CATEGORY_GENERIC_2;
                break;
            case Category.NOT_REQUIRED:
                widget.hover = category_status;
                widget.category = Widget.NO_CATEGORY;
                widget.background = Widget.RED;
                break;
            case Category.VALID:
                widget.hover = category_status;
                widget.category = Widget.NO_CATEGORY;
                // widget.foreground = Widget.BLACK;
                widget.background = Widget.GREEN;
                break;
            case Category.INVALID:
                widget.hover = category_status;
                widget.category = Widget.NO_CATEGORY;
                widget.background = Widget.RED;
                break;
            case Category.LATENT:
                widget.hover = category_status;
                widget.category = Widget.NO_CATEGORY;
                widget.background = Widget.ORANGE;
                break;
            default:
                Message(`Category "${category_status}" is not supported.`);
                break;
        }
    }
}