'use strict';

/**
 * @constructor
 */
function Thing() {
    this.x = 0;
    this.y = 0;
    this.color = '#000000';
    this.stroke = '#000000';
    this.type = 'Thing';
    this.lineWidth = 1;
    this.filled = true;
    this.hasBorder = false;
}

/**
 * Sets a Thing object to filled.
 * Throws an error if an argument is not passed.
 * @param {bool} filled - A boolean of whether or not Thing is filled.
 */
Thing.prototype.setFilled = function(filled){
    if (arguments.length !== 1) {
        throw new Error('You should pass exactly 1 argument to setFilled');
    }
    this.filled = filled;
};

/**
 * Returns if a Thing is filled.
 * @returns {boolean} True if the Thing is filled.
 */
Thing.prototype.isFilled = function(){
    return this.filled;
};

/**
 * Sets a Thing object to filled.
 * Throws an error if an argument is not passed.
 * @param {bool} hasBorder - A boolean of whether or not Thing has a border.
 */
Thing.prototype.setBorder = function(border){
    if (arguments.length !== 1) {
        throw new Error('You should pass exactly 1 argument to setBorder');
    }
    this.hasBorder = border;
};

/**
 * Returns if a Thing has a border.
 * @returns {boolean} True if the Thing has a border.
 */
Thing.prototype.hasBorder = function(){
    return this.hasBorder;
};

/**
 * Sets a Thing object's type.
 * Questionable of whether or not this method is used.
 * @param {type} type - A type to set the Thing to.
 */
Thing.prototype.setType = function(type){
    if (arguments.length !== 1) {
        throw new Error('You should pass exactly 1 argument to setType');
    }
    this.type = type;
};

/**
 * Returns the type of a Thing.
 * @returns {type} The type of the Thing.
 */
Thing.prototype.getType = function(){
    return this.type;
};

/**
 * Sets the position of a Thing.
 * Throws an error if there are fewer than 2 params or if
 * they are not numbers.
 * @param {number} x - The destination x coordinate of this Thing.
 * @param {number} y - The destination y coordinate of this Thing.
 */
Thing.prototype.setPosition = function(x, y) {
    if (arguments.length !== 2) {
        throw new Error('You should pass exactly 2 arguments to setPosition');
    }
    if (typeof x !== 'number' && isNaN(x)) {
        throw new TypeError('Invalid number for x-coordinate');
    }
    if (typeof y !== 'number' && isNaN(y)) {
        throw new TypeError('Invalid number for y-coordinate');
    }
    this.x = x;
    this.y = y;
};

/**
 * Sets the color of a Thing.
 * Throws an error if there are fewer than 1 params or if
 * the param is undefined.
 * @param {Color} color - The resulting color of Thing.
 */
Thing.prototype.setColor = function(color){
    if (arguments.length !== 1) {
        throw new Error('You should pass exactly 1 argument to setColor.');
    }
    if (color === undefined) {
        throw new TypeError('Invalid color');
    }
    this.color = color;
};

/**
 * Gets the color of a Thing.
 * @returns {Color} The destination y coordinate of this Thing.
 */
Thing.prototype.getColor = function(){
    return this.color;
};

/**
 * Sets the border color of a Thing.
 * Throws an error if there are fewer than 1 params or if
 * the param is undefined.
 * @param {Color} color - The resulting color of the Thing's border.
 */
Thing.prototype.setBorderColor = function(color){
    if (color === undefined) {
        throw new TypeError('Invalid color.');
    }
    this.stroke = color;
    this.hasBorder = true;
    this.hasBorder = true;
};


/**
 * Gets the border color of a Thing.
 * @returns {Color} The color of the Thing's border.
 */
Thing.prototype.getBorderColor = function(){
    return this.stroke;
};

/**
 * Sets the width of a Thing's border.
 * Throws an error if there is not 1 argument.
 * @param {number} width - The resulting width of the Thing's border.
 */
Thing.prototype.setBorderWidth = function(width){
    if (arguments.length !== 1) {
        throw new Error('You should pass exactly 1 argument to setBorderWidth.');
    }
    this.lineWidth = width;
    this.hasBorder = true;
};

/**
 * Gets the width of the Thing's border.
 * @returns {number} The width of the Thing's border.
 */
Thing.prototype.getBorderWidth = function(){
    return this.lineWidth;
};

/**
 * Changes the possition of a thing by a specified x and y amount.
 * @param {number} dx - The resulting change in the Thing's x position.
 * @param {number} dy - The resulting change in the Thing's y position.
 */
Thing.prototype.move = function(dx, dy){
    if (arguments.length !== 2) {
        throw new Error('You should pass exactly 2 arguments to move.');
    }
    if (typeof dx !== 'number' && isNaN(dx)) {
        throw new TypeError('Invalid number for dx.');
    }
    if (typeof dy !== 'number' && isNaN(dy)) {
        throw new TypeError('Invalid number for dy.');
    }
    this.x += dx;
    this.y += dy;
};

/**
 * Gets the x position of the Thing.
 * @returns {number} The x position of the Thing.
 */
Thing.prototype.getX = function(){
    return this.x;
};

/**
 * Gets the y position of the Thing.
 * @returns {number} The y position of the Thing.
 */
Thing.prototype.getY = function(){
    return this.y;
};

/**
 * This function is overridden in subclasses of Thing.
 */
Thing.prototype.draw = function(){

};

/**
 * Check if a given point is within the Thing.
 * This function only works in subclasses of Thing.
 * @param {number} x - The x coordinate of the point being checked.
 * @param {number} y - The y coordinate of the point being checked.
 * @returns {boolean} Whether the point x, y is within the Thing.
 */
Thing.prototype.containsPoint = function(x, y){
    return false;
};

module.exports = Thing;
