/*
	External callbacks
*/

function rPlus_embedCbFx(data, asyncCallFlag) {
	window['rPlus_embedCbFxCb'](data, asyncCallFlag);
}

function rPlus_onBlocksDataLoadedCallback (data) {
	window['rPlus_onBlocksDataLoadedCallback'](data);
}

/* Main code */

(function () {

	var urlParamsFromApi;
	var paramsFromApi;
    var hiddenBlocks = [];
    var blocks = {};
    var serviceUrl;

	function apiCallback (data, asyncCallFlag) {
		urlParamsFromApi = data.urlParams.replace('user_id=', 'userId=').replace('orig_url=&', '');
		paramsFromApi=data;
		paramsFromApi.asyncCallFlag=asyncCallFlag;

	    manageBlockParams ();
    	window.setInterval(manageBlockParams, 200); 
	}

	window['rPlus_embedCbFxCb'] = apiCallback;

    /*
     * AJAX wrapper
    */

    function formatParams(params, skip) {
        return (skip ? "" : "?") + Object
              .keys(params)
              .map(function (key) {
                  return key + "=" + params[key]
              })
              .join("&");
    }

    var ajax = function (args) {
        var method = args.method || "GET";
        var url = args.url;
        var success = args.success;
        var error = args.error;
        var data = args.data;

        var request = new XMLHttpRequest();
        request.onload = function () {
            if (request.status >= 200 && request.status < 400) {
                success && success(request.responseText);
            } else {
                error && error(request);
            }
        };

        request.onerror = function () {
            error && error(request);
        };

        if (method === "GET" && data) {
            url += formatParams(data, false);
        }
        request.open(method, url, true);

        if (method === "POST") {
            request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
            request.send(formatParams(data, true));
        } else {
            request.send();
        }
    };

    /*
     * Check visibility functions
    */
	function isElementInViewport(rect, win, doc) {
		var windowHeight = (win.innerHeight || doc.documentElement.clientHeight);
		var windowWidth = (win.innerWidth || doc.documentElement.clientWidth);
		var centerY = rect.top + rect.height / 2;
		var centerX = rect.left + rect.width / 2;
		return centerX >= 0 && centerY >= 0 && centerX <= windowWidth && centerY <= windowHeight;
	}

	function ensureVisible (element) {
		try {
			return ensureVisibleA(element);
		}
		catch(ee) {
			return true;
		}
	}

	function ensureVisibleA (element) {
		if (typeof jQuery === "function" && element instanceof jQuery) element = element[0];
		// rather checking element in iframe we're checking iframe for visibility instead
		if (window !== top) {
			var frameset = top.document.getElementsByTagName("iframe");
			for(var j=0; j < frameset.length; ++j) {
				//xlog("frame["+j+"]");
				var f = ensureVisibleImpl(frameset[j], top, top.document);
				if(f) return true;
			}
			return false;
		}
		else
			return ensureVisibleImpl(element, window, document);
	}

	function ensureVisibleImpl(element, win, doc) {
		if (element.offsetWidth === 0 || element.offsetHeight === 0) return false;
		var height = doc.documentElement.clientHeight;
		var rects = element.getClientRects();

		var on_top = function(r, doc) {
			var x = (r.left + r.right)/2, y = (r.top + r.bottom)/2;
			var dfp = doc.elementFromPoint(x, y);
			if (dfp === element) return true;
			if (!dfp) return false;
			for(;;) {
				if (!dfp.parentElement) break;
				if (dfp.parentElement === element) return true;
				dfp = dfp.parentElement;
			}
			return false;
		};

		for (var i = 0, l = rects.length; i < l; i++) {
			var r = rects[i];
			var in_viewport = r.top > 0 ? r.top <= height : (r.bottom > 0 && r.bottom <= height);
			var on_top_flag = in_viewport && on_top(r, doc);
			var on_vp_flag = on_top_flag && isElementInViewport(r, win, doc);
			//xlog("Element["+element+"]: " + r.left + " " + r.top + " " + r.right + " " + r.bottom + " vs " + height + 
			//	" => in_vp==" + in_viewport + ", on_top=" + on_top_flag + ", in_vp2=" + on_vp_flag);
			if (in_viewport && on_top_flag && on_vp_flag) 
				return true;
		}
		return false;
	}

	/*
	 * True View: defer block.show() until it really visible
	*/

	function onVisibilityChange(el, callback) {
		return function () {
			for (var j = 0; j < hiddenBlocks.length; ++j) {
				if (hiddenBlocks[j].getDiv() == el) {
					var visible = ensureVisible(el);
					if (visible) {
						if (typeof callback == 'function') callback(hiddenBlocks[j]);
						hiddenBlocks.splice(j, 1);
	                	if(hiddenBlocks.length == 0) break;
	                	--j; 
		            }
				}
			}
		}
	}

	function addHandlerForScroll(handler, framed) {
		if (framed) addHandlerForScrollImpl(handler, top);
		addHandlerForScrollImpl(handler, window);
	}

	function addHandlerForScrollImpl(handler, win) {
		if (win.addEventListener) {
			win.addEventListener('load', handler, false); 
			win.addEventListener('scroll', handler, false); 
			win.addEventListener('resize', handler, false); 
		} else if (window.attachEvent)  {
			win.attachEvent('onload', handler);
			win.attachEvent('onscroll', handler);
			win.attachEvent('onresize', handler);
		}
		win.setInterval(handler, 200); 
	}

    /*
     * Magic with scripts: HTML5 banners should evaluate scripts if applicable
    */
	function insertAndExecute(domelement, text, url) {
		var scripts = [];

		if (text.indexOf('${CLICK_URL}') >= 0) {
			text = text.replace('${CLICK_URL}', url + "&orig_url=");
		}
		domelement.innerHTML = text;

		var ret = domelement.childNodes;
		for ( var i = 0; ret[i]; i++ ) {
			if ( scripts && netp_nodeName( ret[i], "script" ) && (!ret[i].type || ret[i].type.toLowerCase() === "text/javascript") ) {
				scripts.push( ret[i].parentNode ? ret[i].parentNode.removeChild( ret[i] ) : ret[i] );
			}
		}

		for(script in scripts) {
			evalScript(scripts[script]);
		}

		// Now we need to wait until all scripts have completed and then tweak
		// links to handle clicks ourself.
		tweakLinks(domelement, url);
	}

	/* 
	 Register monitor to check continuously the block against newly arrived links
	 Unfortunately we cannot tweak once - some blocks might appear only 
	 at the scrolling time for example
	*/
	function tweakLinks(domelement, url) {
		window.setInterval(function() 
			{
				if (!domelement) return;
				var a = domelement.getElementsByTagName('a');
				for(var j = 0; a != null && j < a.length; ++j) {
					if(a[j].href.indexOf('TeaserClicked') > 0) continue;
					a[j].href = url + "&orig_url=" + encodeURIComponent(a[j].href);
				}
			}, 200 /* ms */); 
	}

	function netp_nodeName( elem, name ) {
		return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase();
	}

	function evalScript( elem ) {
		data = ( elem.text || elem.textContent || elem.innerHTML || "" );

		var head = document.getElementsByTagName("head")[0] || document.documentElement,
			script = document.createElement("script");
		script.type = "text/javascript";
		script.appendChild( document.createTextNode( data ) );
		head.insertBefore( script, head.firstChild );
		head.removeChild( script );

		if ( elem.parentNode ) {
			elem.parentNode.removeChild( elem );
		}
	}

	function readCookie(name) {
		var nameEQ = name + "=";
		var ca = document.cookie.split(';');
		for(var i=0;i < ca.length;i++) {
			var c = ca[i];
			while (c.charAt(0)==' ') c = c.substring(1,c.length);
			if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
		}
		return null;
	}

    /**
     * @constructor
     */
    function Teaser(model, block) {
        this.blockId = block.blockId;
        this.transitUrl = block.transitUrl;
        this.skipTransitPage = block.skipTransitPage || model["Raw"];
        this.U = model["U"] || paramsFromApi.u;

        if (model["Utm"]) {
        	this.transitUrl += this.transitUrl.indexOf('?') > 0 ? '&' : '?';
        	this.transitUrl += model["Utm"];
        }

        this.model = model;

        this.containerElement = this.createPlaceHolder(block.containerElement, "teaser-container", "div");
        if (model["Raw"]) {
        	/* HTML5 */
        	insertAndExecute(this.containerElement, model["Raw"], this.getUrl(false, this.U));
        }
        else {
	        if (model["Type"] != "Text") {
		        this.divImgElement = this.createPlaceHolder(this.containerElement, "teaser-image-container", "div");
		        this.imgAnchorElement = this.createImageAnchor(this.divImgElement);
		    }
		    if (model["Type"] != "Picture") {
		        this.divTitleElement = this.createPlaceHolder(this.containerElement, "teaser-title-container", "div");
		        this.contentAnchorElement = this.createContentAnchor(this.divTitleElement);
	        }
		    if (model["Type"] == "Recomender") {
		    	var div = this.createPlaceHolder(this.containerElement, null, "div");
		    	var element = this.createPlaceHolder(div, "main-anchor", "a");
        		element.href = this.getUrl(true, this.U);
        		element.target = "_blank";

		        var h2 = this.createPlaceHolder(element, "teaser-text", "p");
        		h2.textContent = this.model["Annotation"];
        		this.divTextElement = div;
		    }
	        this.separatorElement = this.createPlaceHolder(this.containerElement, "separator", "hr");
        }
    }

    Teaser.prototype.createImageAnchor = function (parent) {
        var element = null;
        if (this.model["ImageUrl"]) {
            element = this.createPlaceHolder(parent, "teaser-image-anchor", "a");
            element.href = this.getUrl(true, this.U);
            element.target = "_blank";
            
            var img = this.createPlaceHolder(element, "teaser-image", "img");
            img.src = this.model["ImageUrl"]; // .replace(/^(https?):/, "");
        }
        return element;
    };

    Teaser.prototype.createContentAnchor = function (parent) {
        var div = this.createPlaceHolder(parent, null, "div");

        var element = this.createPlaceHolder(div, "main-anchor", "a");
        element.href = this.getUrl(true, this.U);
        element.target = "_blank";

        var h2 = this.createPlaceHolder(element, "teaser-title", "h2");
        h2.textContent = this.model["Title"];
       	h2.style = "cursor: pointer;";
        return element;
    }

    Teaser.prototype.createPlaceHolder = function(parent, style, name) {
        var divElement = document.createElement(name ? name : "div");
        if(style) divElement.className = style;           
        parent.appendChild(divElement);
        return divElement;
    }

    Teaser.prototype.getUrl = function(addOrigUrlPart, u) {
        var self = this;
        var clickData = "?block_id=" + self.blockId + "&teaser_id=" + self.model["Id"] + "&user_id=" + paramsFromApi.uid;
        clickData += "&u=" + u;
        if(!addOrigUrlPart || (this.skipTransitPage && !this.model["IsAd"])) {
 	        clickData += "&count_jump=true";
 	        if (this.model["Url"] && addOrigUrlPart) 
	    	    clickData += "&orig_url=" + encodeURIComponent(this.model["Url"]);
        }
        else {
            var isUtm = this.transitUrl.includes('?');
 	        clickData += "&count_jump=false";
 	        clickData += "&orig_url=" + encodeURIComponent(this.transitUrl + (isUtm ? "&" : "") + 
 	        	formatParams({ "id": this.model["Id"], "block_id": this.blockId /*, "user_id": paramsFromApi.uid*/ }, isUtm));
        }
        clickData = clickData.replace('orig_url=&', '');
        return serviceUrl + "/Service/TeaserClicked" + clickData;
    }

    /**
     * @constructor
     */
    function Block(blockId, elementId) {
        this.blockId = blockId;
        this.elementId = elementId;

        this.containerElement = document.getElementById(this.elementId);
    }

    Block.prototype.getDiv = function () {
    	return this.containerElement;
    }

    Block.prototype.setData = function (data) {
        this.transitUrl = data["TransitUrl"];
        this.skipTransitPage = data["SkipTransitPage"];
        this.skipTV = data["TV"] == false;
        this.iframed = !!window.frameElement;

        var teasersModels = data["Teasers"];
        this.teasers = [];
        this.teaserIds = [];
        this.flightIds = [];
        for (var i = 0; i < teasersModels.length; i++) {
            var model = teasersModels[i];
            this.teasers.push(new Teaser(model, this));
            this.teaserIds.push(model["Id"]);
            this.flightIds.push(model["FlightId"]);
        }
    };

    Block.prototype.show = function () {
        var self = this;

        ajax({
            url: serviceUrl + "/Block/BlockShowed",
            method: "POST",
            data: {
                "blockId": self.blockId,
                "teaserIds": self.teaserIds.join(),
                "flightIds": self.flightIds.join(),
                "userId": paramsFromApi.uid
            }
        });
    };

    function onBlocksDataLoaded(data) {
        data = JSON.parse(data);
        onBlocksDataLoadedCallback_Impl(data);
    }

    window['rPlus_onBlocksDataLoadedCallback'] = onBlocksDataLoadedCallback_Impl;

    function onBlocksDataLoadedCallback_Impl(data) {
        for (var i = 0; i < data.length; i++) {
            var blockData = data[i];

            var blockId = blockData["BlockId"];
            var block = blocks[blockId]; // <===
            block.blockId = blockId;

            if(block.containerElement) {
                var style = document.createElement("style");
                style.innerHTML = blockData["Stylesheet"].replace(/<embed_div_id>/g, block.elementId);
                document.getElementsByTagName("head")[0].appendChild(style);

                block.setData(blockData);
                if (block.skipTV || ensureVisible(block.containerElement))
	                block.show();
	            else { 
	            	hiddenBlocks.push(block);
					var handler = onVisibilityChange(block.containerElement, function(block) {
						block.show();
					});
					try {
						addHandlerForScroll(handler, block.iframed);
					}
					catch(ee) {
						block.show();
						hiddenBlocks.splice(hiddenBlocks.length - 1, 1);
					}
	            }
            }
        }
    }

    function manageBlockParams () {
        var exchangeArgsRef = window[window['RamblerExchangeObject']].q;
        window[window['RamblerExchangeObject']].q = [];

        if (exchangeArgsRef == null || exchangeArgsRef.length == 0) return; // nothing to do, come later

        var actual_blocks = {};

        for(var jjk = 0; jjk < exchangeArgsRef.length; ++jjk) {
            var exchangeArgs = exchangeArgsRef[jjk];
            serviceUrl = exchangeArgs[0];
            var embedBlocks = exchangeArgs[1];
            for (var i = 0; i < embedBlocks.length; i++) {
                var embedBlock = embedBlocks[i];
                var blockId = embedBlock["blockId"];
                blocks[blockId] = new Block(blockId, embedBlock["elementId"]);
                actual_blocks[blockId] = blocks[blockId];
            }
        }

        /* use JSON rather AJAX: not supported right now */

    	var scriptVsAjax = document.createElement('script');
    	scriptVsAjax.src = serviceUrl + "/Block/Data?" + 
    		"ids=" + Object.keys(actual_blocks).join(",") + "&" + urlParamsFromApi +
    		"&callback=rPlus_onBlocksDataLoadedCallback";
    	document.getElementsByTagName("head")[0].appendChild(scriptVsAjax); 

    	/*
        ajax({
            url: serviceUrl + "/Block/Data",
            data: {
                "ids": Object.keys(actual_blocks).join(","), // blocks() have all; actual_blocks are just new
                "userId": paramsFromApi.uid,
                "screen": window.screen.width + "x" + window.screen.height,
                "rp": paramsFromApi.rp
            },
            success: onBlocksDataLoaded
        }); */
    }

	var curScript = document.currentScript;
	if (!curScript) {
		var scripts = document.getElementsByTagName('script');
		for(var jk = scripts.length - 1; jk >= 0 ; --jk) {
			if (scripts[jk].src.indexOf('cripts/embed.min.js') > 0) {
				curScript = scripts[jk];
				break;
			}
			if (scripts[jk].src.indexOf('cripts/embed.js') > 0) {
				curScript = scripts[jk];
				break;
			}
		}
	}
	var href = curScript.src;

   	var scriptVsAjax = document.createElement('script');
   	scriptVsAjax.src = href.replace('/embed.', '/api.') + "?callback=rPlus_embedCbFx";
   	document.getElementsByTagName("head")[0].appendChild(scriptVsAjax); 
})();
