
var cards = {

	init : function() {
		//cards._initAnchors();
		cards._initPositionLeftStatic();
		cards._initDynamicCards();
		cards._initCardOverlays();
	},


	/* public methods - dynamic cards */

	openCard : function(node) {
		cards._openCloseCard(node, true);
		return false;
	},
	closeCard : function(node) {
		cards._openCloseCard(node, false);
		return false;
	},


	/* public methods - card overlays */

	enterCard : function(event) {
		cards._enterLeaveCard(this, true);
	},

	leaveCard : function(event) {
		cards._enterLeaveCard(this, false);
	},


	/* protected methods - position anchors absolute */

	_initAnchors : function() {
		if (Prototype.Browser.WebKit) {
			var anchors = document.getElementsByClassName('anchor');
			for (var i = 0; i < anchors.length; i++) {
				var anchor = anchors[i];
				Element.absolutize(anchor);
			}
		}
	},


	/* protected methods - position left parts */

	_initPositionLeftStatic : function() {
		if (Prototype.Browser.IE && (!document.getElementById || navigator.appVersion.search('MSIE 6.') != -1)) {
			// skip IE6 and older because of lacking position: static support
			return;
		}

		Event.observe(window, 'resize', cards._resizePositionLeft);

		// replace auto-horizontal margin-left by fixed values
		var main = $('main');
		main.style.marginLeft = main.viewportOffset().left + 'px';
		var deltaTop = main.offsetTop - main.viewportOffset().top;

		// fixed positions for left containers
		var nodes = [];
		nodes.push($('thesis'));
		nodes.push($('nav'));
		for (var i = 0; i < nodes.length; i++) {
			var node = nodes[i];
			var offset = node.viewportOffset();
			node.style.position = 'fixed';
			node.style.top = offset.top + deltaTop + 'px';
			node.style.left = offset.left + 'px';
		}
	},

	_resizePositionLeft : function() {
		// restore auto-horizontal margin-left to dynamic position and refix again
		var main = $('main');
		var before = parseInt(main.style.marginLeft);
		main.writeAttribute('marginLeftBefore', before);
		main.style.marginLeft = 'auto';
		// delay refixing again for IE to catch up
		cards._resizePositionLeftContinue.defer(before);
	},

	_resizePositionLeftContinue : function(before) {
		// replace auto-horizontal margin-left by fixed values
		var main = $('main');
		var after = main.viewportOffset().left;
		main.style.marginLeft = after + 'px';
		var delta = after - before;
		// move positions for left containers
		var nodes = [];
		nodes.push($('thesis'));
		nodes.push($('nav'));
		for (var i = 0; i < nodes.length; i++) {
			var node = nodes[i];
			node.style.left = parseInt(node.style.left) + delta + 'px';
		}
	},


	/* protected methods - dynamic cards */

	_initDynamicCards : function() {
		var dynamicCards = document.getElementsByClassName('dynamiccard');
		for (var i = 0; i < dynamicCards.length; i++) {
			var dynamicCard = dynamicCards[i];
			var cardContent = dynamicCard.getElementsByClassName('cardcontent');
			if (cardContent.length != 1) continue;
			cardContent = cardContent[0];
			var cardText = dynamicCard.getElementsByClassName('cardtext');
			if (cardText.length != 1) continue;
			cardText = cardText[0];
			var contentFadeout = dynamicCard.getElementsByClassName('contentfadeout');
			if (contentFadeout.length != 1) continue;
			contentFadeout = contentFadeout[0];

			var openedHeight = cards._getHeightWithoutBorder(cardContent);
			dynamicCard.addClassName('closedcard');
			var closedHeight = cards._getHeightWithoutBorder(cardContent);
			if (openedHeight > closedHeight && openedHeight < closedHeight + 10) {
				// convert dynamic card to staticcard if only a little bit larger than allowed (which effectivly disables the fade-out)
				dynamicCard.removeClassName('closedcard');
				dynamicCard.removeClassName('dynamiccard');
				dynamicCard.addClassName('staticcard');
			} else if (openedHeight <= closedHeight) {
				// remove dynamic attributes for cards with fewer content than height of the card
				dynamicCard.removeClassName('closedcard');
			} else {
				cardContent.closedHeight = closedHeight;
				cardContent.openedHeight = openedHeight;
				var closedTop = parseInt(contentFadeout.getStyle('top'));
				contentFadeout.closedTop = closedTop;
				contentFadeout.openedTop = closedTop + openedHeight - closedHeight;
			}
		}
	},

	_openCloseCard : function(node, opening) {
		var buttonDiv = $(node).up(opening ? '.opencard' : '.closecard');
		var dynamicCard = buttonDiv.up('.cardtype');
		var cardContent = dynamicCard.getElementsByClassName('cardcontent');
		cardContent = cardContent[0];
		var cardText = dynamicCard.getElementsByClassName('cardtext');
		cardText = cardText[0];
		var contentFadeout = dynamicCard.getElementsByClassName('contentfadeout');
		contentFadeout = contentFadeout[0];

		var from = (opening ? cardContent.closedHeight : cardContent.openedHeight);
		var to = (opening ? cardContent.openedHeight : cardContent.closedHeight);
		var fromFadeout = (opening ? contentFadeout.closedTop : contentFadeout.openedTop);
		var toFadeout = (opening ? contentFadeout.openedTop : contentFadeout.closedTop);

		cardContent.style.height = from + 'px';
		contentFadeout.style.top = fromFadeout + 'px';
		dynamicCard.removeClassName(opening ? 'closedcard' : 'openedcard');

		cardContent.fadeoutNode = contentFadeout;
		cardContent.fadeoutOffset = fromFadeout - from;
		cardContent.tweenEffect = new Effect.Tween(cardContent,
			from,
			to,
			{
				duration: cards._getDuration(from, to),
				afterFinish: (opening ? cards._openingCardFinished : cards._closingCardFinished)
			},
			function(pos) {
				this.style.height = pos + 'px';
				this.fadeoutNode.style.top = (pos + cardContent.fadeoutOffset) + 'px';
			}
		);
		cardContent.tweenEffect.element = cardContent;
	},

	_openingCardFinished : function(effect) {
		var cardContent = effect.element;
		cardContent.tweenEffect = null;
		var dynamicCard = cardContent.up('.cardtype');
		dynamicCard.addClassName('openedcard');
	},
	_closingCardFinished : function(effect) {
		var cardContent = effect.element;
		cardContent.tweenEffect = null;
		var dynamicCard = cardContent.up('.cardtype');
		dynamicCard.addClassName('closedcard');
	},

	_getDuration : function(from, to) {
		var maxSinoidal = 1000;  // pixel
		var maxSinoidalDuration = 2.5;  // seconds
		var maxSpeed = 500;  // pixel/seconds
		var minDuration = 0.8;  // seconds

		var delta = (from > to ? from - to : to - from);
		var duration = minDuration;
		if (delta > maxSinoidal) {
			duration += delta / maxSpeed;
		} else {
			var fraction = delta / maxSinoidal;
			var sinoidal = (-Math.cos(fraction * Math.PI) / 2) + 0.5;
			duration += maxSinoidalDuration * sinoidal;
		}
		return duration;
	},

	_getHeightWithoutBorder : function(element) {
   var height = element.getHeight();
   height -= parseInt(element.getStyle('border-top-width'));
   height -= parseInt(element.getStyle('border-bottom-width'));
   return height;
	},


	/* protected methods - card overlays */

	_initCardOverlays : function() {
		var cardOverlays = document.getElementsByClassName('overlay');
		for (var i = 0; i < cardOverlays.length; i++) {
			var cardOverlay = cardOverlays[i];

			if (cardOverlay.hasClassName('static')) continue;
			
			// do not move overlays to initial start position during init - this might fail in IE
			//var overlayHeight = cardOverlay.getHeight();
			//cardOverlay.style.bottom = - overlayHeight + 'px';

			var cardContent = cardOverlay.up('.cardcontent');
			xb.addEvent(cardContent, 'mouseenter', cards.enterCard, false);
			xb.addEvent(cardContent, 'mouseleave', cards.leaveCard, false);
		}
	},

	_enterLeaveCard : function(cardContent, opening) {
		var cardOverlay = cardContent.down('.overlay');
		if (!cardOverlay.effectQueue) {
			var cardContent = cardOverlay.up('.cardcontent');
			var uniqueQueueName = (cardContent && cardContent.id ? cardContent.id : Math.round(1000000000 * Math.random()));
			cardOverlay.effectQueue = Effect.Queues.get('cardoverlay_'+uniqueQueueName);
			cardOverlay.overlayHeight = cardOverlay.getHeight();
			var overlayHeader = cardOverlay.getElementsByClassName('overlayheader');
			cardOverlay.overlayHeaderHeight = (overlayHeader.length == 1 ? overlayHeader[0].getHeight() : 0);
			var overlayText = cardOverlay.getElementsByClassName('overlaytext');
			cardOverlay.overlayTextHeight = (overlayText.length == 1 ? overlayText[0].getHeight() : 0);
		}
		var queue = cardOverlay.effectQueue;

		var canceledPrevious = (queue.effects.length > 0);
		queue.each(function(e) { e.cancel() });

		var from = parseInt(cardOverlay.getStyle('bottom'));
		if (from == 1000) {
			// move overlay to initial start position on first action
			var overlayHeight = cardOverlay.getHeight();
			cardOverlay.style.bottom = - overlayHeight + 'px';
			from = -overlayHeight;
		}
		var to = (opening ? 0 : -cardOverlay.overlayHeight);
		if (to == from) return;

		var delay = (canceledPrevious ? 0.0 : (opening ? 0.3 : 0.1));
		if (opening) {
			var via = cardOverlay.overlayHeaderHeight - cardOverlay.overlayHeight;
			if (cardOverlay.overlayHeaderHeight && from < via) {
				new Effect.Tween(cardOverlay,
					from,
					via,
					{
						delay: delay,
						duration: cards._getOverlayDuration(from, to, true),
						queue: {position: 'end', scope: queue}
					},
					function(pos) { this.style.bottom = pos + 'px'; }
				);
				from = via;
			}
			if (cardOverlay.overlayTextHeight && from < to) {
				delay = (queue.effects.length > 0 ? 0.4 : 0.0);
				new Effect.Tween(cardOverlay,
					from,
					to,
					{
						delay: delay,
						duration: cards._getOverlayDuration(from, to, false),
						queue: {position: 'end', scope: queue}
					},
					function(pos) { this.style.bottom = pos + 'px'; }
				);
			}

		} else {
			new Effect.Tween(cardOverlay,
				from,
				to,
				{
					delay: delay,
					duration: cards._getOverlayDuration(from, to, false),
					queue: {position: 'end', scope: queue}
				},
				function(pos) { this.style.bottom = pos + 'px'; }
			);

		}
	},

	_getOverlayDuration : function(from, to, header) {
		var maxSinoidal = 1000;  // pixel
		var maxSinoidalDuration = 2.5;  // seconds
		var maxSpeed = 500;  // pixel/seconds
		var minDuration = (header ? 0.3 : 0.8);  // seconds

		var delta = (from > to ? from - to : to - from);
		var duration = minDuration;
		if (delta > maxSinoidal) {
			duration += delta / maxSpeed;
		} else {
			var fraction = delta / maxSinoidal;
			var sinoidal = (-Math.cos(fraction * Math.PI) / 2) + 0.5;
			duration += maxSinoidalDuration * sinoidal;
		}
		return duration;
	}

}

Event.observe(window, 'load', cards.init);
