(function(requirejs, require, define) {
    define(
'video/00_resizer.js',
[],
function() {
    var Resizer = function(params) {
        var defaults = {
                container: window,
                element: null,
                containerRatio: null,
                elementRatio: null
            },
            callbacksList = [],
            delta = {
                height: 0,
                width: 0
            },
            module = {},
            mode = null,
            config;

        var initialize = function(params) {
            if (!config) {
                config = defaults;
            }

            config = $.extend(true, {}, config, params);

            if (!config.element) {
                console.log(
                    'Required parameter `element` is not passed.'
                );
            }

            return module;
        };

        var getData = function() {
            var container = $(config.container),
                containerWidth = container.width() + delta.width,
                containerHeight = container.height() + delta.height,
                containerRatio = config.containerRatio,

                element = $(config.element),
                elementRatio = config.elementRatio;

            if (!containerRatio) {
                containerRatio = containerWidth / containerHeight;
            }

            if (!elementRatio) {
                elementRatio = element.width() / element.height();
            }

            return {
                containerWidth: containerWidth,
                containerHeight: containerHeight,
                containerRatio: containerRatio,
                element: element,
                elementRatio: elementRatio
            };
        };

        var align = function() {
            var data = getData();

            switch (mode) {
            case 'height':
                alignByHeightOnly();
                break;

            case 'width':
                alignByWidthOnly();
                break;

            default:
                if (data.containerRatio >= data.elementRatio) {
                    alignByHeightOnly();
                } else {
                    alignByWidthOnly();
                }
                break;
            }

            fireCallbacks();

            return module;
        };

        var alignByWidthOnly = function() {
            var data = getData(),
                height = data.containerWidth / data.elementRatio;

            data.element.css({
                'height': height,
                'width': data.containerWidth,
                'top': 0.5 * (data.containerHeight - height),
                'left': 0
            });

            return module;
        };

        var alignByHeightOnly = function() {
            var data = getData(),
                width = data.containerHeight * data.elementRatio;

            data.element.css({
                'height': data.containerHeight,
                'width': data.containerHeight * data.elementRatio,
                'top': 0,
                'left': 0.5 * (data.containerWidth - width)
            });

            return module;
        };

        var setMode = function(param) {
            if (_.isString(param)) {
                mode = param;
                align();
            }

            return module;
        };

        var setElement = function(element) {
            config.element = element;

            return module;
        };

        var addCallback = function(func) {
            if ($.isFunction(func)) {
                callbacksList.push(func);
            } else {
                console.error('[Video info]: TypeError: Argument is not a function.');
            }

            return module;
        };

        var addOnceCallback = function(func) {
            if ($.isFunction(func)) {
                var decorator = function() {
                    func();
                    removeCallback(func);
                };

                addCallback(decorator);
            } else {
                console.error('TypeError: Argument is not a function.');
            }

            return module;
        };

        var fireCallbacks = function() {
            $.each(callbacksList, function(index, callback) {
                callback();
            });
        };

        var removeCallbacks = function() {
            callbacksList.length = 0;

            return module;
        };

        var removeCallback = function(func) {
            var index = $.inArray(func, callbacksList);

            if (index !== -1) {
                return callbacksList.splice(index, 1);
            }
        };

        var resetDelta = function() {
            delta['height'] = delta['width'] = 0;

            return module;
        };

        var addDelta = function(value, side) {
            if (_.isNumber(value) && _.isNumber(delta[side])) {
                delta[side] += value;
            }

            return module;
        };

        var substractDelta = function(value, side) {
            if (_.isNumber(value) && _.isNumber(delta[side])) {
                delta[side] -= value;
            }

            return module;
        };

        var destroy = function() {
            var data = getData();
            data.element.css({
                'height': '', 'width': '', 'top': '', 'left': ''
            });
            removeCallbacks();
            resetDelta();
            mode = null;
        };

        initialize.apply(module, arguments);

        return $.extend(true, module, {
            align: align,
            alignByWidthOnly: alignByWidthOnly,
            alignByHeightOnly: alignByHeightOnly,
            destroy: destroy,
            setParams: initialize,
            setMode: setMode,
            setElement: setElement,
            callbacks: {
                add: addCallback,
                once: addOnceCallback,
                remove: removeCallback,
                removeAll: removeCallbacks
            },
            delta: {
                add: addDelta,
                substract: substractDelta,
                reset: resetDelta
            }
        });
    };

    return Resizer;
});
}(RequireJS.requirejs, RequireJS.require, RequireJS.define));
