window.cmu = window.cmu || {};

(function (ns) {

    ns.gridCanvas = function (spec, my) {
        var that;

        spec = spec || {};
        spec.drawDelay = spec.drawDelay !== undefined ? spec.drawDelay : 50;
        spec.useDotOutline = spec.useDotOutline !== undefined ? spec.useDotOutline : true;
        spec.useObjectOutline = spec.useObjectOutline !== undefined ? spec.useObjectOutline : true;
        spec.outlineOffsetDot = spec.outlineOffsetDot !== undefined ? spec.outlineOffsetDot : 8;
        spec.outlineOffsetObject = spec.outlineOffsetObject !== undefined ? spec.outlineOffsetObject : spec.outlineOffsetDot;
        spec.lineWidth = spec.lineWidth || 2;
        spec.dashPattern = spec.dashPattern || [3, 3];
        spec.elementId = spec.elementId || 'gridCanvas';
        spec.container = spec.container || $('body');

        // ------------------------------------------------------------------
        // Shared properties
        // ------------------------------------------------------------------

        my = my || {};
        my.logger = gj.logging.getLogger('cmu.gridCanvas');
        my.canvas = null;
        my.ctx = null;

        my.activeObject = null;
        // my.activeObject = $('.treasuryGrid ul.images li').eq(1);

        my.dotCenter = [0, 0];
        my.dotRadius = null;

        // Important: inherit from canvasDrawer()
        that = gj.canvasDrawer(spec, my);

        // ------------------------------------------------------------------
        // Private properties
        // ------------------------------------------------------------------

        var drawTimeout;

        // ------------------------------------------------------------------
        // Private methods
        // ------------------------------------------------------------------

        my.initExtra = function () {
            my.logger.debug('initExtra()');

            // Make the canvas full screen
            my.canvas.width = $(document).width();
            my.canvas.height = $(document).height();

            my.dotCenter = getElementCenter(spec.originObject);
            my.dotRadius = Math.ceil(spec.originObject.width() / 2);
        };

        my.draw = function () {
            my.logger.debug('draw()');

            my.clear();

            if (my.activeObject) {
                drawLineToActiveObject();
            }
        };

        var drawLineToActiveObject = function () {
            my.logger.debug('drawLineToActiveObject()');

            var ctx = my.ctx;

            var activeImage = my.activeObject.find('a img');
            var imageCenter = getElementCenter(activeImage);
            var lineStart, lineEnd;

            var delta = [
                imageCenter[0] - my.dotCenter[0],
                imageCenter[1] - my.dotCenter[1]
            ];
            var angle = Math.atan2(delta[1], delta[0]);

            if (spec.useDotOutline) {
                var circlePoint = getCirclePoint(my.dotRadius + spec.outlineOffsetDot, angle);
                lineStart = [
                    circlePoint[0] + my.dotCenter[0],
                    circlePoint[1] + my.dotCenter[1]
                ];
            } else {
                lineStart = my.dotCenter;
            }

            if (spec.useObjectOutline) {
                var squareSize = activeImage.width() + spec.outlineOffsetObject * 2;
                var squarePoint = getSquarePoint(squareSize, angle);
                lineEnd = [
                    imageCenter[0] + squarePoint[0],
                    imageCenter[1] + squarePoint[1],
                ]
            } else {
                lineEnd = imageCenter;
            }

            if (0) {
                ctx.lineWidth = 4;
                ctx.beginPath();
                ctx.moveTo(my.dotCenter[0], my.dotCenter[1]);
                ctx.lineTo(imageCenter[0], imageCenter[1]);
            } else {
                ctx.lineWidth = spec.lineWidth;
                ctx.beginPath();
                gj.canvas.dashedLine(ctx, lineStart[0], lineStart[1], lineEnd[0], lineEnd[1], spec.dashPattern);
            }
            ctx.stroke();
        };

        var getElementCenter = function (element) {
            var offset = element.offset();
            var center = [
                offset.left + element.width() / 2,
                offset.top - $(window).scrollTop() + element.height() / 2
            ];
            return center;
        };

        var getCirclePoint = function (radius, angle) {
            var x = Math.cos(angle) * radius;
            var y = Math.sin(angle) * radius;
            return [x, y];
        }

        var getSquarePoint = function (size, angle) {
            var point;
            var squareHalf = size / 2;
            var angleDegrees = angle * 180 / Math.PI;
            angleDegrees += 180; // To always make it between 0 and 360 instead of -180 to 180
            angleDegrees += 45; // To allow multiples of 90 in comparing
            if (angleDegrees > 360) {
                angleDegrees -= 360;
            }

            // Hitting image on right side
            if (angleDegrees < 90) {
                point = [
                    squareHalf,
                    squareHalf * Math.tan(angle)
                ];

            // Hitting image on bottom
            } else if (angleDegrees < 180) {
                point = [
                    squareHalf * Math.cos(angle) * -1,
                    squareHalf
                ];

            // Hitting image on left side
            } else if (angleDegrees < 270) {
                point = [
                    squareHalf * -1,
                    squareHalf * Math.tan(angle) * -1
                ];

            // Hitting image on top
            } else {
                point = [
                    squareHalf * Math.cos(angle) * -1,
                    squareHalf * -1
                ];
            }
            return point;
        };

        // ------------------------------------------------------------------
        // Public methods
        // ------------------------------------------------------------------

        that.setActiveObject = function (newObject) {
            my.logger.debug('setActiveObject()', newObject);
            my.activeObject = newObject;

            if (drawTimeout) {
                window.clearTimeout(drawTimeout);
            }

            if (my.activeObject) {
                drawTimeout = window.setTimeout(function () {
                    my.draw();
                }, spec.drawDelay);
            } else {
                my.draw(); // Draw immediately for mouseleaves
            }
        };

        // ------------------------------------------------------------------
        // Constructor
        // ------------------------------------------------------------------

        my.init();
        return that;
    };

})(window.cmu);

