var Twirl = (function () {

    "use strict";

    var _model,
        _duration = 0,
        _sync,
        _width,
        _height,
        _ctx,
        _preflightCallback;

    var _ctxBrush,
        _vctx,
        _blob = [],
        BLOBCOUNT = 7,
        COL_BRUSH_SHADOW = '#f32201';

    var _imgW,
        _imgH;

    var _boxPadding;

    var _multiply,
        _ctxCombine,
        _slice,
        _sliceCtx,
        _glow;

    var _logoStab,
        _logoAngle,
        _logoStripes,
        _logoMaxAmp;

    function preflight(callbackFn, duration, model) {

        _preflightCallback = callbackFn;

        _duration = duration;
        _model = model;

        _sync = _model.sync;
        _width = _model.width();
        _height = _model.height();

        initSync();

        _ctx = _model.twoDeeRenderer;

        var canvas = document.createElement('canvas');
        canvas.width = _width;
        canvas.height = _height;
        _ctxBrush = canvas.getContext('2d');

        canvas = document.createElement('canvas');
        canvas.width = _width;
        canvas.height = _height;
        _ctxCombine = canvas.getContext('2d');

        _multiply = new Multiply();
        _multiply.setContext(_ctxCombine);
        _multiply.setImage(Meat.boldini);

        _imgW = Math.round(Meat.boldini_transp.width / 1920 * _width);
        _imgH = Math.round(Meat.boldini_transp.height / 1080 * _height);

        canvas = document.createElement('canvas');
        canvas.width = _width;
        canvas.height = _height;
        _sliceCtx = canvas.getContext('2d');

        _slice = new Slice();
        _slice.setContext(_sliceCtx);

        _preflightCallback();
    }

    function init() {
        _model.on("resize", resize);

        _boxPadding = Math.round(45 / 1920 * _width);
        _vctx = _model.vignette;
        _vctx.clearRect(0, 0, _width, _height);
        _vctx.drawImage(Meat.vignette, 0, 0, _width, _height);

        _blob = [];

        _boxPadding = 37 / 1920 * _width;

        if (_ctx.setLineDash)
            _ctx.setLineDash([0]);
        else {
            try {
                _ctx.mozDash = [1];
            } catch (error) {
            }
        }

        for (var i = 0; i < BLOBCOUNT; i++) {

            var w = Random.range(200 / 1920 * _width, 400 / 1920 * _width);

            _blob.push({
                "rotation": Random.float() * 180,
                "width": w,
                "x": Random.range(0, _width - w),
                "y": Random.range(0, _height - w),
                "deltaX": Random.range(.5, 15),
                "deltaY": Random.range(.5, 15)
            });
        }
    }

    function setNewPosition() {

        for (var i = 0; i < BLOBCOUNT; i++) {

            var blob = _blob[i];

            if (blob.x < blob.width || blob.x > _width - blob.width) {
                blob.deltaX = -blob.deltaX;
            }

            if (blob.y < blob.width || blob.y > _height - blob.width) {
                blob.deltaY = -blob.deltaY;
            }

            blob.x += blob.deltaX;
            blob.y += blob.deltaY;
        }
    }

    var PI_PI = Math.PI * 2;

    function drawBlobToOffscreen(diameter) {

        _ctxBrush.fillStyle = COL_BRUSH_SHADOW;

        //4 circles
        //main
        var middle = .5 * ((diameter * 2) - diameter),
            radius = diameter * .15;

        _ctxBrush.beginPath();
        _ctxBrush.arc(middle, middle, radius, 0, PI_PI);
        _ctxBrush.closePath();

        //tl
        //_ctxBrush.beginPath();
        _ctxBrush.arc(middle - radius, middle - radius, radius * .5, 0, PI_PI);
        _ctxBrush.closePath();

        //tr
        //_ctxBrush.beginPath();
        _ctxBrush.arc(middle + radius, middle - radius, radius * .5, 0, PI_PI);
        _ctxBrush.closePath();

        //bl
        //_ctxBrush.beginPath();
        _ctxBrush.arc(middle - radius, middle + radius, radius * .5, 0, PI_PI, false);
        _ctxBrush.closePath();

        //br
        //_ctxBrush.beginPath();
        _ctxBrush.arc(middle + radius, middle + radius, radius * .5, 0, PI_PI, false);
        _ctxBrush.closePath();
        _ctxBrush.fill();
    }

    function drawBlob(xPos, yPos, rotation, diameter) {

        _ctxBrush.canvas.width = (diameter * 2);
        _ctxBrush.canvas.height = (diameter * 2);

        _ctxBrush.translate((diameter * 2) * .5, (diameter * 2) * .5);
        _ctxBrush.rotate(rotation * Math.PI / 180);
        _ctxBrush.translate(-(diameter * 2) * .5, -(diameter * 2) * .5);

        drawBlobToOffscreen(diameter);

        _ctxCombine.drawImage(_ctxBrush.canvas, xPos, yPos);
    }

    function initSync() {
        _logoStab = _sync.getTrack('logoStab');
        _logoAngle = _sync.getTrack('logoAngle');
        _logoStripes = _sync.getTrack('logoStripes');
        _logoMaxAmp = _sync.getTrack('logoMaxAmp');
        _glow = _sync.getTrack('glow');
    }

    function render(sceneTime, floatBeat, frameDelta, row) {

        var stripes = _logoStripes.getValue(row);

        if (stripes >= 1) {
            _sliceCtx.drawImage(_ctx.canvas, 0, 0);
            _slice.setAngle(_logoAngle.getValue(row));
            _slice.setStripes(_logoStripes.getValue(row));
            _slice.setMaxAmplitude(_logoMaxAmp.getValue(row));
            _slice.setAmplitudeMultiplicator(_logoStab.getValue(row));

            _slice.render(row);

            _ctx.drawImage(_sliceCtx.canvas, 0, 0);

        } else {

            _vctx.clearRect(0, 0, _width, _height);
            _vctx.strokeStyle = "#ffffff";
            _vctx.fillStyle = "#ffffff";

            _vctx.lineWidth = Math.round(2 / 1920 * _width);
            _vctx.strokeRect(_boxPadding, _boxPadding, _width - (2 * _boxPadding), _height - (2 * _boxPadding));

            _vctx.beginPath();
            _vctx.moveTo(_boxPadding, _boxPadding * 2);
            _vctx.lineTo(_boxPadding * 2, _boxPadding);
            _vctx.lineTo(_boxPadding * 2, _boxPadding * 2);
            _vctx.closePath();
            _vctx.fill();

            _vctx.drawImage(Meat.vignette, 0, 0, _width, _height);

            _ctx.fillStyle = "rgba(249,224,182,.1)";
            _ctx.fillRect(0, 0, _width, _height);

            _ctx.drawImage(Meat.boldini_transp, _width - _imgW, _height - _imgH, _imgW, _imgH);

            _ctx.save();

            setNewPosition();

            _ctxCombine.clearRect(0, 0, _width, _height);

            _ctxCombine.strokeStyle = "#ffffff";
            _ctxCombine.lineWidth = 3 / 1920 * _width;

            for (var i = 0; i < BLOBCOUNT; i++) {
                _blob[i].rotation += frameDelta * .333;
                drawBlob(_blob[i].x, _blob[i].y, _blob[i].rotation, _blob[i].width);
            }

            _multiply.render(Math.round(_width - _imgW), Math.round(_height - _imgH));
            _ctx.drawImage(_ctxCombine.canvas, 0, 0);

            _ctx.globalCompositeOperation = "source-over";

            var offsetX = Math.sin(row / 10) * 2,
                offsetY = Math.cos(row / 10) * 2;

            _ctx.translate(-1.5 + offsetX, -1.5 + offsetY);
            _ctx.scale(1.01, 1.01);
            _ctx.drawImage(_ctx.canvas, (_width - (_width * 1.01)) / 2, (_height - (_height * 1.01)) / 2);
            _ctx.restore();
        }

        var glow = _glow.getValue(row);
        if (glow > 0) {
            var glowScale = 1;

            for (i = 0; i < 4; i++) {
                glowScale += .01;
                var sW = _width * glowScale,
                    sH = _height * glowScale;
                _ctx.save();
                _ctx.globalCompositeOperation = 'lighter';
                _ctx.globalAlpha = glow;
                _ctx.drawImage(_ctx.canvas, (_width - sW) / 2, (_height - sH) / 2, sW, sH);
                _ctx.restore();
            }
        }
    }

    function onBeat(integerBeat, msTime, majorBeat, minorBeat) {
    }

    function clear() {
        _model.on("resize", function () {
        });
    }

    function resize(width, height) {
        _width = width;
        _height = height;
    }

    return {
        preflight: preflight,
        init: init,
        render: render,
        onBeat: onBeat,
        clear: clear,
        resize: resize
    };
}());