var Carousel = Class.create({
	initialize: function( element ){
		this.element = $(element);
		this.container = this.element.select( '.container' )[0];
		this.innerContainer = this.container.select( '.innerContainer' )[0];
		this.items = this.innerContainer.select( '.item' );
		this.firstItem = this.items[0];
		
		// Different init depending on the orientation of the carousel
		if(this.element.down('.leftButton')!=null) {
			this.orientation = 'horizontal';
			this.initHorizontal();
		} else {
			this.orientation = 'vertical';
			this.initVertical();
		}
		
		// Default value for scroll amount
		this.scrollSize = 1;
		
		// Read config from json
		var jsonspan = this.element.down('span.jsondata');
		
		if(jsonspan) {
			// We read the json configuration and set the new parameters
			var jsondata = this.getJSON(jsonspan);
			if(jsondata.scrollSize) {
				this.scrollSize = jsondata.scrollSize;
			}
		}
		
		this.currentScrollPos = 0;
		this.currentIndex = 0;
		this.currentItem = this.items[this.currentIndex];
		this.effect = null;

		this.checkNextActive();
		this.prevButton.observe('click', this.prevHandler.bindAsEventListener(this) );
		this.nextButton.observe('click', this.nextHandler.bindAsEventListener(this) );
		this.element.removeClassName('notInitialized');

	},
	
	initHorizontal: function() {
		// Get appropriate elements
		this.prevButton = this.element.select( '.leftButton' )[0];
		this.prevButtonGradient = this.element.select( '.leftButtonGradient' )[0];
		this.nextButton = this.element.select( '.rightButton' )[0];
		this.nextButtonGradient = this.element.select( '.rightButtonGradient' )[0];
		
		// Calculate the width of an element
		firstItem = this.items[0];
		this.itemGap = firstItem.getWidth();
		this.itemGap += parseInt(firstItem.getStyle('margin-left').replace('px',''));
		this.itemGap += parseInt(firstItem.getStyle('margin-right').replace('px',''));
		
		// Calculate the width of the whole carousel
		viewGap = this.container.getWidth();
		viewGap += parseInt(this.container.getStyle('margin-left').replace('px',''));
		viewGap += parseInt(this.container.getStyle('margin-right').replace('px',''));
		
		// Calculate how many items are shown in the carousel visible area
		this.viewedItems = Math.round(viewGap / this.itemGap);
	},
	
	initVertical: function() {
		// Get appropriate elements
		this.prevButton = this.element.select( '.upButton' )[0];
		this.prevButtonGradient = this.element.select( '.upButtonGradient' )[0];
		this.nextButton = this.element.select( '.downButton' )[0];
		this.nextButtonGradient = this.element.select( '.downButtonGradient' )[0];
		
		// Calculate the height of an element
		firstItem = this.items[0];
		this.itemGap = firstItem.getHeight();
		this.itemGap += parseInt(firstItem.getStyle('margin-top').replace('px',''));
		this.itemGap += parseInt(firstItem.getStyle('margin-bottom').replace('px',''));
		
		// Calculate the height of the whole carousel
		viewGap = this.container.getHeight();
		viewGap += parseInt(this.container.getStyle('margin-top').replace('px',''));
		viewGap += parseInt(this.container.getStyle('margin-bottom').replace('px',''));
		
		// Calculate how many items are shown in the carousel visible area
		this.viewedItems = Math.round(viewGap / this.itemGap);
	},
	
	prevHandler: function(e) {
		if( this.currentIndex >= this.scrollSize ) {
			this.scrollToIndex( this.currentIndex-this.scrollSize );
			this.currentScrollPos = this.currentScrollPos - 1;
		} else if (this.currentIndex > 0) {
			this.scrollToIndex(0);
			this.currentScrollPos = this.currentScrollPos - 1;	
		}
		this.checkNextActive();
		this.checkPrevActive();
	},

	nextHandler: function(e) {
		if( this.currentIndex+this.viewedItems+this.scrollSize <= this.items.length ) {
			this.scrollToIndex( this.currentIndex+this.scrollSize );
			this.currentScrollPos = this.currentScrollPos + 1;
		} else if ( this.currentIndex+this.viewedItems < this.items.length) {
			this.scrollToIndex( this.items.length-this.viewedItems );
			this.currentScrollPos = this.currentScrollPos + 1;	
		}
		this.checkNextActive();
		this.checkPrevActive();
	},

    checkNextActive: function() {
		this.debugThis();
		if( this.currentIndex+this.viewedItems < this.items.length  ) {
			this.nextButton.addClassName('active');	
			this.nextButtonGradient.addClassName('active');
		}else {
			this.nextButton.removeClassName('active');
			this.nextButtonGradient.removeClassName('active');
		}
    },

    checkPrevActive: function() {
    	this.debugThis();
    	if( this.currentScrollPos + this.viewedItems > this.viewedItems ) {
			this.prevButton.addClassName('active');
			this.prevButtonGradient.addClassName('active');
		}else {
			this.prevButton.removeClassName('active');
			this.prevButtonGradient.removeClassName('active');
		}
    },

    debugThis: function() {
    	/*
		console.log("this.scrollSize:" + this.scrollSize);
		console.log("this.currentScrollPos:" + this.currentScrollPos);
		console.log("this.viewedItems:" + this.viewedItems);
		*/
    },

    getCoordinate: function(index) {
        return index * (-this.itemGap);
    },

    scrollToIndex: function( index ) {
        var coordinate = this.getCoordinate(index);
        if(this.orientation=='horizontal') {
        	var currentCoordinate = parseInt(Element.getStyle(this.innerContainer, 'left')) || 0;
        } else {
        	var currentCoordinate = parseInt(Element.getStyle(this.innerContainer, 'top')) || 0;
        }
        var move = coordinate - currentCoordinate;
        if( null!=this.effect ) {
        	this.effect.cancel();
        }
        if(this.orientation=='horizontal') {
	        this.effect = new Effect.Move(this.innerContainer, {
	            duration: 0.3,
	            fps: 35,
	            x: move,
	            afterFinish: function() {
	        		this.innerContainer.setStyle({ left: coordinate + 'px' });
	        		this.effect = null;
	            }.bind(this)
	        });
        } else {
	        this.effect = new Effect.Move(this.innerContainer, {
	            duration: 0.3,
	            fps: 35,
	            y: move,
	            afterFinish: function() {
	        		this.innerContainer.setStyle({ top: coordinate + 'px' });
	        		this.effect = null;
	            }.bind(this)
	        });
        }
        this.currentIndex = index;
	},
	
	getJSON : function(jsonData) {
		var json = {};
		if (jsonData) {
			var plainData = '';
			if(jsonData.innerHTML!=undefined) {
				plainData = new String(jsonData.innerHTML);
			} else {
				plainData = new String(jsonData);
			}
			var attr = plainData.split('<!-- json:');
			if (attr.length >= 2) {
				var json_raw = attr[1].split('-->')[0];
				try {
					// The json_raw var is HTML encoded.
					json_raw = json_raw.unescapeHTML();

					// JS code in JSON object is not allowed
					json = json_raw.evalJSON(true);
				} catch (e) {
					console.error("JSON could not be parsed (%o)",e);
				}
			}
		}
		return json;
	}
});

var ZoomImage = Class.create({
	intendedZoomFactor: 4,
	opening: false,
	open: false,
	closing: false,
	flyOff: null,
	flyDim: null,

	initialize: function() {
		this.div = $('scene7zoom');
		if (this.div) {
			this.div.select('.base').each( function( elem ) {
				this.base = elem;
			}.bind(this) );
			this.div.select('.baseImage').each( function( elem ) {
				this.baseImage = elem;
			}.bind(this) );
			this.div.select('.marker').each( function( elem ) {
				this.marker = elem;
			}.bind(this) );
			this.div.select('.flyout').each( function( elem ) {
				this.flyout = elem;
			}.bind(this) );
			this.div.select('.flyoutObj').each( function( elem ) {
				this.flyoutObj = elem;
			}.bind(this) );

			this.flyDim = this.flyout.getDimensions();
			this.flyOff = { left: 348, top: 0 }; //this.flyout.positionedOffset();

			this.div.select('.zoomImage').each( function( elem ) {
				this.zoomImage = elem;
				//this.zoomImage.observe('onload', this.handleZoomLoaded.bind(this) );

				this.cacheImage = new Image();
				this.cacheImage.onload = this.handleZoomLoaded.bind(this);

				this.zoomImage.config = null;
				this.zoomImage.loaded = false;
				if (this.zoomImage.hasClassName('noImageSet')) {
					this.zoomImage.removeClassName('noImageSet');
					this.zoomImage.config = this.zoomImage.getConfiguration('ImgLink', true);
					this.loadZoomImage(this.zoomImage.config.img);
					this.zoomImage.loaded = true;
				} else {
					this.zoomImage.loaded = true;
				}
			}.bind(this) );

			this.base.observe('mousemove', this.handleMouseMove.bind(this) );
			this.base.observe('mouseenter', this.handleMouseMove.bind(this) );
			this.div.observe('mouseleave', this.handleMouseLeave.bind(this) );
			this.flyout.observe('mousemove', this.handleMouseFlyout.bind(this) );

			//this.adjustMarkerSize();
		}
	},

	setImage: function( baseImageUrl, zoomImageUrl ) {
		//var zoomImageUrl = baseImageUrl.split('?')[0];
		this.baseImage.src = baseImageUrl;
		//SOLI-814 sfhe
		this.zoomImage.config = {
			img: zoomImageUrl
		};

		this.loadZoomImage(zoomImageUrl);
		this.zoomImageLoaded = true;
	},

	loadZoomImage: function( zoomImageUrl ) {
		this.zoomImage.src = zoomImageUrl;
		this.cacheImage.src = zoomImageUrl;

		/*var ajaxRequest = new Ajax.Request(zoomImageUrl+'req=imageprops,text', {
			method: 'post',
			evalJS: false,
			evalJSON: false,
			onComplete: function(transport) {
				var prop = getS7Response( transport.responseText );
				var width = prop['image.width'];
				var height = prop['image.height'];
				zoomImageUrl += 'wid=' + width + '&hei=' + height;
				this.zoomImage.src = zoomImageUrl;
				this.cacheImage.src = zoomImageUrl;
		/*	}.bind(this)
		}); */
	},

	handleZoomLoaded: function() {
		this.adjustMarkerSize();
	},

	handleMouseFlyout: function( ev ) {
		ev.stop();
		if( !this.opening && this.open && !this.closing ) {
			this.closing = true;
			this.triggerEffects();
		}
	},

	handleMouseLeave: function( ev ) {
		ev.stop();
		//this.flyout.hide();
		//this.marker.hide();
		if( !this.closing ) {
			this.closing = true;
			this.triggerEffects();
		}
		return false;
	},

	deferId: null,
	handleMouseMove: function( ev ) {
		// reload Zoom Image from scene7 //
		if (this.zoomImage.config && !this.zoomImage.loaded) {
			this.loadZoomImage(this.zoomImage.config.img);
		}
		ev.stop();
		if( null==this.deferId ) {
			var rect = this.getCoordinates( ev );
			this.deferId = this.update.bind( this, rect ).defer();
		}
		if( !this.open && !this.opening ) {
			this.opening = true;
			this.triggerEffects( rect );
		}

		return false;
	},

	triggerEffects: function( rect ) {
		if( this.opening && !this.closing ) {
			var markDim = this.marker.getDimensions();
			var markOff = this.marker.positionedOffset();
			if( rect ) {
				markOff = { left: rect.x1, top: rect.y1 };
			}

			this.setPosition( this.flyout, markOff.left, markOff.top );
			this.setDimensions( this.flyout, markDim.width, markDim.height );

			this.openEffect = new Effect.Parallel([
			    new Effect.Appear( this.marker, {sync: true, to: 0.5 } ),
			    new Effect.Appear( this.flyout, {sync: true, from: 0.5 } ),
			    new Effect.Move( this.flyout, { x: this.flyOff.left, y: this.flyOff.top, mode: 'absolute', sync: true } ),
			    new Effect.Morph( this.flyout, {
			    	style: { width: this.flyDim.width+'px', height: this.flyDim.height+'px' },
			    	sync: true,
			    	afterFinish: (function(effect) {
			    		this.open = true;
			    		this.opening = false;
			    		this.triggerEffects();
			    	}).bind(this)
			    } )
			], { duration: 0.3 } );
		}
		if( this.closing && !this.opening ) {
			this.closeEffect = new Effect.Parallel([
			    new Effect.Fade( this.marker, {sync: true, from: 0.5 } ),
			    new Effect.Fade( this.flyout, { sync: true } ),
			    new Effect.Morph( this.flyout, {
			    	style: { width: 1+'px' },
			    	sync: true,
			    	afterFinish: (function(effect) {
			    		this.open = false;
			    		this.closing = false;
			    		this.triggerEffects();
			    	}).bind(this)
			    } )
            ], { duration: 0.2 } );
		}
	},

	update: function( rect ) {
		this.deferId = null;
		this.setPosition( this.marker, rect.x1, rect.y1 );
		this.setPosition( this.flyoutObj, -rect.x2, -rect.y2 );
	},

	getCoordinates: function( ev ) {
		var off = this.baseImage.cumulativeOffset();
		var x = ev.pointerX() - off.left;
		var y = ev.pointerY() - off.top;
		var dim = this.baseImage.getDimensions();
		var markDim = this.marker.getDimensions();

		var rect = { x1:0, x2:0, y1:0, y2:0 };
		if( x >= dim.width + 1 - markDim.width/2 ) {
			rect.x1 = dim.width + 1 - markDim.width;
		}
		else if( x >= markDim.width/2 - 1 ) {
			rect.x1 = x - markDim.width/2;
		}
		else if( x >= 0 ) {
			rect.x1 = -1;
		}

		if( y >= dim.height + 1 - markDim.height/2 ) {
			rect.y1 = dim.height + 1 - markDim.height;
		}
		else if( y >= markDim.height/2 - 1 ) {
			rect.y1 = y - markDim.height/2;
		}
		else if( y >= 0 ) {
			rect.y1 = -1;
		}

		var zoomDim = this.zoomImage //.getDimensions();
		var flyDim = this.flyDim; // this.flyout.getDimensions();
		rect.x2 = Math.min( ( rect.x1 + 1 ) * this.zoomFactor, zoomDim.width - flyDim.width );
		rect.y2 = Math.min( ( rect.y1 + 1 ) * this.zoomFactor, zoomDim.height - flyDim.height );
		return rect;
	},

	adjustMarkerSize: function() {
		var zoomDim = this.cacheImage;
		var flyDim = this.flyDim; //this.flyout.getDimensions();
		var baseDim = this.baseImage.getDimensions();
		var divDim = this.div.getDimensions();

		var zoomFactor = Math.min( this.intendedZoomFactor, Math.max( zoomDim.width / baseDim.width, zoomDim.height / baseDim.height ) );

		var width = flyDim.width / zoomFactor;
		var height = flyDim.height / zoomFactor;

		if( width > divDim.width || height > divDim.height ) {
			if( width / height > divDim.width / divDim.height ) {
				zoomFactor *= width / divDim.width;
			}
			else {
				zoomFactor *= height / divDim.height;
			}
			width = flyDim.width / zoomFactor;
			height = flyDim.height / zoomFactor;
		}
		this.zoomFactor = zoomFactor;
		this.setDimensions( this.zoomImage, divDim.width * zoomFactor, divDim.height * zoomFactor );
		this.setDimensions( this.marker, width, height );
	},

	setDimensions: function( elem, width, height ) {
		elem.style.width = width + 'px';
		elem.style.height = height + 'px';
	},

	setPosition: function( elem, left, top ) {
		if (top) {
			elem.style.top = top + 'px';
		}
		if (left) {
			elem.style.left = left + 'px';
		}
	}
});


/* Handle variation selections and inventory handling */
var variationHandler = Class.create({
	reloadCallback: null,
	callbackContext: null,
	variationValueFields: null,
	symbolicVariationValueFields: null,
	availabilityInformation: null,
	availabilityInformationElementID: null,
	availabilityInformationJSON: null,
	variationValues: null,
	selectedProduct: null,
	fixDisabledOptionFields: false,
	imagesForColors: null,
	imageIndex: 0,
	storedColorName: null,

	/* Ctor */
	initialize: function(reloadCallback, callbackContext, availabilityInformation) {
		this.reloadCallback = reloadCallback;
		this.callbackContext = callbackContext;
		this.disabledOptionFieldFixCheck();
		this.availabilityInformationElementID = availabilityInformation;
		var fitIcon = $('fitIcon');
		if (fitIcon) {
			var fitTab = $('passform');
			if (fitTab) {
				fitIcon.clickTabHandler = fitTab.tabHandler;
				fitIcon.onclick = function() {
					this.clickTabHandler.setTab('passform');
					return false;
				};
			}
		}
		this.reinit();
	},

	/* reinit variationHandler. Have to be done after selecting variant. Should be called
	   by reloadCallback function.
	*/
	reinit: function() {
		var that = this;

		this.initAvailabilityInformation(this.availabilityInformationElementID);
		this.initVariationValues();

		var selProd = $('selectedProduct');
		if (selProd) {
			this.selectedProduct = selProd.value;
		} else {
			this.selectedProduct = null;
			selProd = null;
		}
		this.updateValuesWithAvailabilityInfos();

		$$('select.variationSelectionField').each(function(field) {
			field.variationHandler = that;
			field.onchange = that.selectVariationValue;
		});

		var colorSelectors = $$('.colorSelector.variantSelection a');
		var sizeSelectors = $$('.sizeSelector a');

		try {
			var imagesForColors = $F('imagesForColors');
			this.imagesForColors = imagesForColors.evalJSON();
		} catch (e) {
			this.imagesForColors = {};
		}

		this.symbolicVariationValueFields = [];
		colorSelectors.each(function(field) {
			field.variationHandler = that;
			that.symbolicVariationValueFields.push(field);
			field.observe('mouseenter', that.colorMouseOverHandler );
			field.observe('mouseout', that.colorMouseOutHandler );
		});

		if (this.variationValues.get(Constants.catalog.colorVariantID) == null || this.variationValues.get(Constants.catalog.colorVariantID).size() == 0) {
			var selectedColorName = $('selectedColorName');
			if (selectedColorName) {
				selectedColorName.update('');
			}
		}

		sizeSelectors.each(function(field) {
			field.variationHandler = that;
			that.symbolicVariationValueFields.push(field);
		});

		this.symbolicVariationValueFields.each(function(field) {
			field.onclick = that.selectVariationValue;
		});

		var selectedProduct = this.getSelectedProduct();
		var productQuantity = $('productQuantity');
		if (productQuantity && selectedProduct) {
			var ats = selectedProduct.ats;
			if (ats != Constants.catalog.maxShownAvailableQuantity) {
				var options = productQuantity.options;
				var elToRem = new Array();
				for (var i = 0; i < options.length; i++) {
					if (options[i].value > ats) {
						elToRem.push($(options[i]));
					}
				}
				elToRem.each(function(el) {
					el.remove();
				});
			}
		}
		this.initIE6BadgePositionFix();
		initIE6HoverFix();
		this.initImageCarousels();
		this.initZoomImage();
		this.initReadMoreButton();
	},

	/* retrieve availability information provided by a JSON string */
	initAvailabilityInformation: function(availabilityInformation) {
		var availInfo = $(availabilityInformation);
		if (availInfo) {
			try {
				this.availabilityInformation = eval(availInfo.value)[0];
				this.availabilityInformationJSON = availInfo.value;
			} catch (ex) {}
		}
		
		if(!this.availabilityInformation) {
			this.availabilityInformation = {varAttrs:[],variants:{}};
			this.availabilityInformationJSON = '[{varAttrs:[],variants:{}}]';
		}
	},

	/* provide available variation values as a easy-to-use hash */
	initVariationValues: function() {
		this.variationValues = $H();
		this.availabilityInformation.varAttrs.each(function(varAttrID) {
			var entry = $H();
			this.variationValues.set(varAttrID, entry);
		}.bind(this));
		for (prodID in this.availabilityInformation.variants) {
			var product = this.availabilityInformation.variants[prodID];
			for (varAttrID in product.varAttrs) {
				var value = product.varAttrs[varAttrID];
				var entry = this.variationValues.get(varAttrID);
				if (!entry) {
					entry = $H();
				}
				var valueEntry = entry.get(value.value);
				if (!valueEntry) {
					entry.set(value.value, value.displayValue);
				}
				this.variationValues.set(varAttrID, entry);
			}
		}
	},

	/* do we have to fix IE to handle disabled option fields */
	disabledOptionFieldFixCheck: function() {
		var ie = /msie\s(\d)/.test(navigator.userAgent.toLowerCase());
		if (ie) {
			var ieVersion = RegExp.$1;
			if (ieVersion < 8) {
				this.fixDisabledOptionFields = true;
			}
		}
	},

	/* handle disabled option fields with IE */
	fixIEOptionFields: function() {
		if (this.fixDisabledOptionFields) {
			var fields = $$('select.variationSelectionField option');
			if (fields) {
				fields.each(function(field) {
					if (field.disabled) {
						field.addClassName('disabledOptionIE');
					}
				});
			}
		}
	},

	initIE6BadgePositionFix: function() {
		if (evilBrowserInformation.isEvil && evilBrowserInformation.evilVersion < 7) {
			var image = $('normalImage');
			var badges = $$('#pt_productdetails .imageContainer .badges');
			if (badges.length > 0) {
				var offset = image.cumulativeOffset();
				badges.each(function(el) {
					el.setStyle({
						left: offset.left-200,
						top: offset.top
					});
				});
			}
		}
	},

	/* update rendered variation values and disable/mark unavailable and impossible combinations
	   using the information provided by the availability informations.
	*/
	updateValuesWithAvailabilityInfos: function() {
		var selectedVariationAttributeValues = new Array();
		this.variationValues.keys().each(function(varAttr) {
			this.markUnavailableSelections(varAttr, selectedVariationAttributeValues);

			selectedVariationAttributeValues.push({
				varAttr: varAttr,
				value: $$('.jsActive .varS_' + varAttr)[0].id.replace('varS_' + varAttr + '_', '')
			});
		}.bind(this));
		this.fixIEOptionFields();
	},

	/* mark impossible variation selections (evaluated by availability information) */
	markUnavailableSelections: function(varAttr, selectedVariationAttributes) {
		if (!varAttr || !this.variationValues || !this.availabilityInformation || !this.availabilityInformation.variants) {
			return;
		}
		var varAttrFields = $$('.varS_' + varAttr);
		if (!varAttrFields) {
			return;
		}
		var variationAttributeValues = this.variationValues.get(varAttr);
		if (!variationAttributeValues) {
			return;
		}
		if (!selectedVariationAttributes) {
			selectedVariationAttributes = [];
		}
		
		varAttrFields.each(function(valueField) {
			var selectedValue = null;
			var isSelectable = variationAttributeValues.keys().any(function(value) {
				if ('varS_' + varAttr + '_' + value == valueField.id) {
					selectedValue = value;

					return true;
				}
				return false;
			});

			if (isSelectable) {
				isSelectable = Object.values(this.availabilityInformation.variants).any(function(variant) {
					var variantFound = selectedVariationAttributes.all(function(selectedVariationAttribute) {
						return variant.varAttrs && variant.varAttrs[selectedVariationAttribute.varAttr] && variant.varAttrs[selectedVariationAttribute.varAttr].value == selectedVariationAttribute.value;
					});
					return variantFound && variant.varAttrs && variant.varAttrs[varAttr] && variant.varAttrs[varAttr].value == selectedValue && variant.ats > 0;
				});
			}

			if (valueField.tagName == 'OPTION') {
				valueField.disabled = !isSelectable;
				valueField.remove(); // we have to remove the option because the non-standard compliant (evil) browsers doesn't support disabled options.
			} else if (valueField.tagName == 'TD') {
				if (isSelectable) {
					valueField.removeClassName('inactive');
				} else {
					valueField.addClassName('inactive');
				}
				var links = valueField.select('a');
				links.each(function(link) {
					link.selectorDisabled = !isSelectable;
				});
			} else if (valueField.tagName == 'A') {
				if (isSelectable) {
					valueField.removeClassName('inactive');
				} else {
					valueField.addClassName('inactive');
				}
				valueField.selectorDisabled = !isSelectable;
			}
		}.bind(this));
	},

	/* matchs the value to the selected product */
	matchVariationValues: function(varAttr, selectedProduct, value) {
		var expectedValues = $H();
		for (attribute in selectedProduct.varAttrs) {
			if (attribute != varAttr) {
				expectedValues.set(attribute, selectedProduct.varAttrs[attribute].value);
			} else {
				expectedValues.set(attribute, value);
			}
		}
		var found = false;
		for (productID in this.availabilityInformation.variants) {
			var product = this.availabilityInformation.variants[productID];
			var matches = 0;
			expectedValues.keys().each(function(attribute) {
				if (product.varAttrs[attribute].value == expectedValues.get(attribute)) {
					++matches;
				}
			});
			if (matches == expectedValues.size()) {
				found = true;
				break;
			}
		}
		return found;
	},

	/* handle variation value selection */
	selectVariationValue: function() {
		if (this.up('.jsActive')) {
			return false;
		}

		var that = this.variationHandler;
		var url = null;

		var disabled = false;

		if (this.tagName == 'A' && this.hasClassName('inactive')) {
			disabled = true;
		} else if (this.tagName == 'SELECT') {
			var value = this.value;
			this.select('option').each(function(field) {
				if (field.value == value) {
					if (field.hasClassName('disabledOptionIE')) {
						disabled = true;
					}
				}
			});
		} else {
			disabled = this.disabled;
		}

		if (!disabled) {
			if (this.tagName == 'A') {
				url = this.getConfiguration('variations').url;
			} else {
				url = this.value;
			}
			MiniCart.deactivateAddToCartButtons();
			
			that.reloadForVariationSelection(url, this.up('.jsProductDetails'));
		}

		return false;
	},

	/* send variation selection to server and reload product presentation */
	reloadForVariationSelection: function(selectURL, root) {
		var that = this;
		var queryParams = selectURL.toQueryParams();
		
		var url = selectURL.split('?')[0];
		new Ajax.Request(url, {
			method: 'GET',
			parameters: queryParams,
			onSuccess: function(transport) {
				that.reloadSuccess(transport.responseText);

				var imageLink = root.select('.selectImageLink').detect(function(item) {
					if (item.name == 'image'+that.imageIndex) {
						return true;
					}
					return false;
				});
				that.selectImageHandler(imageLink);
			},
			onFailure: AjaxErrorHandler
		});
	},

	/* handle successful response for variation selection */
	reloadSuccess: function(content) {
		var contentParts = content.split(Constants.ajax.contentSplitter);
		var responseProlog = {quickView: false, productID: null, productDetailLink: null};
		var str = contentParts[0];
		str = removeXMLComments(str);
		try {
			responseProlog = eval(str)[0];
		} catch (e) {
		}
		if (!responseProlog.quickView) {
			$('productDetails').update(contentParts[1]);
			$('productDetailLinks').update(contentParts[2]);
		} else {
			$('quickviewData').update(contentParts[1]);
			var qvTitleProductID = $('qvTitleProductID');
			if (qvTitleProductID!=null) {
				qvTitleProductID.update(responseProlog.productID);
			}

			var qvProdDetailLink = $('qvProdDetailLink')
			if (qvProdDetailLink!=null) {
				var detailLinkURL = qvProdDetailLink.href;
				var urlParts = detailLinkURL.split('?');
				var detailLinkURLParams = detailLinkURL.toQueryParams();
				detailLinkURLParams.pid = responseProlog.productID;
				var parameterString = Object.toQueryString(detailLinkURLParams);
	
				qvProdDetailLink.href = urlParts[0] + '?' + parameterString.replace(/&amp;\s*/g, '&');
			}
		}
		this.storedColorName = null;
		this.reloadCallback(this.callbackContext);
	},

	/* handle mouse over on color swatches */
	colorMouseOverHandler: function() {
		if( this.variationHandler.storedColorName!=null ) {
			return;
		}
		var colorSwatch = this.select('img');
		var colorName = null;
		if (colorSwatch.length > 0) {
			colorName = colorSwatch[0].alt;
		}
		var colorName = this.select('img')[0].alt;
		if (colorName) {
			var colorNameField = $('selectedColorName');
			if (colorNameField) {
				this.variationHandler.storedColorName = colorNameField.innerHTML;
				if( 'textContent' in colorNameField ) {
					colorNameField.textContent = colorName;
				}
				else {
					colorNameField.innerText = colorName;
				}
			}
		}
		if (!this.hasClassName('active')) {
			var colorValue = this.id.replace('varS_' + Constants.catalog.colorVariantID + '_', '');
			var imagesForValue = this.variationHandler.imagesForColors[colorValue];

			this.variationHandler.markUnavailableSelections(Constants.catalog.sizeVariantID, [{varAttr: Constants.catalog.colorVariantID, value: colorValue}]);

			// Change images
			if (imagesForValue) {
				var bigImage = $$('#scene7zoom .base img');
				if( bigImage.length==1 ) {
					var index = this.variationHandler.imageIndex < imagesForValue.length ? this.variationHandler.imageIndex : 0;
					this.storedBigImage = bigImage[0].src;
					bigImage[0].src = imagesForValue[index];
				}
			}
		}
	},

	/* handle mouse out on color swatches */
	colorMouseOutHandler: function( ev ) {
		var toE = $(ev.toElement || ev.relatedTarget);
		if( toE!=null && (toE==this || toE.descendantOf(this)) ) {
			ev.stop();
			return;
		}

		// Reset images
		var storedColorName = this.variationHandler.storedColorName;
		if (storedColorName && storedColorName != null) {
			var colorNameField = $('selectedColorName');
			if (colorNameField) {
				colorNameField.innerHTML = storedColorName;
				this.variationHandler.storedColorName = null;
			}
		}
		if (!this.hasClassName('active')) {
			var bigImage = $$('#scene7zoom .base img');
			var storedBigImage = this.storedBigImage;
			if( bigImage.length==1 && storedBigImage ) {
				bigImage[0].src = storedBigImage;
				this.storedBigImage = null;
			}
		}

		this.variationHandler.markUnavailableSelections(Constants.catalog.sizeVariantID, [{varAttr: Constants.catalog.colorVariantID, value: $$('.jsActive .varS_variantColor')[0].id.replace('varS_variantColor_', '')}]);
	},

	/* returns the currently selected product */
	getSelectedProduct: function() {
		var product = null;
		if (this.selectedProduct != null) {
			product = this.availabilityInformation.variants[this.selectedProduct];
		}
		return product;
	},

	initImageCarousels: function() {
		$$('.imageSelector.notInitialized').each(function(carousel) {
			this.imageCarousel = new Carousel(carousel);
			carousel.select('.selectImageLink').each(function(e) {
				e.observe('click', function(event) {
					var imageLink = event.findElement('.selectImageLink');
					this.selectImageHandler(imageLink);
				}.bind(this));
			}.bind(this));
		}.bind(this));
	},

	initZoomImage: function() {
		this.zoomImage = new ZoomImage();
	},
	
	selectImageHandler: function(element) {
		var largeImage = element.next('.largeImage');
		var largeImageUrl = (largeImage.innerText || largeImage.textContent).replace(/^\s+/g,'').replace(/\s+$/g,'');
		if(this.zoomImage.zoomImage==undefined) {
			element.up('.imageSelector').up().down('.jsCarouselDisplayWindow').src = largeImageUrl;
		} else {
			var zoomImage = element.next('.zoomImage');
			document.fire('tracking:onZoomView', {});
			var zoomImageUrl = (zoomImage.innerText || zoomImage.textContent).replace(/^\s+/g,'').replace(/\s+$/g,'');
			this.zoomImage.setImage( largeImageUrl, zoomImageUrl );
		}
		var index = element.next('.index');
		var indexNumber = parseInt(index.innerHTML);
		this.imageIndex = indexNumber;
	},

	initReadMoreButton: function() {
		var button = $('jsMoreDescription');
		if (null != button) {
			button.observe('mouseover', this.showMore.bindAsEventListener(this));
			$('descriptions').observe('mouseout', this.hideMore.bindAsEventListener(this));
		}
	},

	isMore: false,
	effect: null,

	showMore: function(ev) {
		if (this.isMore /*||  this.effects!=null*/) {
			return;
		}
		new Effect.Parallel([
			Effect.SlideUp('shortDescription', { sync: true }),
			Effect.BlindDown('longDescription', { sync: true })
	    ], { duration: .5, queue: { position: 'end', scope: 'description' } } );
		this.isMore = true;
	},

	hideMore: function(ev) {
		if (!this.isMore /*||  this.effects!=null*/) {
			return;
		}
		var toE = $(ev.toElement || ev.relatedTarget);
		if (toE != null && (toE.id == 'descriptions' || toE.descendantOf($('descriptions')))) {
			ev.stop();
			return;
		}
		new Effect.Parallel([
		   Effect.SlideDown('shortDescription', { sync: true }),
		   Effect.BlindUp('longDescription', { sync: true })
       	], { duration: .5, queue: { position: 'end', scope: 'description' } } );
		this.isMore = false;
	}

});

var quickView = null;

/* Handler for quickview overlays and product mini behavior */
var QuickViewHandler = Class.create({

	productMinis: null,
	productMinisByProductID: null,
	quickViewOverlayElement: null,
	quickViewOverlay: null,
	varHandler: null,
	currentlyShownProductMini: null,

	/* Ctor */
	initialize: function(issetproduct) {
		// on product set pages use other class to get prod mini
		if(issetproduct){
			var productMinis = $$('.setproduct');
		}
		else{
			var productMinis = $$('.prodMini');
		}
		this.productMinis = new Array();
		this.productMinisByProductID = $H();
		var lastProductMini = null;

		productMinis.each(function(element) {
			if(issetproduct){
				// on product set pages use SetProduct as product mini
				var productMini = new SetProduct(this, element);
			}
			else{
				var productMini = new ProductMini(this, element, lastProductMini);
			
				// do not add productsets
				if(!productMini.isProductSet){
					this.productMinis.push(productMini);
					lastProductMini = productMini;
				
					var prodMinisForID = this.productMinisByProductID.get(productMini.productID);
					if (!prodMinisForID) {
						prodMinisForID = [];
					}
					prodMinisForID.push(productMini);
					this.productMinisByProductID.set(productMini.productID, prodMinisForID);
				}
				productMini.setAltImage();
			}
		}.bind(this));

		var qvOverlayElement = $('quickview');
		if (qvOverlayElement) {
			this.quickViewOverlayElement = qvOverlayElement;
		}
	},

	showProduct: function(pid,productsetid) {
		if(productsetid.length > 0){
			this.loadQuickView({quickViewURL: Constants.url.quickViewURL + escape(pid) + '&productsetid=' + escape(productsetid)});
		}
		else{
			this.loadQuickView({quickViewURL: Constants.url.quickViewURL + escape(pid)});
		}
	},

	/* event handler for quick view open requests */
	loadQuickView: function(productMini) {
		if (productMini) {
			StatusWindow.openProgressWindow();
			new Ajax.Request(productMini.quickViewURL, {method:'get', onSuccess: function(transport) {
				this.quickViewLoaded(transport.responseText, productMini);
			}.bind(this), onFailure: AjaxErrorHandler});
		}
	},

	/* handle successful quick view response */
	quickViewLoaded: function(responseText, productMini) {
		StatusWindow.close();
		this.currentlyShownProductMini = productMini;
		var contentParts = responseText.split(Constants.ajax.contentSplitter);
		this.quickViewOverlay = new Overlay('quickview');
		this.quickViewOverlay.show();
		this.quickViewOverlay.update(contentParts[0]);
		tabHandlerInit();
		this.varHandler = new variationHandler(this.reloadCallback, this, 'availability');
		this.initializeNavigationButtons();
		MiniCart.registerAddToCartButton($('addToCartButton'));
	},

	/* init the navigation buttons on quick view overlay (previous and next links) */
	initializeNavigationButtons: function() {
		initializePopupLinkHandler();
		$$('#quickview .prevArticle').each(function(element) {
			element.onclick = this.navButtonPrevious.bind(this);
			if (!this.currentlyShownProductMini.predecessor) {
				element.style.visibility = 'hidden';
			} else {
				element.style.visibility = 'visible';
			}
		}.bind(this));
		$$('#quickview .nextArticle').each(function(element) {
			element.onclick = this.navButtonNext.bind(this);
			if (!this.currentlyShownProductMini.successor) {
				element.style.visibility = 'hidden';
			} else {
				element.style.visibility = 'visible';
			}
		}.bind(this));
		$$('#quickview .divider').each(function(element) {
			if (!this.currentlyShownProductMini.successor || !this.currentlyShownProductMini.predecessor) {
				element.style.visibility = 'hidden';
			} else {
				element.style.visibility = 'visible';
			}
		}.bind(this));
	},

	/* Event handler for "previous" navigation link click */
	navButtonPrevious: function() {
		this.quickViewOverlay.hide();
		this.loadQuickView(this.currentlyShownProductMini.predecessor);
		return false;
	},

	/* Event handler for "next" navigation link click */
	navButtonNext: function() {
		this.quickViewOverlay.hide();
		this.loadQuickView(this.currentlyShownProductMini.successor);
		return false;
	},

	/* handle variation selection and reinit variation handler */
	reloadCallback: function(callbackContext) {
		callbackContext.varHandler.reinit();
		tabHandlerInit();
		initializePopupLinkHandler();
		MiniCart.registerAddToCartButton($('addToCartButton'));
	}

});

/* This class represents a product mini */
var ProductMini = Class.create({

	element: null,
	quickViewURL: null,
	quickViewHandler: null,
	productMiniReloadURL: null,
	predecessor: null,
	successor: null,
	masterProductID: null,
	productID: null,
	isProductSet: null,
	categoryID: null,
	imagesForSwatches: new Object(),
	originalImage: null,
	_imageContainerCache: $H(),

	/* Ctor */
	initialize: function(qvHandler, element, predecessor) {
		if (element) {
			this.element = element;
			this.quickViewHandler = qvHandler;
			if (predecessor) {
				predecessor.successor = this;
				this.predecessor = predecessor;
			}

			var masterProductID = this.element.select('input.masterProductID');
			if (masterProductID.length > 0 && masterProductID[0].value != null) {
				this.masterProductID = masterProductID[0].value;
			}

			var productID = this.element.select('input.productID');
			if (productID.length > 0 && productID[0].value != null) {
				this.productID = productID[0].value;
			}

			var categoryID = this.element.select('input.categoryID');
			if (categoryID.length > 0 && categoryID[0].value != null) {
				this.categoryID = categoryID[0].value;
			}
			
			var isProductSet = this.element.select('input.isProductSet');
			if (isProductSet.length > 0 && isProductSet[0].value != null) {
				if(isProductSet[0].value == 'true'){
					this.isProductSet = true;
				}
				else{
					this.isProductSet = false;
				}
			}

			var quickViewURL = this.element.select('input.quickviewURL');
			if (quickViewURL.length > 0 && quickViewURL[0].value != null) {
				this.quickViewURL = quickViewURL[0].value;
			}
			if (this.quickViewURL) {
				this.element.select('.quickviewBtn').each(function(el) {
					el.addClassName('active');
					el.onclick = this.quickViewLinkClick.bind(this);
				}.bind(this));
			}

			var productMiniReloadURL = this.element.select('input.productMiniReloadURL');
			if (productMiniReloadURL.length > 0 && productMiniReloadURL[0].value != null) {
				this.productMiniReloadURL = productMiniReloadURL[0].value;
			}

			var altImageURL = this.element.select('input.altimageURL');
			if (altImageURL.length > 0 && altImageURL[0].value != null) {
				this.altImageURL = altImageURL[0].value;
			}
		}
	},

	/* set product badges */
	setProductBadges: function(badges) {
		var badgeElements = this.element.select('span.productBadges');
		if (badgeElements.length > 0) {
			badgeElements[0].update(badges);
		}
	},

	/* event handler for a quick view button click */
	quickViewLinkClick: function() {
		document.fire('tracking:onQuickviewClick');
		this.quickViewHandler.loadQuickView(this);
		return false;
	},

	/* set alternative images */
	setAltImage: function() {
		if (this.altImageURL) {
			this.element.select('.imageContainer').each(function(el) {
				el.productMini = this;
				el.observe('mouseover', this.altImageMouseOverHandler.bindAsEventListener(el) );
				el.observe('mouseout', this.altImageMouseOutHandler.bindAsEventListener(el) );
			}.bind(this));
		}
	},

	/* event handlers for alternative hover image mouse over and out */
	altImageMouseOverHandler: function(ev) {

		var prodImg = ev.findElement('.prodImg');
		var altImg = this.productMini.altImageURL;
		if(prodImg != null && altImg != null && prodImg.src != altImg){
			this.originalImage = prodImg.src;
			prodImg.src = altImg;
		}

	},
	altImageMouseOutHandler: function(ev) {
		var prodImg = ev.findElement('.prodImg');
		if(prodImg != null && this.originalImage != null && prodImg.src != this.originalImage){
			prodImg.src = this.originalImage;
		}
	},

	/* reload image for product minis using an AJAX request */
	reloadImageContainer: function(ev, variantID, element) {

		var selected = element.hasClassName('active');
		if(!selected){
			// set active class and add event handler
			var colorSelector = ev.findElement('div.colorSelector');
			var aList = colorSelector.select('li');
			aList.each(function(el) {
				if(el.hasClassName('active')){
					el.removeClassName('active');
				}
			});
			element.addClassName('active');
			var queryParams = $H();
			var imageContainer = ev.findElement('.imageContainer');
			queryParams.set('pid', variantID);

			var queryParamsString = queryParams.toQueryString();
			var cachedResponseText = this.productMini._imageContainerCache.get(queryParamsString);
			if (cachedResponseText) {
				this.productMini.imageContainerLoaded(ev, cachedResponseText, element);
			} else {
				new Ajax.Request(this.productMini.productMiniReloadURL, {
					method: 'GET',
					parameters: queryParams,
					onSuccess: function(transport) {
						this.productMini.imageContainerLoaded(ev, transport.responseText, element);

						this.productMini._imageContainerCache.set(queryParamsString, transport.responseText);
					}.bind(this),
					onFailure: AjaxErrorHandler
				});
			}
		}
	},

	/* handle successful Image Container loading response */
	imageContainerLoaded: function(ev, responseText, element) {

		var content = responseText;
		var ancestor = ev.findElement('.colorSelector');
		if(ancestor != null){
			var imageContainer = ancestor.previous('.imageContainer');
		}
		new Effect.Opacity(imageContainer, { from: 1.0, to: 0, duration: 0.1 });
		setTimeout(function() {
			imageContainer.update(content);
		  }, 100);
		setTimeout(function() {
			new Effect.Opacity(imageContainer, { from: 0, to: 1, duration: 0.1 });
			initQuickView(element.productMini.isProductSet);
		  }, 300);


	}
});

/* Handler for detail view images switching */
var DetailViewHandler = Class.create({

	images: null,

	/* Ctor */
	initialize: function(element) {
		if (element) {
			this.images = [];
			var cnt = 0;
			$$('#detailBtns li').each(function(el, i) {
				var links = el.select('a');
				if (links && links.length > 0) {
					var link = links[0];
					if (link.href && link.href.indexOf('#') != -1) {
						var img = $(link.href.substring(link.href.indexOf('#') + 1));
						if (img) {
							var data = {li: el, 'img': img};
							this.images.push(data);
							++cnt;
							link.detailViewCnt = cnt;
							link.detailViewHandler = this;
							link.onclick = this.clickHandler;
						}
					}
				}
			}.bind(this));
			this.setImage(1);
		}
	},

	/* Show image */
	setImage: function(imgNo) {
		this.images.each(function(obj, i) {
			if (i + 1 == imgNo) {
				obj.img.show();
				obj.li.addClassName('active');
			} else {
				obj.img.hide();
				obj.li.removeClassName('active');
			}
		});
	},

	/* Handle click */
	clickHandler: function(el) {
		this.detailViewHandler.setImage(this.detailViewCnt);
		return false;
	}
});

/* This class represents a product set */
var SetProduct = Class.create({

	element: null,
	productSetID: null,
	productID: null,
	quickViewURL: null,
	quickViewHandler: null,

	/* Ctor */
	initialize: function(qvHandler,element) {
		if (element) {
			this.element = element;
			this.quickViewHandler = qvHandler;
			var productSetID = this.element.select('input.productSetID');
			if (productSetID.length > 0 && productSetID[0].value != null) {
				this.productSetID = productSetID[0].value;
			}
			
			var productID = this.element.select('input.productID');
			if (productID.length > 0 && productID[0].value != null) {
				this.productID = productID[0].value;
			}
			
			var quickViewURL = this.element.select('input.quickviewURL');
			if (quickViewURL.length > 0 && quickViewURL[0].value != null) {
				this.quickViewURL = quickViewURL[0].value;
			}
			
			if (this.quickViewURL) {
				this.element.select('.quickviewBtn').each(function(el) {
					el.onclick = this.quickViewLinkClick.bind(this);
				}.bind(this));
				this.element.select('li').each(function(el) {
					el.addClassName('pointer');
					el.onclick = this.quickViewLinkClick.bind(this);
				}.bind(this));
			}
		}
	},

	/* event handler for a quick view button click */
	quickViewLinkClick: function() {
		document.fire('tracking:onQuickviewClick');
		this.quickViewHandler.loadQuickView(this);
		return false;
	}
	
});
function initQuickView(issetproduct) {
	quickView = new QuickViewHandler(issetproduct);
}

document.observe('dom:loaded', function() {
	initQuickView(false);
	quickView.productMinis.each(function(productMini) {
		var colorSelector = productMini.element.select('div.colorSelector');
		if (colorSelector.length > 0) {
			var aList = colorSelector[0].select('li');
			aList.each(function(el) {
				// add mouseoverhandler
				var variantIDs = el.select('input.variantID');

				if (variantIDs.length > 0) {
					var variantID = variantIDs[0].value;
					el.observe('mouseover', productMini.reloadImageContainer.bindAsEventListener(el, variantID, el) );
					el.productMini = productMini;
				}

			}.bind(productMini));
			productMini.swatches = aList;
		}
	});
	// issetproduct for product set detail page
	initQuickView(true);
});

