var portalManager = (function () {
    var seed = 0,
        modal;

    modal = '<div class="modal fade" id="{0}" tabindex="-1" role="dialog" aria-hidden="true" style="display:none">' +
        '<div class="modal-dialog">' +
            '<div class="modal-content">' +
                '<div class="modal-header">' +
                    '<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>' +
                    '<h4 class="modal-title">{1}</h4>' +
                '</div>' +
                '<div class="modal-body"></div>' +
                //'<div class="modal-footer">' +
                //    '<button type="button" class="btn btn-default" data-dismiss="modal">{2}</button>' +
                //'</div>' +
            '</div>' +
        '</div>' +
    '</div>';

    String.prototype.format = function () {
        var s = this,
            i = arguments.length;

        while (i--) {
            s = s.replace(new RegExp('\\{' + i + '\\}', 'gm'), arguments[i]);
        }
        return s;
    }

    return {

        loadScripts: function (id, interval, html, callback) {

            var scriptTagRe = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig,
                srcRe = /\ssrc=([\'\"])(.*?)\1/i,
                typeRe = /\stype=([\'\"])(.*?)\1/i,
                hd, match, attrs, srcMatch, typeMatch, el, s,
                bufferedjs = '',
                scriptImported = [],
                pos = 0,
                execScriptTries = 1000,
                intervalExecScript;

            function ScriptLoadHandler(position) {
                this.position = position;
                this.eventHandler = function () {
                    scriptImported[position] = true;
                };
            }

            function execCallback(cb) {
                if (typeof cb == 'function') {
                    cb.apply(this);
                }
            }

            if (!(el = document.getElementById(id))) {
                return false;
            }
            clearInterval(interval);
            el.parentNode.removeChild(el);
            hd = document.getElementsByTagName('head')[0];


            while ((match = scriptTagRe.exec(html))) {
                attrs = match[1];
                srcMatch = attrs ? attrs.match(srcRe) : false;
                if (srcMatch && srcMatch[2]) {
                    s = document.createElement("script");
                    s.src = srcMatch[2];
                    typeMatch = attrs.match(typeRe);
                    if (typeMatch && typeMatch[2]) {
                        s.type = typeMatch[2];
                    }

                    scriptImported[pos] = false;
                    handler = new ScriptLoadHandler(pos);


                    if (s.addEventListener) {
                        s.addEventListener("load", handler.eventHandler, false);
                    } else if (s.readyState) {
                        s.onreadystatechange = handler.eventHandler;
                    }
                    pos++;


                    hd.appendChild(s);
                } else if (match[2] && match[2].length > 0) {

                    typeMatch = attrs.match(typeRe);
                    if (typeMatch && typeMatch[2] && typeMatch[2] == 'text/javascript') {
                        bufferedjs += '\n' + match[2];
                    }
                }
            }


            /*
             * The JS execution block (code below) cannot be executed immediately after
             * the script import block (code above), since if there's a dependency from
             * a JS file and this file hasn't already been imported, undefined errors
             * occur. The solution is to call the JS execution block only when all the
             * scripts have already been imported. This can be accomplished by checking
             * if all the elements in the scriptImported array are true. The loop has a
             * 10 milliseconds gap and runs a maximum of 1000 times, after that give up
             * (time out) we let the errors occur;
             */
            if (bufferedjs != '') {
                intervalExecScript = setInterval(function () {
                    // Wait until all scripts are loaded or break after 1000 tries
                    var allScriptsLoaded = true;
                    for (var i = 0; i < scriptImported.length; i++) {
                        allScriptsLoaded = allScriptsLoaded && scriptImported[i];
                    }
                    if (allScriptsLoaded) {
                        try {
                            if (window.execScript) {
                                window.execScript(bufferedjs);
                            } else {
                                window.eval(bufferedjs);
                            }
                        }
                        catch (e) {
                            throw e;
                        }
                        finally {
                            clearInterval(intervalExecScript);
                            execCallback(callback);
                        }
                    } else if (execScriptTries == 0) {
                        clearInterval(intervalExecScript);
                        execCallback(callback);
                    }
                    execScriptTries--;
                }, 10);
            } else {
                execCallback(callback);
            }
        },



        update: function (el, html, callback) {
            var me = this,
                id, interval,
                scriptTagRe = /(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig;

            html = html || '';

            id = ++seed;
            html += '<span id="' + id + '"></span>';

            interval = setInterval(function () {
                me.loadScripts(id, interval, html, callback);
            }, 20);

            el.innerHTML = html.replace(scriptTagRe, '');
        },

        computeFrame: function (frame, isPreview) {
            var frameId = $(frame).attr('data-frame-id'),
                portalId = $(frame).attr('data-portal-id'),
                templateId = $(frame).attr('data-template-id'),
                data = { frameId: frameId, portalId: portalId, templateId: templateId };

            $(frame).removeAttr('data-frame-id');
            $(frame).removeAttr('data-portal-id');
            $(frame).removeAttr('data-template-id');

            $.ajax({
                url: 'cmsmanagementservice.svc/' + (isPreview ? 'preview' : 'compute') + 'portalframe?_dc=' + new Date().getTime(),
                data: isPreview ? JSON.stringify(data) : data,
                contentType: 'application/json; charset=utf-8',
                dataType: 'json',
                type: isPreview ? 'POST' : 'GET',
                success: function (result, opts) {
                    if (result && result.success) {
                        this.update(frame, result.d, this.onLoad.call(this));

                        $(document).trigger('framecompute', frameId);
                    }
                },
                context: this
            });
        },

        computeEmbed: function (frame, isPreview) {
            var me = this,
                embed = $(frame).attr('data-embed'),
                data = { data: $.base64.encode(embed) },
                embedObject = $.parseJSON(embed),
                id = 'embed-' + ++seed;

            $(frame).removeAttr('data-embed');

            if (embedObject.Properties.AsLink) {
                $(frame).attr('href', '#' + id);
                $(frame).attr('data-toggle', 'modal');
                $(document.body).append(modal.format(id, embedObject.Properties.Title, me.closeText));

                $('#' + id).one('show.bs.modal', function () {
                    me.doComputeEmbed(data, isPreview, $('#' + id).find('.modal-body')[0]);
                });
            }
            else {
                me.doComputeEmbed(data, isPreview, frame);
            }
        },

        doComputeEmbed: function (data, isPreview, target) {
            $.ajax({
                url: 'cmsmanagementservice.svc/' + (isPreview ? 'preview' : 'compute') + 'EmbeddedFrame?_dc=' + new Date().getTime(),
                data: JSON.stringify(data),
                contentType: 'application/json; charset=utf-8',
                dataType: 'json',
                type: 'POST',
                success: function (result, opts) {
                    if (result && result.success) {
                        this.update(target, result.d);
                        var slider = $(target).parents('.royalSlider').data('royalSlider');
                        if (slider) {
                            slider.updateSliderSize();
                        }
                    }
                },
                context: this
            });
        },


        onLoad: function () {
            var me = this,
                isPreview = $('#portal').attr('data-portal-preview') == 'true';

            $('[data-frame-id]').each(function (index, frame) {
                me.computeFrame.apply(me, [frame, isPreview]);
            });
            $('[data-embed]').each(function (index, frame) {
                me.computeEmbed.apply(me, [frame, isPreview]);
            });

            var $responsiveIframes = $('iframe[data-responsive]');

            $responsiveIframes.each(function () {

                $(this)
                    // jQuery .data does not work on object/embed elements
                    .attr('data-ratio', ''+(parseInt(this.height) / parseInt(this.width)))
                    .attr('data-max-width', '' + this.width)                    
                    .removeAttr('height')
                    .removeAttr('width')
                    .removeAttr('data-responsive');

            });

            $(window).resize(function () {

                $responsiveIframes.each(function () {

                    var $el = $(this),
                        maxWidth = parseInt($el.attr('data-max-width')),
                        newWidth = Math.min($el.parents().width(), maxWidth);

                    if (newWidth == 0) newWidth = maxWidth;
                    $el
                        .width(newWidth)
                        .height(newWidth * $el.attr('data-ratio'));

                });

            }).resize();
        }
    }
})();

$(document).ready(function () {
    portalManager.onLoad()
});