'use strict';

/**
 * @class Grid
 * @param {rows} rows - Number of rows in the grid.
 * @param {cols} cols - Number of cols in the grid.
 */
function Grid(rows, cols) {
    this.grid = new Array(rows);
    for (var i=0; i < rows; i++) {
        this.grid[i] = new Array(cols);
    }
}

/**
 * Initializes a Grid from an array.
 * @param {array} arr - Array containing elements to be made into a Grid.
 */
Grid.prototype.initFromArray = function(arr){
    for(var i = 0; i < arr.length; i++){
        for(var j = 0; j < arr[0].length; j++){
            if (this.inBounds(i, j)) {
                this.set(i, j, arr[i][j]);
            }
        }
    }
};

/**
 * Initializes the contents of the grid with `value`.
 * @param {number|string|object} value - The value to be inserted in all
 * positions of the grid.
 */
Grid.prototype.init = function(value) {
    for (var i = 0; i < this.numRows(); i++) {
        for (var j = 0; j < this.numCols(); j++) {
            this.grid[i][j] = value;
        }
    }
};

/**
 * Gets the object stored at the requested row and column.
 * @param {number} i - The row of the desired object.
 * @param {number} j - The col of the desired object.
 * @returns {object} The object stored in the grid at that position.
 */
Grid.prototype.get = function(i, j) {
    return this.grid[i][j];
};

/**
 * Sets an object at the requested row and column.
 * @param {number} i - The row of the destination of the object.
 * @param {number} j - The row of the destination of the object.
 */
Grid.prototype.set = function(i, j, value) {
    this.grid[i][j] = value;
};

/**
 * Returns the number of rows in the grid.
 * @returns {number} The number of rows in the grid.
 */
Grid.prototype.numRows = function() {
    return this.grid.length;
};

/**
 * Returns the number of cols in the grid.
 * @returns {number} The number of cols in the grid.
 */
Grid.prototype.numCols = function() {
    return this.grid[0].length;
};

/**
 * Checks whether the given row and col exist in the grid.
 * @param {number} row - Row of the position being checked.
 * @param {number} col - Col of the position being checked.
 * @param {boolean} Whether or not the given position is in bounds.
 */
Grid.prototype.inBounds = function(row, col) {
    if(row < 0 || col < 0){
        return false;
    }
    if(row >= this.numRows() || col >= this.numCols()){
        return false;
    }
    return true;
};

/**
 * Converts a grid to a list.
 * For example:
 * -------
 * A B C D
 * E F G H
 * I J K L
 * -------
 * would convert to:
 * -------
 * [[0, 0, 'A'], [0, 1, 'B'], [0, 2, 'C'], [0, 3, 'D'], [1, 0, 'E']...[2, 3, 'L']]
 * @returns {array} List representation of the Grid.
 */
Grid.prototype.toList = function() {
    var list = [];
    for (var i = 0; i < this.grid.length; i++) {
        for (var j = 0; j < this.grid[0].length; j++) {
            var value = this.grid[i][j];
            if (value && value !== 0) {
                list.push([i, j, value]);
            }
        }
    }
    return list;
};

/**
 * Generates a string representation of the Grid.
 * @returns {string} A representatino of a grid of the format
 * "A B C <br/>D E F <br/>G H I <br/>"
 */
Grid.prototype.toString = function() {
    var result = "";
    for(var i = 0; i < this.numRows(); i++){
        for(var j = 0; j < this.numCols(); j++){
            result += this.get(i, j) + " ";
        }
        result += "<br/>";
    }
    return result;
};

module.exports = Grid;
