HttpCom.extensions.initPseudo3dGallery = function (scope) {
	var $form = $('#customizer', scope),
		$options = $('#customizer-options label', $form),
		nOptions = $options.length,
		// set dimensions of interface and items
		nSize = $options.eq(0).find('img').height(),
		nDeltaSize = Math.round(nSize/4),
		nWidth = $form.width()/2,
		nHeight = nSize/2,
		// math stuff and additional vars 
		nCurrentPhi = 0,
		n2pi = Math.PI*2,
		$animContainer,
		$controlsContainer,
        nAux;
	
	// si no existe $form casi que paramos
	if ($form.length === 0) {
		return;
	}
	else {
		$form.children().hide();
	}
	if ($options.find(':checked').length === 0) {
		$options.eq(0).find(':radio').attr('checked', true);
	}
	
	// define helper functions (internal)
	function angleToCSS(angle) {
		// use [].join('') instead of + because it is far faster
		var nFactor = (1-Math.cos(angle))/2,
			size = nSize - nDeltaSize*nFactor,
			sDim = [size, 'px'].join(''),
			sMargin = [-size/2, 'px'].join(''),
			nCos = Math.cos(angle),
			nSin = Math.sin(angle),
			oReturn;
		if (nCos < 0.01 && nCos > -0.01) nCos = 0;
		if (nSin < 0.01 && nSin > -0.01) nSin = 0;
		oReturn = {
			width:  sDim,
			height: sDim,
			marginTop:  sMargin,
			marginLeft: sMargin,
			top:    [nCos*nHeight/2, 'px'].join(''),
			left:   [nSin*nWidth/2, 'px'].join(''),
			zIndex: parseInt((nCos + 2) * nOptions, 10)
		};
		if ($.support.opacity) {
			oReturn.opacity = 1-0.5*nFactor;
		}
		return oReturn;
	}
	function setAnimationAngle(angle) {
		nCurrentPhi = angle;
		$animContainer.children().each(function (nIndex) {
			$(this).css(angleToCSS(nCurrentPhi + nIndex*n2pi/(nOptions)));
		});
	}
	
	// find out starting phi
	$options.each(function (nIndex) {
		if ($(this).find('input:checked').length) {
			nCurrentPhi = -n2pi*nIndex/nOptions;
			return false;
		}
	});
		
	// insert animation container and set its dimensions
	$animContainer = $('<div id="pseudo3d-gallery" />')
	.height(nHeight)
	.prependTo($form);
	// insert animation controls container
	$controlsContainer = $('<span id="pseudo3d-gallery-controls"><span id="pseudo3d-gallery-controls-inner" /></span>').appendTo('#customizer-controls-container', $form).children();
	
	// iterate the options to build the HTML for the interface and controls
	$options.each(function (nIndex) {
		var $option = $options.eq(nIndex);
		// create animation elements
		$option.find('img').clone().addClass("pseudo3d-gallery-item")	// create the element
		.appendTo($animContainer);										// and append it to the container
		
		// create controls
		$('<span class="pseudo3d-gallery-control-item" />')			// create the control item
		.addClass($option.find(':checked').length ? 'current' : '')	// check if it's the current one
		.text($option.text()).appendTo($controlsContainer);			// set text and insert to the container
	});
	setAnimationAngle(nCurrentPhi); // set the angle
	
	// define external interface, access it through document.getElementById('pseudo3d-gallery')
	$animContainer.get(0).pseudo3dGallery = {
		/**
		 * return An integer with the current front item index
		 * type {Number}
		 */
		getActiveIndex: function () {
			var nActiveIndex = 0,
				nAuxTop = 0;
			$animContainer.children().each(function (index) {
				var nThisTop = parseInt(this.style.top, 10);
				nAuxTop = Math.max(nThisTop, nAuxTop);
				if (nAuxTop === nThisTop) {
					nActiveIndex = index;
				}
			});
			return nActiveIndex;
		},
		/**
		 * Moves the wheel nDelta slots, negative is for counterclockwise
		 * @param {Number} nDelta must be an integer
		 * @param {fCallback} function to execute at the end of the animation
		 */
		move: function(nDelta, fCallback) {
			var nTarget = nCurrentPhi - nDelta * n2pi / nOptions,
				fCb = fCallback || function () {};
			$animContainer.get(0).nCurrentPhi = nCurrentPhi;
			// we use jQuery default animations to take profit of the queue
			$animContainer.animate({
				nCurrentPhi: nTarget
			}, {
				duration: Math.abs(nDelta) * 400, // lo de 400 es por decir y porque queda mono
				step: function(now, fx){
					setAnimationAngle(now);
				},
				complete: fCb
			});
		},
		/**
		 * Move the wheel to the desired index
		 * @param {Number} nItemIndex
		 * @param {fCallback} function to execute at the end of the animation
		 */
		moveToIndex: function(nItemIndex, fCallback) {
			var nCurrentIndex = this.getActiveIndex(),
				nDelta = nItemIndex - nCurrentIndex,
				fCb = fCallback || function () {};
			if (nDelta > nOptions/2) {
				nDelta = nDelta - nOptions;
			}
			else if (nDelta < -nOptions/2) {
				nDelta = nDelta + nOptions;
			}
			this.move(nDelta, fCb);
		}
	}
	
	// define control events (moving the wheel)
	$('#pseudo3d-gallery-controls span.pseudo3d-gallery-control-item', $form).each(function (nIndex) {
		$(this).click(function () {
			document.getElementById('pseudo3d-gallery').pseudo3dGallery.moveToIndex(nIndex);
			var $t = $(this).addClass('current'),
				$sibl = $t.siblings().removeClass('current').hide(); // ocultamos temporalmente para forzar el mouseout
			// metemos el valor correcto y mandamos
			$options.eq(nIndex).find(':radio').attr('checked', true);
			nAux = nIndex;
			$form.submit();
			// definimos el evento para volver a mostrar los siblings
			$t.one('mouseover', function () {
				$sibl.css('display', '');
			})
		});
	});
	
	// submit the form
	$form.submit(function () {
		var urlDestiny = $options.eq(nAux).find(':radio').attr('value').toString();
		window.location.href = urlDestiny;
		// controlamos que exista el elemento a sustituir o mandamos el form
		if (urlDestiny.length == 0) {
			return true;
		}
		$.fancybox.showActivity();
		// preparo este AJAX a modo de ejemplo  
		return false;
	});
};
