ig.module(
	'impact.image'
)
.defines(function () {
    "use strict";

    ig.Image = ig.Class.extend({
        data: null,
        width: 0,
        height: 0,
        loaded: false,
        failed: false,
        loadCallback: null,
        path: '',


        staticInstantiate: function (path) {
            return ig.Image.cache[path] || null;
        },


        init: function (path) {
            this.path = path;
            this.load();
        },


        load: function (loadCallback) {
            if (this.loaded) {
                if (loadCallback) {
                    loadCallback(this.path, true);
                }
                return;
            }
            else if (!this.loaded && ig.ready) {
                this.loadCallback = loadCallback || null;

                this.data = new Image();
                this.data.onload = this.onload.bind(this);
                this.data.onerror = this.onerror.bind(this);
                this.data.src = ig.prefix + this.path + ig.nocache;
            }
            else {
                ig.addResource(this);
            }

            ig.Image.cache[this.path] = this;
        },


        reload: function () {
            this.loaded = false;
            this.data = new Image();
            this.data.onload = this.onload.bind(this);
            this.data.src = this.path + '?' + Date.now();
        },


        onload: function (event) {
            this.width = this.data.width;
            this.height = this.data.height;
            this.loaded = true;

            if (ig.system.scale != 1) {
                this.resize(ig.system.scale);
            }

            if (this.loadCallback) {
                this.loadCallback(this.path, true);
            }
        },


        onerror: function (event) {
            this.failed = true;

            if (this.loadCallback) {
                this.loadCallback(this.path, false);
            }
        },


        resize: function (scale) {
            // Nearest-Neighbor scaling

            // The original image is drawn into an offscreen canvas of the same size
            // and copied into another offscreen canvas with the new size. 
            // The scaled offscreen canvas becomes the image (data) of this object.

            var origPixels = ig.getImagePixels(this.data, 0, 0, this.width, this.height);

            var widthScaled = this.width * scale;
            var heightScaled = this.height * scale;

            var scaled = ig.$new('canvas');
            scaled.width = widthScaled;
            scaled.height = heightScaled;
            var scaledCtx = scaled.getContext('2d');
            var scaledPixels = scaledCtx.getImageData(0, 0, widthScaled, heightScaled);

            for (var y = 0; y < heightScaled; y++) {
                for (var x = 0; x < widthScaled; x++) {
                    var index = (Math.floor(y / scale) * this.width + Math.floor(x / scale)) * 4;
                    var indexScaled = (y * widthScaled + x) * 4;
                    scaledPixels.data[indexScaled] = origPixels.data[index];
                    scaledPixels.data[indexScaled + 1] = origPixels.data[index + 1];
                    scaledPixels.data[indexScaled + 2] = origPixels.data[index + 2];
                    scaledPixels.data[indexScaled + 3] = origPixels.data[index + 3];
                }
            }
            scaledCtx.putImageData(scaledPixels, 0, 0);
            this.data = scaled;
        },


        draw: function (targetX, targetY, sourceX, sourceY, width, height) {
            if (!this.loaded) { return; }

            var scale = ig.system.scale;
            sourceX = sourceX ? sourceX * scale : 0;
            sourceY = sourceY ? sourceY * scale : 0;
            width = (width ? width : this.width) * scale;
            height = (height ? height : this.height) * scale;

            ig.system.context.drawImage(
			this.data, sourceX, sourceY, width, height,
			ig.system.getDrawPos(targetX),
			ig.system.getDrawPos(targetY),
			width, height
		);

            ig.Image.drawCount++;
        },

        drawTile: function (targetX, targetY, tile, tileWidth, tileHeight, flipX, flipY) {
            tileHeight = tileHeight ? tileHeight : tileWidth;

            if (!this.loaded || tileWidth > this.width || tileHeight > this.height) { return; }

            var scale = ig.system.scale;
            var tileWidthScaled = Math.floor(tileWidth * scale);
            var tileHeightScaled = Math.floor(tileHeight * scale);

            var scaleX = flipX ? -1 : 1;
            var scaleY = flipY ? -1 : 1;

            if (flipX || flipY) {
                ig.system.context.save();
                ig.system.context.scale(scaleX, scaleY);
            }
            ig.system.context.drawImage(
			this.data,
			(Math.floor(tile * tileWidth) % this.width) * scale,
			(Math.floor(tile * tileWidth / this.width) * tileHeight) * scale,
			tileWidthScaled,
			tileHeightScaled,
			ig.system.getDrawPos(targetX) * scaleX - (flipX ? tileWidthScaled : 0),
			ig.system.getDrawPos(targetY) * scaleY - (flipY ? tileHeightScaled : 0),
			tileWidthScaled,
			tileHeightScaled
		);
            if (flipX || flipY) {
                ig.system.context.restore();
            }

            ig.Image.drawCount++;
        }
    });

    ig.Image.drawCount = 0;
    ig.Image.cache = {};
    ig.Image.reloadCache = function () {
        for (var path in ig.Image.cache) {
            ig.Image.cache[path].reload();
        }
    };

});