(function($) {
    var requestTimer = null;
    var requestPool = [];
    var teaserURL = 'https://cct.check24.de/api';
    var datainterfaceURL = 'https://cct.check24.de/datainterface';
    var timeout = 5500;
    var haveIframe = false;
    var debugLog = [];

    


var JSON = window.JSON;
if (JSON === undefined) {
    JSON = {
        stringify: function (vContent) {
            if (vContent instanceof Object) {
                var sOutput = "";
                if (vContent.constructor === Array) {
                    for (var nId = 0; nId < vContent.length; sOutput += this.stringify(vContent[nId]) + ",", nId++);
                    return "[" + sOutput.substr(0, sOutput.length - 1) + "]";
                }
                if (vContent.toString !== Object.prototype.toString) { return "\"" + vContent.toString().replace(/"/g, "\\$&") + "\""; }
                for (var sProp in vContent) { sOutput += "\"" + sProp.replace(/"/g, "\\$&") + "\":" + this.stringify(vContent[sProp]) + ","; }
                return "{" + sOutput.substr(0, sOutput.length - 1) + "}";
            }
            return typeof vContent === "string" ? "\"" + vContent.replace(/"/g, "\\$&") + "\"" : String(vContent);
        }
    };
}
    
function Spinner(element) {

    var self = this;
	var cSpeed = 9;
	var cWidth = 50;
	var cHeight = 50;
	var cTotalFrames = 18;
	var cFrameWidth = 50;
	var cImageSrc = 'https://cct.check24.de/images/main/loading.png';
	var cIndex = 0;
	var cXpos = 0;
	var cPreloaderTimeout = false;
	var SECONDS_BETWEEN_FRAMES = 0;

	this.startAnimation = function() {

		element.style.backgroundImage='url('+cImageSrc+')';
		element.style.width=cWidth+'px';
		element.style.height=cHeight+'px';

		var FPS = Math.round(100/cSpeed);
		SECONDS_BETWEEN_FRAMES = 1 / FPS;

		cPreloaderTimeout=setTimeout(function() { self.continueAnimation(); }, SECONDS_BETWEEN_FRAMES/1000);
	};

	this.continueAnimation = function() {

		cXpos += cFrameWidth;
		cIndex += 1;

		if (cIndex >= cTotalFrames) {
			cXpos =0;
			cIndex=0;
		}

		element.style.backgroundPosition = (-cXpos)+'px 0';

		cPreloaderTimeout = setTimeout(function() { self.continueAnimation(); }, SECONDS_BETWEEN_FRAMES*1000);
	};

	this.stopAnimation = function() {
		clearTimeout(cPreloaderTimeout);
		cPreloaderTimeout=false;
	};
}
    
$.fn.cctSpinner = function(start) {

    for (var id = 0; id < this.length; id++) {

        var element = this[id];

        if (element.spinner === undefined && start === true) {
            element.spinner = new Spinner(element);
            element.spinner.startAnimation();
        }
        if (typeof element.spinner === 'object' && start === false) {
            element.spinner.stopAnimation();
            element.spinner = undefined;
        }
    }

    return this;
};

(function() {
    $.fn.cctClickTip = function(displayClass) {

        displayClass = displayClass === undefined ? 'clicktip-trigger' : displayClass;

        if ($('#c24cct-clicktip').length === 0) {
            $(document.body).append($('<div />', { id: 'c24cct-clicktip', style: 'display: none; position: absolute;' }));
            $(document.body).on('click', function() {
                hide();
            });
        }

        for (var id = 0; id < this.length; id++) {
            (function(that) {

                that.cctClickTipContent = $(that).html();
                $(that).html('');
                $(that).addClass(displayClass);

                $(that).on('click', function(e) {
                    e.stopPropagation();
                    if (currentOwner === that) {
                        hide();
                    } else {
                        show(that);
                    }
                });

            }(this[id]));
        }
    };

    var currentOwner = null;

    var getOverlayPosition = function($owner, $clicktip) {

        var $window = $(window);
        var position = $owner.offset();

        var toLeft = position.left + $clicktip.outerWidth() >= $window.width() ? true : false;
        var toTop = position.top + $clicktip.outerHeight() - $window.scrollTop() >= $window.height() ? true : false;

        var x = toLeft ? position.left - $clicktip.outerWidth() : position.left + $owner.outerWidth();
        var y = toTop ? position.top - $clicktip.outerHeight() + $owner.outerHeight() : position.top;

        return { x: x, y: y, toTop: toTop, toLeft: toLeft };
    };

    var show = function(owner) {

        var $clickTip = $('#c24cct-clicktip');
        var $owner = $(owner);

        currentOwner = owner;

        var prefix = $owner.prop('class').match(/(c[a-zA-Z0-9]+\-)clicktip/);
        prefix = prefix instanceof Array ? prefix[1] : 'c24cct-';

        $clickTip.prop('class', $clickTip.prop('class').replace(/\s*c[a-zA-Z0-9]+\-clicktip\-overlay/, ''));
        $clickTip.addClass(prefix + 'clicktip-overlay');
        $clickTip.html(owner.cctClickTipContent);
        $clickTip.show();

        var position = getOverlayPosition($owner, $clickTip);

        $clickTip.css({
            left: position.x,
            top: position.y
        });
    };

    var hide = function() {

        var $clickTip = $('#c24cct-clicktip');
        currentOwner = null;
        $clickTip.hide();
    };
})();

$.fn.cctFade = function(type, duration) {

    duration = duration !== undefined ? duration : 250;
    type = type === 'in' ? 'in' : 'out';

    for (var id = 0; id < this.length; id++) {
        var element = this[id];
        var $element = $(element);

        if (element.cctFadeTimer === undefined) {
            $element.css({
                transition: 'opacity ' + duration + 'ms',
                opacity: 0,
                display: 'none'
            });
        }

        if (type === 'out') {

            $element.css('opacity', 0);
            clearTimeout(element.cctFadeTimer);

            element.cctFadeTimer = setTimeout(function() {
                $element.css('display', 'none');
            }, duration);

        } else {

                        $element.css('display', 'block');
            setTimeout(function() {
                $element.css('opacity', 1);
            }, 0);

            clearTimeout(element.cctFadeTimer);
            element.cctFadeTimer = setTimeout(function() {
                $element.css('display', 'block');
            }, duration);
        }
    }
};

$.fn.cctOverlay = function(overlaySelector, watchTriggerOnly, duration) {

    duration = duration !== undefined ? duration : 250;
    watchTriggerOnly = watchTriggerOnly !== undefined ? watchTriggerOnly : false;

    var trigger = this[0];
    var $overlay = $($(overlaySelector).get(0));
    var $watch = watchTriggerOnly ? $(trigger) : $([ this[0], $(overlaySelector).get(0) ]);

    
    var lastTarget = '';

    $watch.on('mouseenter mouseleave', function(e) {

        var type = e.type;
        var target = e.target === trigger ? 'trigger' : 'overlay';

        if (type === 'mouseleave') {
            $overlay.cctFade('out', duration);
        } else {
            if (target !== 'overlay' || lastTarget !== 'overlay') {
                $overlay.cctFade('in', duration);
            }
        }

        lastTarget = target;
    });
};

$.fn.cctToolTip = function(html, className, watchTriggerOnly, duration) {

    duration = duration !== undefined ? duration : 250;

    for (var id = 0; id < this.length; id++) {

        var $element = $(this[id]);
        var $tip = $('<div />', { 'class': className });
        $tip.css({
            'display': 'none',
            'position': 'absolute'
        });
        $tip.html('<div>' + html + '</div>');
        $tip.insertAfter($element);
        $element.cctOverlay($tip, watchTriggerOnly, duration);
    }
};

$.fn.cctFill = function(options, valueIsKey, elementType, indexAttribute) {

    elementType = (elementType === undefined ? 'option' : elementType);
    indexAttribute = (indexAttribute === undefined ? 'value' : indexAttribute);
    valueIsKey = (valueIsKey === undefined ? false : valueIsKey);

    for (var id = 0; id < this.length; id++) {

        var $element = $(this[id]);
        $element.empty();

        for (var index in options) {
            if (options.hasOwnProperty(index)) {
                var $option = $('<' + elementType + ' />');
                $option.text(options[index]);
                if (indexAttribute !== null) {
                    $option.attr(indexAttribute, valueIsKey ? options[index] : index);
                }
                $element.append($option);
            }
        }
    }

    return this;
};

$.fn.cctFormData = function() {
    var result = { };
    for (var id = 0; id < this.length; id++) {
        $.each($(this).serializeArray(), function(_, kv) {
            result[kv.name] = kv.value;
        });
    }
    return result;
};

(function() {
    $.fn.cctFormValidate = function(definition) {

        var fields = definition.fields;
        var handler = definition.handler || formValidateHandler;
        var data = $.fn.cctFormData.call(this);
        var $this = $(this);
        var errors = [];

        for (var key in fields) {
            var field = fields[key];
            var isError = field.test(data[key]) !== true;
            handler($this.find('[name="' + key + '"]').get(0), isError, key, definition);
            if (isError) {
                errors.push(key);
            }
        }

        return errors;
    };

    var formValidateHandler = function(element, error, key, definition) {

        var errorClass = definition.errorClass || 'form-error';
        $(element).toggleClass(errorClass, error);
    };
})();    


function receiveMessage(event) {
    if (typeof event.data === 'string') {
        var message = event.data.split(":");
        var eventName = message[0];
        var iframes, len, i = 0;
        if (event.origin === "null" && eventName === "cct.resize") {
            iframes = document.getElementsByTagName("iframe");
            len = iframes.length;
            for (; i < len; i++) {
                if ((iframes[i].contentWindow || iframes[i].documentWindow) == event.source) {
                    iframes[i].style.height = message[1] + "px";
                    return;
                }
            }
        }
    }
}

function registerResizer() {
    if ( window.addEventListener ) {
        window.addEventListener("message", receiveMessage, false);
    } else if (window.attachEvent)  {
        window.attachEvent("onmessage", receiveMessage);
    }
}

    
        var applyHost = function(html) {

        if (typeof html !== 'string') {
            return html;
        }

        var current;
        var regex = /<!--\s*CCTHOST\[\[(.+?)\]\]\s*-->([\S\s]+?)<!--\s*\/CCTHOST\s*-->/;

        while ((current = html.match(regex))) {

            var $target = $(current[1]);

            if ($target.html().indexOf(current[2]) === -1) {
                $target.append(current[2]);
            }

            html = html.replace(regex, '');
        }

        return html;
    };

        var versionDefaults = {
        v2: {
            frameContent: true
        },
        v3: {
            frameContent: true,
            numItems: 4
        }
    };
    var defaults = {
        filterLoader: '.c24-teaser-loader',
        filterDefault: '.c24-teaser',
        loaderDelay: 150,
        autoCall: true,
        useDefaultLoader: true,
        hideUnused: false,
        hideOnError: false,
        frameContent: false,
        version: 1,
        numItems: 1,
        kind: 'teaser',
        showTeaser: function(html, unique) {
            this.hideLoader();
            var teaser = $(this.element).find(this.filterDefault);
            if (this.frameContent) {
                                html = applyHost(html);
                html = '<!doctype html>\n<html><head><meta charset="utf-8"/><script>' + "        \n\n\n(function (win, doc) {\n    var awesomeIframe = {};\n    awesomeIframe.requestAnimFrame = (function(){\n        var lastTime = 0;\n        return  win.requestAnimationFrame ||\n                \/\/ polyfill with setTimeout fallback for IE8\/9\n            function(callback) {\n                var now = +new Date(), nextTime = Math.max(lastTime + 16, now);\n                return setTimeout(function() {\n                    callback(lastTime = nextTime);\n                }, nextTime - now);\n            };\n    })();\n    awesomeIframe.windowHeight = 0;\n    \/\/ Domains to send post messages to - \"*\" for wildcard domains\n    awesomeIframe.targetDomain = \"*\";\n    awesomeIframe.resizeFrame = function (){\n        var windowHeight = document.body.offsetHeight;\n        if ( awesomeIframe.windowHeight === windowHeight ) {\n            awesomeIframe.requestAnimFrame.call(win, awesomeIframe.resizeFrame);\n            return false;\n        }\n        awesomeIframe.windowHeight = windowHeight;\n        try {\n            \/\/ Same Origin iFrame\n            \/\/ manipulate style of the iframe-element the page is embedded in\n            win.frameElement.style.height = windowHeight + \"px\";\n        }\n        catch ( e ) {\n            \/\/ Cross Origin iFrame\n            \/\/ post message to parent iframe\n            win.parent.postMessage(\"cct.resize:\" + windowHeight , awesomeIframe.targetDomain);\n        }\n        awesomeIframe.requestAnimFrame.call(win, awesomeIframe.resizeFrame);\n    };\n    awesomeIframe.requestAnimFrame.call(win, awesomeIframe.resizeFrame);\n})(window, document, undefined);\n\n    " + '</scr' + 'ipt></head><body>' + html + '</body></html>';
                html = html.replace(/<!--\s*\/?CCTFRAME\s*-->/g, '');
                teaser.html('<iframe frameborder="0" scrolling="no" class="c24-teaser-frame" id="' + (unique || '') + '"></iframe>');
                var frame = document.getElementById(unique);
                var content = frame.contentWindow ? frame.contentWindow : (frame.contentDocument.document ? frame.contentDocument.document : frame.contentDocument);
                content.document.open();
                content.document.write(html);
                content.document.close();
                haveIframe = true;
            } else {
                                html = html.replace(/<!--\s*CCTFRAME\s*-->([\S\s]+?)<!--\s*\/CCTFRAME\s*-->/g, '');
                html = html.replace(/<!--\s*CCTHOST\[\[(?:.+?)\]\]\s*-->(?:[\S\s]+?)<!--\s*\/CCTHOST\s*-->/g, '');
                teaser.html(html);
            }
            teaser.show();
        },
        showDefault: function() {
            this.hideLoader();
            $(this.element).find(this.filterDefault).show();
        },
        hideDefault: function() {
            $(this.element).find(this.filterDefault).hide();
        },
        insertDefaultContainer: function() {
            if ($(this.element).find(this.filterDefault).length === 0 && /\.[a-z0-9_\-]+/.test(this.filterDefault)) {
                $(this.element).prepend($('<div class="' + this.filterDefault.slice(1) + '"></div>'));
            }
        },
        insertDefaultLoader: function() {
            var element = $('<div style="margin: auto;"></div>');
            var loader = $('<div class="c24-teaser-loader" style="padding-top: 75px; height: 125px;"></div>');
            $(loader).append(element);
            $(this.element).prepend(loader);
            this.spinnerObj = new Spinner(element.get(0));
        },
        showLoader: function() {
            var self = this;
            this.loaderRes = setTimeout(function() {
                if (self.spinnerObj) {
                    self.spinnerObj.startAnimation();
                }
                $(self.element).find(self.filterLoader).show();
            }, this.loaderDelay);
        },
        hideLoader: function() {
            clearTimeout(this.loaderRes);
            $(this.element).find(this.filterLoader).hide();
            if (this.spinnerObj) {
                this.spinnerObj.stopAnimation();
            }
        },
        replacements: { },
        exclude_product: [ ],
        force_bl_send: [ ]
    };

        var teaserFields = [ 'replacements', 'disable_cs', 'exclude_product', 'csplan_id', 'id', 'domain_id', 'version' ];

        var optionFields = [ 'customer', 'auth', 'onSuccess', 'onError', 'force_bl_send', 'kind', 'preview' ];

        var resultError = function(pool) {
        for (var poolId in pool) {
            if (pool.hasOwnProperty(poolId)) {
                teaserError(pool, poolId);
            }
        }
    };

    var teaserError = function(pool, poolId) {
        if (pool[poolId].hideOnError) {
            pool[poolId].hideLoader();
            pool[poolId].hideDefault();
        } else {
            pool[poolId].showDefault();
        }
    };

        var resultSuccess = function(pool, result) {

        var itemsHtml = '';
        var unique = '';
        var resultId = 0;

        for (var poolId = 0; poolId < pool.length; ++poolId) {
            for (var cloneId = 0; cloneId < pool[poolId].numItems; ++cloneId) {

                var data = result.data[resultId];

                if (data !== undefined && (cloneId > 0 || (data.teaser_id !== 0 && data.html !== null))) {

                                        //itemsHtml += '<div class="c24cct-teaser-item">' + data.html + '</div>';
                    itemsHtml += data.html || '';
                    unique = cloneId === 0 ? data.unique : unique;

                                        (function() {
                        var localPoolId = poolId;
                        var localUnique = unique || '';
                        var localHtml = pool[poolId].numItems > 1 ? '<div class="c24cct-teaser-items clearfix">' + itemsHtml + '</div>' : data.html;
                        var itemsComplete = cloneId === (pool[poolId].numItems - 1) || resultId === (result.data.length - 1);
                        if (itemsComplete) {
                            itemsHtml = '';
                        }
                        loadDatainterface(data.datainterface || null, function(success) {
                            if (itemsComplete) {
                                if (success) {
                                    pool[localPoolId].showTeaser(localHtml, localUnique);
                                } else {
                                    teaserError(pool, localPoolId);
                                }
                            }
                        });
                    })();

                } else {

                                        if (pool[poolId].hideUnused) {
                        pool[poolId].hideLoader();
                        pool[poolId].hideDefault();
                    } else {
                        pool[poolId].showDefault();
                    }
                }

                ++resultId;
            }
        }

                if (haveIframe) {
            registerResizer();
        }
    };

        var loadDatainterface = function(name, callback) {
        if (name === null) {
            callback(true);
        } else {
            $.getScript(datainterfaceURL + '/' + name)
                .done(function() {
                    callback(true);
                })
                .fail(function(jqxhr, settings, exception) {
                    debugLog.push({ message: 'loadDatainterface failed', exeption: exception, settings: settings });
                    callback(false);
                });
        }
    };

        var request = function() {

        var pool = requestPool.slice(0);
        var options = { };
        var teasers = [];

        if (pool.length === 0) {
            return;
        }

        // separate local parameters from request

        for (var key = 0; key < pool.length; ++key) {
            var item = pool[key];
            var teaser = { };

            for (var id = 0, len = optionFields.length; id < len; id++) {
                var name = optionFields[id];
                if (item[name] !== undefined) {
                    options[name] = item[name];
                }
            }

            for (var id = 0, len = teaserFields.length; id < len; id++) {
                var name = teaserFields[id];
                if (item[name] !== undefined) {
                    teaser[name] = item[name];
                }
            }

            for (var clone = 0; clone < item.numItems; ++clone) {
                teasers.push(teaser);
            }
        }

        if (options.auth === undefined) {
            throw new Error('cctSelect: None of the given teasers define auth information.')
        }

        if (options.customer === undefined) {
            throw new Error('cctSelect: None of the given teasers define customer information.')
        }

        $.ajax({
            url: teaserURL,
            timeout: timeout,
            type: 'POST',
            dataType: 'jsonp',
            data: { request: JSON.stringify({ method: 'get_teaser', parameter: [ options, teasers ] }) },
            success: function(result) {
                debugLog.push({ message: 'response', result: result });
                if (result instanceof Object !== true || result.error !== null || result.data === null) {
                    resultError.call(options, pool);
                } else {
                    resultSuccess.call(options, pool, result);
                }
                if (typeof options.onSuccess === 'function') {
                    options.onSuccess(result);
                }
            },
            error: function(jqXHR, text, error) {
                debugLog.push({ message: 'request failed', text: text, error: error });
                resultError.call(options, pool);
                if (typeof options.onError === 'function') {
                    options.onError(jqXHR, text, error);
                }
            }
        });

        requestPool = [];
    };

        $.fn.cctSelect = function(options) {

        this.each(function() {

            // merge options with defaults

            options = (options instanceof Object ? $.extend({ }, options) : { });
            options.defaults = defaults;

            var prevRequest = (requestPool.length > 0 ? requestPool[requestPool.length -1] : null);
            var vxDefaults = versionDefaults['v' + (options['version'] || 1)] || { };

            for (var key in defaults) {
                if (prevRequest !== null && prevRequest[key] !== undefined) {
                    options[key] = (options[key] !== undefined ? options[key] : prevRequest[key]);
                } else {
                    options[key] = (options[key] !== undefined ? options[key] : (vxDefaults[key] !== undefined ? vxDefaults[key] : defaults[key]));
                }
            }

            options.loaderRes = null;
            options.element = this;

            // hide default teaser immediately

            options.insertDefaultContainer();
            options.hideDefault();

            // if the default spinner is to be used, initialize it

            if (options.useDefaultLoader) {
                options.insertDefaultLoader();
                options.showLoader();
            }

            // push teaser request onto request pool and reset pool "delay"

            requestPool.push(options);

            if (options.autoCall === true) {
                clearTimeout(requestTimer);
                requestTimer = setTimeout(request, 0);
            }
        });

        return this;
    };

        $.cctCall = function() {
        request();
    };

    $.cctGetLog = function() {
        return debugLog;
    };

})(jQuery);