Source: drawing/visible_robot.js

require("./../rur.js");
require("./../utils/validator.js");
var record_id = require("./../../lang/msg.js").record_id;
record_id("robot0");
record_id("robot1");
record_id("robot2");
record_id("robot3");

RUR.vis_robot = {};
RUR.vis_robot.images = {};

// we will keep track if we have loaded all images
RUR.vis_robot.loaded_images = 0;
RUR.vis_robot.nb_images = 0;

// enable changing defaults for unit tests or if put on different server location
RUR.BASE_URL = RUR.BASE_URL || '';

function set_images(images) {
    "use strict"
    var default_images, east, west, north, south, robot, model = images.model;

    default_images = {east: RUR.BASE_URL + '/src/images/robot_e.png',
        north: RUR.BASE_URL + '/src/images/robot_n.png',
        west: RUR.BASE_URL + '/src/images/robot_w.png',
        south: RUR.BASE_URL + '/src/images/robot_s.png'
    }

    if (RUR.KNOWN_ROBOT_MODELS.indexOf(model) == -1) {
        RUR.KNOWN_ROBOT_MODELS.push(model);
    }

    if (RUR.vis_robot.images[model] === undefined) {
        RUR.vis_robot.images[model] = {};
        robot = RUR.vis_robot.images[model];
        robot.robot_e_img = new Image();
        robot.robot_n_img = new Image();
        robot.robot_w_img = new Image();
        robot.robot_s_img = new Image();
    } else {
        robot = RUR.vis_robot.images[model];
    }

    if (robot.robot_e_img.src != images.east) {
        robot.robot_e_img.src = images.east || default_images.east;
        robot.e_url = images.east || '/src/images/robot_e.png';
        robot.robot_e_img.onload = RUR.onload_new_image;
        RUR.state.reset_default_robot_images_needed = true;
    }
    if (robot.robot_n_img.src != images.north) {
        robot.robot_n_img.src = images.north || default_images.north;
        robot.n_url = images.north || '/src/images/robot_n.png';
        robot.robot_n_img.onload = RUR.onload_new_image;
        RUR.state.reset_default_robot_images_needed = true;
    }
    if (robot.robot_w_img.src != images.west) {
        robot.robot_w_img.src = images.west || default_images.west;
        robot.w_url = images.west || '/src/images/robot_w.png';
        robot.robot_w_img.onload = RUR.onload_new_image;
        RUR.state.reset_default_robot_images_needed = true;
    }
    if (robot.robot_s_img.src != images.south) {
        robot.robot_s_img.src = images.south || default_images.south;
        robot.s_url = images.south || '/src/images/robot_s.png';
        robot.robot_s_img.onload = RUR.onload_new_image;
        RUR.state.reset_default_robot_images_needed = true;
    }
}

RUR.reset_default_robot_images = function () {
    "use strict"
    var saved_model;
    set_images({model: "classic"}); // classic; uses default
    set_images({model: "2d red rover",
        east: RUR.BASE_URL + '/src/images/rover_e.png',
        north: RUR.BASE_URL + '/src/images/rover_n.png',
        west: RUR.BASE_URL + '/src/images/rover_w.png',
        south: RUR.BASE_URL + '/src/images/rover_s.png'
    });
    set_images({model: "3d red rover",
        east: RUR.BASE_URL + '/src/images/plain_e.png',
        north: RUR.BASE_URL + '/src/images/plain_n.png',
        west: RUR.BASE_URL + '/src/images/plain_w.png',
        south: RUR.BASE_URL + '/src/images/plain_s.png'
    });
    set_images({model: "solar panel",
        east: RUR.BASE_URL + '/src/images/sp_e.png',
        north: RUR.BASE_URL + '/src/images/sp_n.png',
        west: RUR.BASE_URL + '/src/images/sp_w.png',
        south: RUR.BASE_URL + '/src/images/sp_s.png'
    });

    $("#robot0 img").attr("src", RUR.vis_robot.images["classic"].robot_e_img.src);
    $("#robot1 img").attr("src", RUR.vis_robot.images["2d red rover"].robot_e_img.src);
    $("#robot2 img").attr("src", RUR.vis_robot.images["3d red rover"].robot_e_img.src);
    $("#robot3 img").attr("src", RUR.vis_robot.images["solar panel"].robot_e_img.src);

    // handle situation where the user had saved values from old naming styles
    saved_model = localStorage.getItem("robot_default_model");
    if (saved_model==0 || saved_model==1 || saved_model==2 || saved_model==3) {
        saved_model = RUR.reeborg_default_model;
        localStorage.setItem("robot_default_model", saved_model);
    }
    RUR.user_selected_model = saved_model;
    RUR.select_default_robot_model(saved_model);

    // additional robot images from rur-ple
    set_images({model: "blue",
        east: RUR.BASE_URL + '/src/images/blue_robot_e.png',
        north: RUR.BASE_URL + '/src/images/blue_robot_n.png',
        west: RUR.BASE_URL + '/src/images/blue_robot_w.png',
        south: RUR.BASE_URL + '/src/images/blue_robot_s.png'
    });
    set_images({model: "purple",
        east: RUR.BASE_URL + '/src/images/purple_robot_e.png',
        north: RUR.BASE_URL + '/src/images/purple_robot_n.png',
        west: RUR.BASE_URL + '/src/images/purple_robot_w.png',
        south: RUR.BASE_URL + '/src/images/purple_robot_s.png'
    });
    set_images({model: "green",
        east: RUR.BASE_URL + '/src/images/green_robot_e.png',
        north: RUR.BASE_URL + '/src/images/green_robot_n.png',
        west: RUR.BASE_URL + '/src/images/green_robot_w.png',
        south: RUR.BASE_URL + '/src/images/green_robot_s.png'
    });
    set_images({model: "light blue",
        east: RUR.BASE_URL + '/src/images/light_blue_robot_e.png',
        north: RUR.BASE_URL + '/src/images/light_blue_robot_n.png',
        west: RUR.BASE_URL + '/src/images/light_blue_robot_w.png',
        south: RUR.BASE_URL + '/src/images/light_blue_robot_s.png'
    });
    set_images({model: "yellow",
        east: RUR.BASE_URL + '/src/images/yellow_robot_e.png',
        north: RUR.BASE_URL + '/src/images/yellow_robot_n.png',
        west: RUR.BASE_URL + '/src/images/yellow_robot_w.png',
        south: RUR.BASE_URL + '/src/images/yellow_robot_s.png'
    });
    RUR.state.reset_default_robot_images_needed = false;
};

RUR.select_default_robot_model = function (model) {
    "use strict";
    var robot;

    if ( !(model == "classic" || model == "2d red rover"
           || model == "3d red rover" || model == "solar panel")){
        model = RUR.reeborg_default_model;
    }
    // the user could click on the robot model buttons when there are
    // no robot present in the world.
    try {
        robot = RUR.get_current_world().robots[0];
        robot.model = model;
        RUR.user_selected_model = model;
    } catch (e) {}

    RUR.vis_robot.e_img = RUR.vis_robot.images[model].robot_e_img;
    RUR.vis_robot.n_img = RUR.vis_robot.images[model].robot_n_img;
    RUR.vis_robot.w_img = RUR.vis_robot.images[model].robot_w_img;
    RUR.vis_robot.s_img = RUR.vis_robot.images[model].robot_s_img;
    if (RUR.vis_world !== undefined) {
        RUR.vis_world.refresh();
    }
    localStorage.setItem("robot_default_model", model);
};
$("#robot0").on("click", function (evt) {
    RUR.select_default_robot_model("classic");
});

$("#robot1").on("click", function (evt) {
    RUR.select_default_robot_model("2d red rover");
});

$("#robot2").on("click", function (evt) {
    RUR.select_default_robot_model("3d red rover");
});

$("#robot3").on("click", function (evt) {
    RUR.select_default_robot_model("solar panel");
});

RUR.reset_default_robot_images();
// the following is to try to ensure that the images are loaded before the "final"
// original drawing is made

RUR.vis_robot.e_img.onload = function () {
    RUR.vis_robot.loaded_images += 1;
};
RUR.vis_robot.nb_images += 1;
RUR.vis_robot.w_img.onload = function () {
    RUR.vis_robot.loaded_images += 1;
};
RUR.vis_robot.nb_images += 1;
RUR.vis_robot.n_img.onload = function () {
    RUR.vis_robot.loaded_images += 1;
};
RUR.vis_robot.nb_images += 1;
RUR.vis_robot.s_img.onload = function () {
    RUR.vis_robot.loaded_images += 1;
};
RUR.vis_robot.nb_images += 1;

/**@function animate_robot
 * @memberof RUR
 * @instance
 *
 * @desc Robot animation is done by cycling through a list of robot models,
 * each model having 4 images (one for each orientation).
 *
 * @param {array} models A list of robot models. If the list contains a single
 * model, the animation is stopped.
 * @param {object} robot_body A robot_body object.
 */

RUR.animate_robot = function (models, robot_body) {
    "use strict"
    if (robot_body === undefined) {
        robot_body = RUR.get_current_world().robots[0];
    }
    if (models.length > 1) {
        robot_body.models_cycle = models;
        robot_body.model_index = 0;
    } else {
        robot_body.models_cycle = null;
        robot_body.model = models[0];
    }
    RUR.record_frame("animate robot", robot_body.__id);
    RUR.state.animated_robots = true;
};

function update_model(robot) { // robot == robot.body
    var default_robot, nb_models = robot.models_cycle.length;

    if (robot.model_index == undefined) {
        robot.model_index = 0;
    }
    robot.model = robot.models_cycle[robot.model_index];

    default_robot = RUR.get_current_world().robots[0];
    if (default_robot.__id == robot.__id) {
        RUR.user_selected_model = undefined;  // overrides the user's choice
    }
    // do we cycle through the value; a model number of -1 ends a cycle
    if (robot.model_index == nb_models-2){
        if (robot.models_cycle[robot.model_index+1] == -1){
            return;
        }
    }
    robot.model_index += 1;
    robot.model_index %= nb_models;
    return;
};


RUR.vis_robot.draw = function (robot) {
    "use strict";
    var x, y, width, height, image, default_robot;
    if (!robot) {
        console.warn("RUR.vis_robot.draw called with no robot.");
        return;
    }

    // handling legacy Code
    if (robot.orientation !== undefined) {
        robot._orientation = robot.orientation;
        robot.orientation = null;
    }
    if (robot.x > RUR.MAX_X || robot.y > RUR.MAX_Y) {
        return;
    }

    // all images are taken to be centered on a tile 40x40, which are scaled
    //  appropriately
    width = RUR.TILE_SIZE * RUR.SCALE;
    height = RUR.TILE_SIZE * RUR.SCALE;

    x = robot.x*RUR.WALL_LENGTH + RUR.WALL_THICKNESS/2;
    y = RUR.HEIGHT - (robot.y+1)*RUR.WALL_LENGTH + RUR.WALL_THICKNESS/2;

    if (robot.models_cycle) {
        update_model(robot);
    }

    if (robot.model == undefined) {
        robot.model = RUR.reeborg_default_model;
    } else if (RUR.KNOWN_ROBOT_MODELS.indexOf(robot.model) == -1) {
        console.warn("robot model not defined: " + robot.model);
        robot.model = RUR.reeborg_default_model;
    }

    if (RUR.user_selected_model !== undefined) {
        default_robot = RUR.get_current_world().robots[0];
        if (default_robot.__id == robot.__id ) {
            robot.model = RUR.user_selected_model;
        }
    }

    switch(robot._orientation){
        case RUR.EAST:
            image = RUR.vis_robot.images[robot.model].robot_e_img;
            break;
        case RUR.NORTH:
            image = RUR.vis_robot.images[robot.model].robot_n_img;
            break;
        case RUR.WEST:
            image = RUR.vis_robot.images[robot.model].robot_w_img;
            break;
        case RUR.SOUTH:
            image = RUR.vis_robot.images[robot.model].robot_s_img;
            break;
        case -1:
            RUR.vis_robot.draw_random(robot);
        default:
            image = RUR.vis_robot.e_img;
        }
    RUR.ROBOT_CTX.drawImage(image, x, y, width, height);
    if (RUR.state.editing_world){
        return;
    }
    RUR.vis_robot.draw_trace_history(robot);
};


// drawing random orientation robot
RUR.vis_robot.draw_random = function (robot) {
    "use strict";
    var x, y, width, height, image, random_orientation;
    if (!robot) {
        console.warn("RUR.vis_robot.draw_random called with no robot.");
        return;
    }

    if (!(robot._orientation == -1 || robot.orientation == -1)) {
        console.warn("RUR.vis_robot.draw_random but orientation != -1.");
        return;
    }
    if (robot.x > RUR.MAX_X || robot.y > RUR.MAX_Y) {
        return;
    }

    // all images are taken to be centered on a tile 40x40, which are scaled
    //  appropriately
    width = RUR.TILE_SIZE * RUR.SCALE;
    height = RUR.TILE_SIZE * RUR.SCALE;

    x = robot.x*RUR.WALL_LENGTH + RUR.WALL_THICKNESS/2;
    y = RUR.HEIGHT - (robot.y+1)*RUR.WALL_LENGTH + RUR.WALL_THICKNESS/2;

    random_orientation = Math.floor(Math.random() * 4)
    switch(random_orientation){
        case RUR.EAST:
            if (robot.model !== undefined){
                image = RUR.vis_robot.images[robot.model].robot_e_img;
            } else {
                image = RUR.vis_robot.e_img;
            }
            break;
        case RUR.NORTH:
            if (robot.model !== undefined){
                image = RUR.vis_robot.images[robot.model].robot_n_img;
            } else {
                image = RUR.vis_robot.n_img;
            }
            break;
        case RUR.WEST:
            if (robot.model !== undefined){
                image = RUR.vis_robot.images[robot.model].robot_w_img;
            } else {
                image = RUR.vis_robot.w_img;
            }
            break;
        case RUR.SOUTH:
            if (robot.model !== undefined){
                image = RUR.vis_robot.images[robot.model].robot_s_img;
            } else {
                image = RUR.vis_robot.s_img;
            }
            break;
        default:
            image = RUR.vis_robot.e_img;
            console.warn("default should not happen in RUR.vis_robot.draw_random.");
        }
    RUR.ROBOT_ANIM_CTX.drawImage(image, x, y, width, height);
    RUR.state.random_robot = true;
};


RUR.vis_robot.draw_trace_history  = function(robot) {
    var segment;
    for (segment of robot._trace_history) { //jshint ignore:line
        RUR.vis_robot.draw_trace_segment(segment);
    }
};

RUR.vis_robot.draw_trace_segment = function (segment) {
    "use strict";
    var ctx = RUR.TRACE_CTX;
    ctx.strokeStyle = segment["color"];
    ctx.lineWidth = segment["thickness"];
    ctx.lineCap = "round";

    ctx.beginPath();
    ctx.moveTo(segment["prev_x"], segment["prev_y"]);
    ctx.lineTo(segment["x"], segment["y"]);
    ctx.stroke();
};

/** @function new_robot_images
 * @memberof RUR
 * @instance
 *
 * @desc Create new images for the robot.
 *
 * **Suggestion**: use in the Onload editor, so that images can be fetched
 * as soon as the world is loaded.
 *
 * **Python**: You _can_ use `new_robot_images` without the `RUR` prefix. For the
 * French version, you can use `nouvelles_images_de_robot`. However, the
 * function described here is preferable as it can be used with either
 * Javascript or Python.
 *
 * @param {Object} images A Javascript object (similar to a Python dict) that
 * holds the relevant attributes.
 *
 * @param {string} [images.model]  The model name of the robot. Integer values
 * will be accepted as well except for -1 which will raise an error. If the
 * model is not specified, the value `"anonymous"` will be used.
 *
 * @param {string} [images.east]  A url for the source of the image to be used
 * for the robot in the East orientation. If it is not specified, the
 * default "classic" image will be used.
 *
 * @param {string} [images.north]  Similar to `images.east`.
 * @param {string} [images.west]  Similar to `images.east`.
 * @param {string} [images.south]  Similar to `images.east`.
 *
 */

RUR.new_robot_images = function (images) {
    var model, random;
    if (images.model !== undefined) {
        if (images.model == -1) {
            throw new RUR.ReeborgError(RUR.translate("Robot model cannot be -1."));
        }
        model = images.model;
    } else {
        images.model = model = "anonymous";
    }
    set_images(images);
};

/** @function show_all_robots
 * @memberof RUR
 * @instance
 *
 * @summary This method shows all known robot models in a table.
 *
 */
RUR.show_all_robots = function () {
    var info, model, east, north, west, south, e_url, w_url, s_url, n_url;
    info = "<table border='1'><tr><th>model</th><th>east</th><th>north</th><th>west</th><th>south</th></tr>";

    for (model in RUR.vis_robot.images) {
        if (RUR.vis_robot.images.hasOwnProperty(model)) {
            east = RUR.vis_robot.images[model].robot_e_img.src;
            north = RUR.vis_robot.images[model].robot_n_img.src;
            west = RUR.vis_robot.images[model].robot_w_img.src;
            south = RUR.vis_robot.images[model].robot_s_img.src;
            e_url = RUR.vis_robot.images[model].e_url;
            n_url = RUR.vis_robot.images[model].n_url;
            w_url = RUR.vis_robot.images[model].w_url;
            s_url = RUR.vis_robot.images[model].s_url;

            info += "<tr><td>" +  model + "</td>";
            info += "<td><img src = '" + east + "'><br>" + e_url + "</td>";
            info += "<td><img src = '" + north + "'><br>" + n_url + "</td>";
            info += "<td><img src = '" + west + "'><br>" + w_url + "</td>";
            info += "<td><img src = '" + south + "'><br>" + s_url + "</td></tr>";
        }
    }

    info += "</table>";
    RUR._print_html_(info, true); // true will replace existing content
    return null; // for the python repl
};