﻿var Ad = {
    _cachedAds: {},

    init: function() {
        Ad.element = $("ad");
        Ad.placeHolderElement = $("ad-placeholder");

        $(document.body).addEvent("keydown", function(e) {
            if (e.key == "esc") {
                if (Lightbox._current) Lightbox.hide();
                else if (Ad._isOpened) Ad.close();
            }
        });
    },

    _initCloseButton: function() {
        $("ad-close").addReplacingEvent("click", function(e) {
            Ad.close();
        });
    },

    // constants for the arrow in every ad item
    // contains background positions
    ARROW_POSITIONS: {
        /*SMALL_FROM:"73px 137px",
        SMALL_TO:"73px 145px",
        BIG_FROM:"0 145px",
        BIG_TO:"0 141px"*/
        SMALL_FROM: "49px 83px",
        SMALL_TO: "49px 93px",
        BIG_FROM: "-25px 93px",
        BIG_TO: "-25px 86px"
    },

    _abortCurrentAdRequest: function() {
        if (Ad._currentAdRequest) Ad._currentAdRequest.abort();
        Ad._currentAdRequest = null;
    },
    _restoreLastOpenedAdHandle: function() {
        if (Ads.last) {
            Ads.last.removeClass("current");
            if (!Browser.Engine.trident4) {
                Ads.last.getElement("a").retrieve("fx").setOptions({ duration: 100 }).start({ backgroundPosition: [Ad.ARROW_POSITIONS.SMALL_TO, Ad.ARROW_POSITIONS.SMALL_FROM] });
            }
            Ads.last = null;
        }
        // clear current html
        Ad.placeHolderElement.empty();
    },

    _abortOpeningSequence: function() {
        if (Ads._openMiniAdChain) Ads._openMiniAdChain.clearChain();
    },

    _isOpened: false,
    open: function(adId, relative) {
        Ad.fireEvent("onOpening", [adId]);
       
        // don't get in if already same is opened
        if (Ads._currentOpenedAdId == adId) {
            Ad.close();
            return;
        }

        Ad._isOpened = true;

        Ads._lowlightOtherAds();

        Ads._currentOpenedAdId = adId;

        // aborts last ajax request if fired but not completed, and user clicked another ad
        function abortLastRequest() {
            if (!isValidChainCall()) return;
            Ad._abortCurrentAdRequest();
            nextInChain();
        }

        // restores last ad's style
        function restoreLastItem() {
            if (!isValidChainCall()) return;
            Ad._restoreLastOpenedAdHandle();
            // remember the last one opened
            Ads.last = relative;
            nextInChain();
        }

        // effect the opening arrow
        function setItemAsCurrent() {
            if (!isValidChainCall()) return;

            if (Browser.Engine.trident4) {
                relative.addClass("current");
                nextInChain();
            } else {
                // a inside the li
                relative.getElement("a")
                // create effect if not exists
					.retrieveOrStore("fx", function() { return this.effects({ wait: false }) })
					.setOptions({ duration: 150 })
                // lower the arrow
					.start({ backgroundPosition: [Ad.ARROW_POSITIONS.SMALL_FROM, Ad.ARROW_POSITIONS.SMALL_TO] }).chain(function() {
					    relative.addClass("current");
					    // raise the big arrow
					    this.start({ backgroundPosition: [Ad.ARROW_POSITIONS.BIG_FROM, Ad.ARROW_POSITIONS.BIG_TO] }).chain(function() {
					        // call the next function in the chain
					        nextInChain();
					    });
					});
            }
        }

        function setAdPosition() {
            if (!isValidChainCall()) return;
            // position is where the #ad gonna be placed
            var position = relative.getRelativePosition(),
            // absPosition is for cheking whther #ad will probably exceed the screen so it should be placed above the relative
				absPosition = relative.getPosition();

            // contains the final style to the #ad, {top,bottom,left,right}
            var finalStyle = new Hash();
            // reset all styles
            ["top", "bottom", "right", "left"].each(function(coor) { finalStyle.set(coor, "auto"); });

            // exceeding right
            if (position.x + Ad.element.getStyle("width").toInt() > Ads.maximums.right) finalStyle.extend({ right: 0 });
            else finalStyle.extend({ left: position.x });
            // exceeding bottom
            var minHeight = 400, // minimum height that won't considered as exceeding
				maxHeight = 400; // maximum height to be considred as exceeding
            var scrollTop = document.getScroll().y;
            //console.log("Ads.maximums.bottom-relative.offsetTop",Ads.maximums.bottom-relative.offsetTop);
            if (
				absPosition.y > maxHeight // there is enought place above the item
				&&
				(absPosition.y + minHeight) // estimated bottom coordinate
				- scrollTop // minus what's scrolled from top
				> // greater than
				document.getSize().y // the offset height of the document
			) finalStyle.extend({
			    bottom: Ads.maximums.bottom - relative.offsetTop
			});
            else finalStyle.extend({
                top: position.y + relative.offsetHeight - relative.getStyle("border-bottom-width").toInt() // -border-bottom-width due to the li's borde
            });

            Ad.element
				.setVisibility(false) // hide visibility so computing positioning won't show flickering
				.show()
				.setStyles(finalStyle)
				.setVisibility(true); // then show it

            // is this the first time running? means height is yet to set
            var firstRun = !Ads.isMiniAdOpen;
            Ads.isMiniAdOpen = true;
            Ad.placeHolderElement
            // clear current html
				.empty()
            // set the height as the current one but let resize by overflowing:hidden
				.setStyles({ height: Ad.placeHolderElement.getStyle("height").toInt() });

            // prepare the effect or take one if already prepared
            Ad.placeHolderElement.retrieveOrStore("fx", function() { return this.effects({ wait: false }) });

            // build what the effect should change
            var newStyle = { opacity: 0.4 };
            // only if this is the first time set height to 0 than slide to 100 in order to view the preloader nicely
            if (firstRun) {
                Ad.placeHolderElement.setStyle("height", 0);
                newStyle.height = 100;
            }
            // else, height is already set, just view the preloader
            else Ad.element.addClass("loading");

            if (!Browser.Engine.trident4) {
                Ad.placeHolderElement.retrieve("fx")
					.setOptions({ duration: 300 })
					.start(newStyle).chain(function() {
					    // if we haven't shown the preloader, show it
					    isFirstRun();
					});
            } else {
                Ad.placeHolderElement.setStyles(newStyle);
                isFirstRun();
            }

            function isFirstRun() {
                if (firstRun) Ad.element.addClass("loading");
                nextInChain();
            }
        }

        var adSource;

        // open the current ad
        // also ajax request for the ad source
        function requestAdSource() {
            if (!isValidChainCall()) return;

            // if ad in the cache take it from there
            if (Ad._cachedAds[adId]) {
                callback(Ad._cachedAds[adId]);
            }
            // if not take it from server, then store it
            else {
                // ajax request
                Ad._currentAdRequest = Mantis.EyeBlaster.Services.AdService.GetAdSource(adId, callback, function(ex) { });
            }

            function callback(source) {
                if (!isValidChainCall()) return;

                // no more preloading
                Ad.element.removeClass("loading");

                adSource = source;

                Ad._cachedAds[adId] = source;

                // after recieving data - delete the reference
                Ad._currentAdRequest = null;

                nextInChain();
            }
        }

        function setAdPositionAfterContentArrived() {
            if (!isValidChainCall()) return;
            // take the current height
            var initialHeight = Ad.placeHolderElement.getStyle("height").toInt();

            // set placeholder's parent height to initialHeight to prevent flickering
            Ad.placeHolderElement.getParent().setStyles({ height: initialHeight });

            Ad.placeHolderElement
				.setStyles({ height: "auto" })
				.empty()
            // set the html as the one we just got
				.setStyles({
				    opacity: 0,
				    // set again to initial height in order to effet it to the final one
				    height: initialHeight
				})
				.setHTML(adSource);

            (function() {
                Ad._initCommentsLink();
                AbstractAd.initRater(Ad.element, Ads._currentOpenedAdId);
                AbstractAd.initActions(Ad.element, Ads._currentOpenedAdId);
                AbstractAd.initAdProperties(Ad.element);

                // scrollHeight has the height of the content also when overflow:hidden
                var finalHeight = Ad.placeHolderElement.scrollHeight;
                // restore placeholder's parent height to auto
                Ad.placeHolderElement.getParent().setStyles({ height: "auto" });

                if (!Browser.Engine.trident4) {
                    Ad.placeHolderElement.retrieve("fx")
						.setOptions({ duration: 600 })
						.start({ "height": finalHeight, opacity: 1 }).chain(function() {

						    // after loading all content and resizing box, make sure the element is positioned by top and not by bottom
						    afterLoadingAll();
						});
                } else {
                    Ad.placeHolderElement.setStyles({ "height": finalHeight, opacity: 1 });
                    afterLoadingAll();
                }

                function afterLoadingAll() {
                    //replace the bottom with the top, the position of the ad need to be from the x,y top position because the page height growing					
                    if (Ad.element.getStyle("top") == "auto") Ad.element.setStyles({ bottom: "auto", top: Ad.element.getRelativePosition().y });
                    nextInChain();
                }

                FullAd.initFullOpen();
            }).delay(100);
        }

        function validateAdPosition() {
            //console.log(Ad.element.getRelativePosition().y);
            Ad.element.setStyles({ top: Ad.element.getRelativePosition().y });
            nextInChain();
        }

        if (Ad.placeHolderElement.retrieve("fx")) Ad.placeHolderElement.retrieve("fx").cancel();

        // if last chain still running - abort it
        Ad._abortOpeningSequence();
        // this chain is a sequence of functions. each function can call next one by nextInChain(); inside
        Ads._openMiniAdChain = new Chain();
        Ads._openMiniAdChain.chain(abortLastRequest);
        Ads._openMiniAdChain.chain(restoreLastItem);
        Ads._openMiniAdChain.chain(setItemAsCurrent);
        Ads._openMiniAdChain.chain(setAdPosition);
        Ads._openMiniAdChain.chain(requestAdSource);
        Ads._openMiniAdChain.chain(setAdPositionAfterContentArrived);
        Ads._openMiniAdChain.chain(validateAdPosition);

        // checks the current call is for the current ad
        function isValidChainCall() {
            return Ads._currentOpenedAdId == adId;
        }

        function nextInChain() {
            if (!isValidChainCall()) return;
            Ads._openMiniAdChain.callChain.delay(1, Ads._openMiniAdChain);
        }

        //debugger;
        nextInChain();
    },
    close: function() {
        if (!Ad._isOpened) return;

        Ads._highlightOtherAds();
        Ad.element.hide();
        //Ad.placeHolderElement.setStyles({height:"auto"});
        Ad._abortOpeningSequence();
        Ad._abortCurrentAdRequest();
        Ad._restoreLastOpenedAdHandle();
        Ads.isMiniAdOpen = false;
        Ads._currentOpenedAdId = null;

        Ad._isOpened = false;
    },

    _initCommentsLink: function() {
        if ($("ad-info-comments")) {
            $("ad-info-comments").addReplacingEvent("click", function(e) {
                FullAd.addEvent("onOpened", function() {
                    $("fullad-button-comments").click(); // this is the comments link in the full ad page
                    FullAd.removeEvent("onOpened", arguments.callee); // remove this function ofter open
                });
            });
        }
    }
};
$DL(Ad.init);

/* common functionality for ads */

var AbstractAd={
	initRater:function (element,adId) {
		var rater=new StarRater(element.getElement(".star-rater"),{
			onRate:function (rate,onAfterRating) {
				Mantis.EyeBlaster.Services.AdService.RateAd(adId,rate,function (newRate) {
					onAfterRating(newRate);
				});
			}
		});
	},

	// init ad action icons, add to case and tag
	initActions:function (element,adId) {
		var actionsContainer=element.getElement(".ad-actions");
		
		actionsContainer.getElement(".tag").addReplacingEvent("click",function (e) {
			AbstractAd._showTagForm(adId,this);
		});
		
		/*actionsContainer.getElement(".send").addReplacingEvent("click",function (e) {
			//AbstractAd._showSendToAFriendForm(adId,this);
			SendToAFriend.showForm(adId,this);
		});*/
		
		function caseFeedback(element) {
			var parent=element.getParent(".ad-actions-wrap");
			var initialHeight=parent.getStyle("height");
			parent.retrieveOrStore("fx",function () { return this.effect("height",{duration:200}) }).start(51);
			element.show();
			parent.retrieve("fx").start(initialHeight).chain(function () {
				(function () {
					parent.retrieve("fx").start(initialHeight);
					element.hide();
				}).delay(2000,this);
			});
		}

		function initAddToCase() {
			var addToCase=actionsContainer.getElement(".case");
			if (addToCase) addToCase.addEvent("click",function (e) {
				e.stop();
				var f=arguments.callee;
				Case.add(adId,this,function () {
					this.title="Remove from my favorites";
					this.replaceClass("case","case-remove");
					this.removeEvent("click",f);
					caseFeedback($("ad-action-case-feedback-added"));
					initRemoveFromCase();
				}.bind(this));
			});
		}
		function initRemoveFromCase() {
			var removeFromCase=actionsContainer.getElement(".case-remove");
			if (removeFromCase) removeFromCase.addEvent("click",function (e) {
				e.stop();
				var f=arguments.callee;
				Case.remove(adId,function () {
					this.title="Add to my favorites";
					this.replaceClass("case-remove","case");
					this.removeEvent("click",f);
					var fx=$("ad-action-case-feedback-removed").retrieveOrStore("fx",function () { return this.effect("opacity",{wait:false}); });
					caseFeedback($("ad-action-case-feedback-removed"));
					initAddToCase();
				}.bind(this));
			});
		}

		initAddToCase();
		initRemoveFromCase();
	},

	initAdProperties:function (element) {
		var propertiesContainer=element.getElement(".ad-properties");
		propertiesContainer.getElements("a").addReplacingEvent("click",function (e) {
			var tagId=+this.id.split("-")[1]; // id in format tag-44
			Ads.search(null,[tagId],false,false);
		});
	},
	
	initTagCloud:function (element) {
		element.getElement(".ad-tag-cloud").getElements("a").addReplacingEvent("click",function (e) {
			var tagName=this.get("text");
			Ads.search([tagName],null,false,false);
		});
	},
	
	_showTagForm:function (adId,relative) {
		Mantis.EyeBlaster.Services.AdService.GetTagFormSource(function (source) {
			var el=new Element("div").adopt(Element.fromMarkup(source,true));
			AbstractAd._initTagForm(el,adId);
			
			(function () {
				var lb=new SiteLightbox(el).show();
			}).delay(50); // delay so js/css could load
		
//			(function () {
//				new Lightbox(el,{
//					relativeTo:relative,
//					offsetPosition:{
//						x:function (container) { return -container.offsetWidth+relative.offsetWidth; },
//						y:function (container) { return -container.offsetHeight-10; }
//					}
//				}).show();
//			}).delay(50); // delay so js/css could load

		});
	},
	
	
	_initTagForm:function (element,adId) {
		var form=element.getElement("form");
		form.addReplacingEvent("submit",function (e) {
			var tagsValue=form["Tags"].value.trim();
			if (!tagsValue) return alert("Please fill in some tags");
			var tags=tagsValue.trim().split(/\s*,\s*/);
			var retrieveSource=FullAd._isOpened; // meaning we'd like to get the tag cloud source
			Mantis.EyeBlaster.Services.AdService.TagAd(adId,tags,retrieveSource,function (source) {
				AbstractAd._tagFormSent(tags.length,source);
			});
		});
		form.getElement(".cancel").addEvent("click",function () {
			Lightbox.hide();
		});
	},
	
	_tagFormSent:function (amount,source) {
		$("tag-ad-amount").set("text",amount>1 ? amount+" tags" : "1 tag");
		$("tag-ad-form").hide();
		$("tag-ad-after").show();
		if (source) $E("#fullad-tagcloud .ad-tags").setHTML(source);
		(function () {
			if (Lightbox._current) {
				Lightbox._container.effect("opacity").start(0).chain(function () {
					Lightbox.hide();
					Lightbox._container.setStyle("opacity",1);
				});
			}
		}).delay(2000);
	}
};
Events.makeObjectEventable(Ad);

// take care of closing the Ad and the FullAd when searched
Ads.addEvent("onSearching",function () {
	Ad.close();
	FullAd.close();
});

