'use strict';

var Thing = require('./thing.js');

WebImage.NOT_LOADED = 1;
WebImage.DONE = 2;

WebImage.NUM_CHANNELS = 4;
WebImage.RED = 0;
WebImage.GREEN = 1;
WebImage.BLUE = 2;
WebImage.ALPHA = 3;

/**
 * @constructor
 * @augments Thing
 * @param {string} filename - Filepath to the image
 */
function WebImage(filename) {
    if (typeof filename !== 'string') {
        throw new TypeError('You must pass a string to <span class="code">new WebImage(filename)</span> that has the image\'s location.');
    }
    Thing.call(this);
    var self = this;

    this.image = new Image();
    this.image.src = filename;
    this.filename = filename;
    this.width = WebImage.NOT_LOADED;
    this.height = WebImage.NOT_LOADED;
    this.image.onload = function(){
        self.checkDimensions();
        if(self.loadfn){
            self.loadfn();
        }

    };
    this.set = 0;
    this.type = 'WebImage';
}

WebImage.prototype = new Thing();
WebImage.prototype.constructor = WebImage;

/**
 * Set a function to be called when the WebImage is loaded.
 * @param {function} callback - A function
 */
WebImage.prototype.loaded = function(callback) {
    this.loadfn = callback;
};

/**
 * Set the image of the WebImage.
 * @param {string} filename - Filepath to the image
 */
WebImage.prototype.setImage = function(filename) {
    var self = this;

    this.image = new Image();
    this.image.src = filename;
    this.filename = filename;
    this.width = WebImage.NOT_LOADED;
    this.height = WebImage.NOT_LOADED;
    this.image.onload = function(){
        self.checkDimensions();
        if(self.loadfn){
            self.loadfn();
        }

    };
    this.set = 0;
};

/**
 * Reinforce the dimensions of the WebImage based on the image it displays.
 */
WebImage.prototype.checkDimensions = function() {
    if(this.width == WebImage.NOT_LOADED){
        this.width = this.image.width;
        this.height = this.image.height;
    }
};

/**
 * Draws the WebImage in the canvas.
 * @param {CodeHSGraphics} __graphics__ - Instance of the __graphics__ module.
 */
WebImage.prototype.draw = function(__graphics__) {
    this.checkDimensions();
    var context = __graphics__.getContext();
    context.beginPath();

    context.drawImage(this.image, this.x, this.y, this.width, this.height);
    // context.strokeStyle = this.stroke;
    // context.fillStyle = this.color;
    // context.lineWidth = this.lineWidth;
    /* HACKY */
//  if(this.set != WebImage.DONE){
 //       context.drawImage(this.image, this.x, this.y, this.width, this.height);
//      this.data = context.getImageData(this.x, this.y, this.width, this.height);
//      this.set++;
//  }else{
//      /* TODO: Getting called twice??? */
//      context.putImageData(this.data, this.x, this.y);
//  }
  context.closePath();
};

/**
 * Assign the ImageData of the canvas at the position of the image,
 * essentially assigning the ImageData.
 * Read more at https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/getImageData
 */
WebImage.prototype.getData = function(__graphics__){
    var context = __graphics__.getContext();
    //context.drawImage(this.image, this.x, this.y, this.width, this.height);
    this.data = context.getImageData(this.x, this.y, this.width, this.height);
};

/**
 * Checks if the passed point is contained in the WebImage.
 * @param {number} x - The x coordinate of the point being tested.
 * @param {number} y - The y coordinate of the point being tested.
 * @returns {boolean} Whether the passed point is contained in the WebImage.
 */
WebImage.prototype.containsPoint = function(x, y){
    return x >= this.x && x <= this.x + this.width &&
           y >= this.y && y <= this.y + this.height;
};

/**
 * Gets the width of the WebImage.
 * @returns {number} Width of the WebImage.
 */
WebImage.prototype.getWidth = function(){
    return this.width;
};

/**
 * Gets the height of the WebImage.
 * @returns {number} Height of the WebImage.
 */
WebImage.prototype.getHeight = function(){
    return this.height;
};

/**
 * Sets the size of the WebImage.
 * @param {number} width - The desired width of the resulting WebImage.
 * @param {number} height - The desired height of the resulting WebImage.
 */
WebImage.prototype.setSize = function(width, height){
    this.width = width;
    this.height = height;
};

/* Get and set pixel functions */

/**
 * Gets a pixel at the given x and y coordinates.
 * Read more here:
 * https://developer.mozilla.org/en-US/docs/Web/API/ImageData/data
 * @param {number} x - The x coordinate of the point being tested.
 * @param {number} y - The y coordinate of the point being tested.
 * @returns {integer} An integer between 0 and 255.
 */
WebImage.prototype.getPixel = function(x, y){
    var index = WebImage.NUM_CHANNELS * (y * this.width + x);
    var pixel = [
            this.data.data[index + WebImage.RED],
            this.data.data[index + WebImage.GREEN],
            this.data.data[index + WebImage.BLUE],
            this.data.data[index + WebImage.ALPHA]
                ];
    return pixel;
};

/**
 * Get the red value at a given location in the image.
 * @param {number} x - The x coordinate of the point being tested.
 * @param {number} y - The y coordinate of the point being tested.
 * @returns {integer} An integer between 0 and 255.
 */
WebImage.prototype.getRed = function(x, y){
    return this.getPixel(x, y)[WebImage.RED];
};

/**
 * Get the green value at a given location in the image.
 * @param {number} x - The x coordinate of the point being tested.
 * @param {number} y - The y coordinate of the point being tested.
 * @returns {integer} An integer between 0 and 255.
 */
WebImage.prototype.getGreen = function(x, y){
    return this.getPixel(x, y)[WebImage.GREEN];
};

/**
 * Get the blue value at a given location in the image.
 * @param {number} x - The x coordinate of the point being tested.
 * @param {number} y - The y coordinate of the point being tested.
 * @returns {integer} An integer between 0 and 255.
 */
WebImage.prototype.getBlue = function(x, y){
    return this.getPixel(x, y)[WebImage.BLUE];
};

/**
 * Get the alpha value at a given location in the image.
 * @param {number} x - The x coordinate of the point being tested.
 * @param {number} y - The y coordinate of the point being tested.
 * @returns {integer} An integer between 0 and 255.
 */
WebImage.prototype.getAlpha = function(x, y){
    return this.getPixel(x, y)[WebImage.ALPHA];
};

/**
 * Set the `component` value at a given location in the image to `val`.
 * @param {number} x - The x coordinate of the point being tested.
 * @param {number} y - The y coordinate of the point being tested.
 * @param {integer} component - Integer representing the color value to
 * be set. R, G, B = 0, 1, 2, respectively.
 * @param {integer} val - The desired value of the `component` at the pixel.
 * Must be between 0 and 255.
 */
WebImage.prototype.setPixel = function(x, y, component, val){
    var index = WebImage.NUM_CHANNELS * (y * this.width + x);
    this.data.data[index + component] = val;
};

/**
 * Set the red value at a given location in the image to `val`.
 * @param {number} x - The x coordinate of the point being tested.
 * @param {number} y - The y coordinate of the point being tested.
 * @param {integer} val - The desired value of the red component at the pixel.
 * Must be between 0 and 255.
 */
WebImage.prototype.setRed = function(x, y, val){
    this.setPixel(x, y, WebImage.RED, val);
};

/**
 * Set the green value at a given location in the image to `val`.
 * @param {number} x - The x coordinate of the point being tested.
 * @param {number} y - The y coordinate of the point being tested.
 * @param {integer} val - The desired value of the green component at the pixel.
 * Must be between 0 and 255.
 */
WebImage.prototype.setGreen = function(x, y, val){
    this.setPixel(x, y, WebImage.GREEN, val);
};

/**
 * Set the blue value at a given location in the image to `val`.
 * @param {number} x - The x coordinate of the point being tested.
 * @param {number} y - The y coordinate of the point being tested.
 * @param {integer} val - The desired value of the blue component at the pixel.
 * Must be between 0 and 255.
 */
WebImage.prototype.setBlue = function(x, y, val){
    this.setPixel(x, y, WebImage.BLUE, val);
};

/**
 * Set the alpha value at a given location in the image to `val`.
 * @param {number} x - The x coordinate of the point being tested.
 * @param {number} y - The y coordinate of the point being tested.
 * @param {integer} val - The desired value of the alpha component at the
 * pixel.
 * Must be between 0 and 255.
 */
WebImage.prototype.setAlpha = function(x, y, val){
    this.setPixel(x, y, WebImage.ALPHA, val);
};

module.exports = WebImage;
