var Piwik_Overlay_Client = (function () {

    var DOMAIN_PARSE_REGEX = /^http(s)?:\/\/(www\.)?([^\/]*)/i;

    /** jQuery */
    var $;

    /** Url of the Piwik root */
    var piwikRoot;

    /** protocol and domain of Piwik root */
    var piwikOrigin;

    /** Piwik idsite */
    var idSite;

    /** The current period and date */
    var period, date, segment;

    /** Reference to the status bar DOM element */
    var statusBar;

    /** Counter for request IDs for postMessage based API requests. */
    var lastRequestId = 0;

    /** Map of callbacks for postMessage based API requests. */
    var requestCallbacks = {};

    /** Load the client CSS */
    function loadCss() {
        var css = c('link').attr({
            rel: 'stylesheet',
            type: 'text/css',
            href: piwikRoot + '/plugins/Overlay/client/client.css'
        });
        $('head').append(css);
    }

    /**
     * This method loads jQuery, if it is not there yet.
     * The callback is triggered after jQuery is loaded.
     */
    function loadJQuery(callback) {
        if (typeof jQuery != 'undefined') {
            $ = jQuery;
            callback();
        }
        else {
            Piwik_Overlay_Client.loadScript('libs/bower_components/jquery/dist/jquery.min.js', function () {
                $ = jQuery;
                jQuery.noConflict();
                callback();
            });
        }
    }

    /**
     * Notify Piwik of the current iframe location.
     * This way, we can display additional metrics on the side of the iframe.
     */
    function notifyPiwikOfLocation() {
        // check whether the session has been opened in a new tab (instead of an iframe)
        if (window != window.top) {
            var iframe = c('iframe', false, {
                src: piwikRoot + '/index.php?module=Overlay&action=notifyParentIframe#' + window.location.href
            }).css({width: 0, height: 0, border: 0});

            $('body').append(iframe);
        }
    }

    /** Create a jqueryfied DOM element */
    function c(tagName, className, attributes) {
        var el = $(document.createElement(tagName));

        if (className) {
            if (className.substring(0, 1) == '#') {
                var id = className.substring(1, className.length);
                id = 'PIS_' + id;
                el.attr('id', id);
            }
            else {
                className = 'PIS_' + className;
                el.addClass(className);
            }
        }

        if (attributes) {
            el.attr(attributes);
        }

        return el;
    }

    function nextRequestId() {
        var nextId = lastRequestId + 1;
        lastRequestId = nextId;
        return nextId;
    }

    function handlePostMessages() {
        window.addEventListener("message", function (event) {
            if (event.origin !== piwikOrigin) {
                return;
            }

            var strData = event.data.split(':', 3);
            if (strData[0] !== 'overlay.response') {
                return;
            }

            var requestId = strData[1];
            if (!requestCallbacks[requestId]) {
                return;
            }

            var callback = requestCallbacks[requestId];
            delete requestCallbacks[requestId];

            var data = JSON.parse(decodeURIComponent(strData[2]));
            if (typeof data.result !== 'undefined'
                && data.result === 'error'
            ) {
                alert('Error: ' + data.message);
            } else {
                callback(data);
            }
        }, false);
    }

    return {

        /** Initialize in-site analytics */
        initialize: function (pPiwikRoot, pIdSite, pPeriod, pDate, pSegment) {
            piwikRoot = pPiwikRoot;
            piwikOrigin = piwikRoot.match(DOMAIN_PARSE_REGEX)[0];
            idSite = pIdSite;
            period = pPeriod;
            date = pDate;
            segment = pSegment;

            var load = this.loadScript;
            var loading = this.loadingNotification;

            loadJQuery(function () {
                handlePostMessages();
                notifyPiwikOfLocation();
                loadCss();

                // translations
                load('plugins/Overlay/client/translations.js', function () {
                    Piwik_Overlay_Translations.initialize(function () {
                        // following pages
                        var finishPages = loading('Loading following pages');
                        load('plugins/Overlay/client/followingpages.js', function () {
                            Piwik_Overlay_FollowingPages.initialize(finishPages);
                        });

                    });
                });
            });
        },

        /** Create a jqueryfied DOM element */
        createElement: function (tagName, className, attributes) {
            return c(tagName, className, attributes);
        },

        /** Load a script and wait for it to be loaded */
        loadScript: function (relativePath, callback) {
            var loaded = false;
            var onLoad = function () {
                if (!loaded) {
                    loaded = true;
                    callback();
                }
            };

            var head = document.getElementsByTagName('head')[0];
            var script = document.createElement('script');
            script.type = 'text/javascript';

            script.onreadystatechange = function () {
                if (this.readyState == 'loaded' || this.readyState == 'complete') {
                    onLoad();
                }
            };
            script.onload = onLoad;

            script.src = piwikRoot + '/' + relativePath + '?v=1';
            head.appendChild(script);
        },

        /** Piwik Overlay API Request */
        api: function (method, callback, additionalParams) {
            var url = piwikRoot + '/index.php?module=API&method=Overlay.' + method
                + '&idSite=' + idSite + '&period=' + period + '&date=' + date + '&format=JSON&filter_limit=-1';

            if (segment) {
                url += '&segment=' + segment;
            }

            if (additionalParams) {
                url += '&' + additionalParams;
            }

            var requestId = nextRequestId();
            requestCallbacks[requestId] = callback;

            var matomoFrame = window.parent;
            matomoFrame.postMessage('overlay.call:' + requestId + ':' + encodeURIComponent(url), piwikOrigin);
        },

        /**
         * Initialize a notification
         * To hide the notification use the returned callback
         */
        notification: function (message, addClass) {
            if (!statusBar) {
                statusBar = c('div', '#StatusBar').css('opacity', .8);
                $('body').prepend(statusBar);
            }

            var item = c('div', 'Item').html(message);

            if (addClass) {
                item.addClass('PIS_' + addClass);
            }

            statusBar.show().append(item);

            return function () {
                item.remove();
                if (!statusBar.children().length) {
                    statusBar.hide();
                }
            };
        },

        /** Hide all notifications with a certain class */
        hideNotifications: function (className) {
            statusBar.find('.PIS_' + className).remove();
            if (!statusBar.children().length) {
                statusBar.hide();
            }
        },

        /**
         * Initialize a loading notification
         * To hide the notification use the returned callback
         */
        loadingNotification: function (message) {
            return Piwik_Overlay_Client.notification(message, 'Loading');
        }

    };

})();
