
var products = {};

products.add = function(prodInfo)
{
	products[prodInfo.id] = new Product(prodInfo);
}

var colorSizeSelectManager = new ColorSizeSelectManager();

function Product(prodInfo)
{
	var inst = this;
	function _construct(prodInfo)
	{
		inst.id = prodInfo.id;
		setColorData(prodInfo.colors);
		reorganizeData();
	}
	function setColorData(colorData)
	{
		inst.colors = {};
		var i = 0;
		$.each(colorData, function(key, val){
			val.productId = inst.id;
			inst.colors[key] = new ColorProduct(val);
			inst.colors[i++] = inst.colors[key];
		});
		inst.numColors = i;
	}
	function reorganizeData()
	{
		// also set data on lowest level possible (i.e. requiredDimensions can be a container & color product level, etc.)
		// TODO have a similar function on other classes as well so that this happens when Product isn't used
		
		inst.requiredDimensions = inst.colors[0].requiredDimensions;
		inst.sizeLabel1 = inst.colors[0].sizeLabel1;
		inst.sizeLabel2 = inst.colors[0].sizeLabel2;
	}
	_construct(prodInfo);
}

function ColorProduct(colorData)
{
	var inst = this;
	function _construct(colorData)
	{
		inst.id = colorData.id;
		inst.productId = colorData.productId;
		inst.name = colorData.name;
		inst.imageStatus = colorData.imageStatus;
		inst.hasView = colorData.hasView;
		setSkuData(colorData.skus, colorData.availableSkus);
		reorganizeData();
	}
	function setSkuData(possibleSkus, availableSkus)
	{
		inst.skus = {};
		var i = 0;
		$.each(possibleSkus, function(key, val){
			var available = ($.inArray(val.id, availableSkus) < 0) ? false : true;
			val.productId = inst.productId;
			val.colorProductId = inst.id;
			inst.skus[key] = new Sku(val, available);
			inst.skus[i++] = inst.skus[key];
		});
		inst.numSkus = i;
	}
	function reorganizeData()
	{
		inst.requiredDimensions = 1; // may be changed below
		var mayRequireSizePart2Fix = false;
		
		inst.totalNumericPart1 = 0;
		inst.totalNumericPart2 = 0;
		for(var i=0; i<inst.numSkus; i++){
			if(inst.skus[i].numericPart1) inst.totalNumericPart1++;
			if(inst.skus[i].numericPart2) inst.totalNumericPart2++;
			
			if(inst.skus[i].requiredDimensions === 2) inst.requiredDimensions = 2;
			else mayRequireSizePart2Fix = true;
		}
		inst.numericPart1 = inst.totalNumericPart1 == inst.numSkus ? true : false;
		inst.numericPart2 = inst.totalNumericPart2 == inst.numSkus ? true : false;
		
		// This is a fix for if some skus have both size dimensions and others only have one for the same product. In this case the ones with the empty 2nd size dimension should be changed to "Regular" as this indicates a regular length
		if(inst.requiredDimensions > 1 && mayRequireSizePart2Fix)
		{
			$.each(inst.skus, function (key, val){
				val.size.requiredDimensions = inst.requiredDimensions;
				val.requiredDimensions = inst.requiredDimensions;
				if(val.size.namePart2 == '') val.size.namePart2 = 'Regular';
				if(val.size.sizeLabel2 == '') val.size.sizeLabel2 = 'Length';
				if(val.sizeLabel2 == '') val.sizeLabel2 = val.size.sizeLabel2;
			});
		}
		
		inst.sizeLabel1 = inst.skus[0].sizeLabel1;
		inst.sizeLabel2 = inst.skus[0].sizeLabel2;
	}
	_construct(colorData);
}

function Sku(skuData, available)
{
	if(typeof available == 'undefined') available = false; // default value
	
	var inst = this;
	function _construct(skuData)
	{
		inst.id = skuData.id;
		inst.productId = skuData.productId;
		inst.colorProductId = skuData.colorProductId;
		inst.available = available;
		inst.listPrice = skuData.listPrice;
		inst.salePrice = skuData.salePrice;
		inst.webOnly = skuData.webOnly;
		
		skuData.size.productId = inst.productId;
		skuData.size.colorProductId = inst.colorProductId;
		inst.size = new Size(skuData.size);
		reorganizeData();
	}
	function reorganizeData()
	{
		inst.requiredDimensions = inst.size.requiredDimensions;
		inst.sizeLabel1 = inst.size.sizeLabel1;
		inst.sizeLabel2 = inst.size.sizeLabel2;
		inst.numericPart1 = inst.size.numericPart1;
		inst.numericPart2 = inst.size.numericPart2;
	}
	_construct(skuData);
}

function Size(sizeData)
{
	var inst = this;
	function _construct(sizeData)
	{
		inst.id = sizeData.id;
		inst.productId = sizeData.productId;
		inst.colorProductId = sizeData.colorProductId;
		inst.name = sizeData.name;
		inst.namePart1 = sizeData.namePart1;
		inst.namePart2 = sizeData.namePart2;
		inst.numericPart1 = !isNaN(sizeData.namePart1) ? true : false;
		inst.numericPart2 = !isNaN(sizeData.namePart2) ? true : false;
		inst.sizeLabel1 = sizeData.label1;
		inst.sizeLabel2 = sizeData.label2;
		determineRequiredDimensions();
		reorganizeData();
	}
	function determineRequiredDimensions()
	{
		inst.requiredDimensions = (inst.namePart2 == '' || typeof inst.namePart2 == 'undefined') ? 1 : 2;
	}
	function reorganizeData()
	{
		
	}
	_construct(sizeData);
}

function ColorSizeSelectManager(userOpts)
{
	function defaultOpts()
	{
		
	}
	
	var opts = new defaultOpts();
	var inst = this;
	inst.instances = [];
	inst.nextKey = 0;
	
	function setConfig(userOpts)
	{
		if (!!userOpts) {
            $.each(opts, function( key ){
                if (typeof userOpts[key] != 'undefined') {
                    opts[key] = configOpts[key];
                }
            });
        }
	}
	
	inst.get = function(key)
	{
		return inst.instances[key];
	}
	inst.create = function(createOpts)
	{
		if(typeof createOpts == 'undefined') createOpts = {};
		createOpts.key = inst.nextKey;
		inst.instances[inst.nextKey] = new ColorSizeSelect(createOpts);
		return inst.instances[inst.nextKey++];
	}
	inst.destroy = function(key)
	{
		if(!!inst.instances[key])
			delete inst.instances[key];
	}
	
	inst.init = function(initOpts)
	{
		setConfig(initOpts);
	}
	inst.init(userOpts);
}

function SizePart(data)
{
	var inst = this;
	
	inst.init = function(data)
	{
		inst.id = data.id;
		inst.name = data.name;
		inst.sizeDimension = data.sizeDimension;
		inst.available = false;
		inst.selected = false;
		inst.hover = false;
		inst.numeric = !isNaN(inst.name); // TODO calculate this across each size dimension so that mixes don't have different widths in the same size dimension (like "6" and "6 1/2")
		inst.skus = [];
	}
	inst.addSku = function(sku)
	{
		inst.skus.push(sku);
	}
	inst.init(data);
}

function ColorSizeSelect(userOpts)
{
	function defaultOpts()
	{
		this.prodId = null;
		this.key = null;
		this.container = 'body';
		this.colorsContainer = 'div.swatchesContainer';
		this.colorContainer = 'div.color_swatch_container';
		this.colorElement = 'a.color';
		this.initalColor = '#OMColorString';
		this.initialSize = '#initialSize';
		this.setValueOnColorSelect = 'input#OMColorString, input#color';
		this.skuInput = 'select#size';
		this.findItSkuInput = 'input#findItSize';
		this.sizesContainer = 'div.sizesContainer';
		this.sizeContainers = 'sizeContainer';
		this.sizeContainerID1 = 'sizeContainer1';
		this.sizeContainerID2 = 'sizeContainer2';
		this.sizeLabels = 'sizeLabel';
		this.sizeNameLabel = 'size_name';
		this.sizeLabelID1 = 'sizeLabel1';
		this.sizeLabelID2 = 'sizeLabel2';
		this.availableClass = 'available';
		this.unavailableClass = 'unavailable';
		this.unavailableSelectedClass = 'unavailable-selected';
		this.availableClass = 'available';
		this.availableSelectedClass = 'available-selected';
		this.availabilityWrapper = 'div.availabilityWrapper';
		this.inventoryMessage = 'span#inventoryMessage';
		this.inventoryMsgInStock = 'In stock';
		this.inventoryMsgNotInStock = 'Out of stock';
		this.inventoryMsgNoSelection = 'Select a size';
		this.inventoryMsgNoSku = this.inventoryMsgNotInStock;
		this.tooltipMsgInStock = 'In stock.';
		this.tooltipMsgNotInStock = 'Selection is not in stock.';
		this.tooltipMsgNoSelection = 'Please choose a size.';
		this.tooltipMsgNoSku = this.tooltipMsgNotInStock;
		this.inventoryMsgWebExclusive = 'Web exclusive';
		this.addToBagButton = 'div#addToBagWrapper input.IRButton';
		this.wishListButton = 'div#wishlist_add input.IRButton';
		this.addToBagToolTipMsg = 'div#addToBagToolTipMsg';
		this.wishListToolTipMsg = 'div#wishListToolTipMsg';
		this.addToBagToolTipBg = 'div#addToBagToolTipBg';
		this.wishListToolTipBg = 'div#wishListToolTipBg';
		this.quickView = false;
	}
	
	var inst = this;
	inst.opts = new defaultOpts();
	inst.product = null;
	inst.el = {};
	inst.selectedColor = null;
	inst.hoverColor = null;
	inst.selectedSize1 = null;
	inst.selectedSize2 = null;
	inst.hoverSize1 = null;
	inst.hoverSize2 = null;
	inst.initialColorElement = null;
	inst.skuLookup = {};
	inst.bagEnabled = false;
	
	function setConfig(userOpts)
	{
		if (!!userOpts) {
            $.each(inst.opts, function( key ){
                if (typeof userOpts[key] != 'undefined') {
                    inst.opts[key] = userOpts[key];
                }
            });
        }
	}
	function initColors()
	{
		inst.el.colorsContainer = inst.el.container.find(inst.opts.colorsContainer);
		inst.el.colors = inst.el.colorsContainer.find(inst.opts.colorContainer+' '+inst.opts.colorElement);
		inst.el.setValueOnColorSelect = inst.el.container.find(inst.opts.setValueOnColorSelect);
		var initialColor = inst.el.container.find(inst.opts.initalColor).val();
		inst.el.colors.each(function(i){
			var qs = parseQueryString($(this).attr('href'));
			this.prodId = qs.productId;
			this.colorProdId = qs.showId;
			inst.opts.prodId = this.prodId;
			this.availableState = true;
			var el = $(this);
			if(this.colorProdId == initialColor) inst.initialColorElement = el; // select this as the initial color if it matches
			if(!inst.product){ // set the product now if it hasn't been done already
				inst.setProduct(inst.opts.prodId);
			}
			el.bind('click', selectColor);
			el.bind('mouseover', mouseOverColor);
			el.bind('mouseout', mouseOutColor);

			inst.skuLookup[this.colorProdId] = {}
		});
		inst.el.colorNameLabel = inst.el.container.find('#color_name_'+inst.product.id); // TODO move this to an option
	}
	function selectColor(eventOrElement, hoverOnly)
	{
		if(typeof hoverOnly == 'undefined') hoverOnly = false;
		
		// set the element reference
		if(hoverOnly)
			var el = eventOrElement;
		else
		{
			eventOrElement.preventDefault();
			var el = $(this);
		}
		
		var prodId = el.get(0).prodId;
		var colorProdId = el.get(0).colorProdId;
		
		if(inst.selectedColor == colorProdId) return; // don't select again if already selected
		
		if(hoverOnly)
		{
			inst.hoverColor = colorProdId;
			selectButton(el);
		}
		else
		{
			inst.el.setValueOnColorSelect.val(colorProdId);
			inst.selectedColor = colorProdId;
			selectButton(el, inst.el.colors);
			checkForSkuSelection();
			inst.imageView.swapColor(inst.selectedColor);
		}
		
		setColorNameLabel(inst.product.colors[colorProdId].name);
		showButtonStates('color');
		// TODO swap image (and change image thumbs)
	}
	function setColorNameLabel(value)
	{
		inst.el.colorNameLabel.text(value);
	}
	function mouseOverColor(event)
	{
		var el = $(this);	
		if(inst.selectedColor != this.colorProdId) selectColor(el, true); // no need to do the hover work if that color is already selected
	}
	function mouseOutColor(event)
	{
		var el = $(this);
		inst.hoverColor = null;
		if(inst.selectedColor != this.colorProdId){ // only deselect the button if it's not the selected color
			showButtonStates('color');
			deselectButton(el);
			if(inst.selectedColor != null) setColorNameLabel(inst.product.colors[inst.selectedColor].name);
			else setColorNameLabel('');
		}
	}
	function selectButton(element, elementGroup)
	{
		if(typeof elementGroup != 'undefined'){
			elementGroup.each(function(){
				deselectButton($(this));
			});
		}
		if(element.get(0).availableState){
			element.addClass(inst.opts.availableSelectedClass);
			element.removeClass(inst.opts.availableClass);
		}else{
			element.addClass(inst.opts.unavailableSelectedClass);
			element.removeClass(inst.opts.unavailableClass);
		}
		element.get(0).selectedState = true;
	}
	function deselectButton(element)
	{
		if(element.get(0).availableState){
			element.removeClass(inst.opts.availableSelectedClass);
			element.addClass(inst.opts.availableClass);
		}else{
			element.removeClass(inst.opts.unavailableSelectedClass);
			element.addClass(inst.opts.unavailableClass);
		}
		element.get(0).selectedState = false;
	}
	function writeSizes()
	{
		inst.el.sizesContainer = inst.el.container.find(inst.opts.sizesContainer);
		for(var i=1; i<=inst.product.requiredDimensions; i++){
			inst.el['sizeLabel'+i] = inst.el.sizesContainer.find('#'+inst.opts['sizeLabelID'+i]);
			if(inst.el['sizeLabel'+i].length <= 0){ // doesn't already exist to create it
				inst.el['sizeLabel'+i] = $('<div class="'+inst.opts.sizeLabels+'" id="'+inst.opts['sizeLabelID'+i]+'"></div>').appendTo(inst.el.sizesContainer);
				inst.el['sizeLabel'+i].append('<h4 class="description_title">Size:</h4>');
			}
			inst.el['sizeLabel'+i].find('.description_title').text(inst.product['sizeLabel'+i]+':');
			inst.el['sizeNameLabel'+i] = inst.el['sizeLabel'+i].find('.'+inst.opts.sizeNameLabel);
			if(inst.el['sizeNameLabel'+i].length <= 0){ // doesn't already exist to create it
				inst.el['sizeNameLabel'+i] = $('<span class="'+inst.opts.sizeNameLabel+'">&nbsp;</span>').appendTo(inst.el['sizeLabel'+i]);
			}
			inst.el['sizeContainer'+i] = inst.el.sizesContainer.find('#'+inst.opts['sizeContainerID'+i]);
			if(inst.el['sizeContainer'+i].length <= 0){ // doesn't already exist to create it
				inst.el['sizeContainer'+i] = $('<div class="'+inst.opts.sizeContainers+'" id="'+inst.opts['sizeContainerID'+i]+'"></div>').appendTo(inst.el.sizesContainer);
			}
			inst['sizeParts'+i] = [];
			inst.el['sizeButtons'+i] = [];
		}
		inst.sizeParts = {};
		inst.numericPart1 = '';
		inst.numericPart2 = '';
		var initialSize = [false, false, false];
		for(var k=0; k<inst.product.numColors; k++){ // for each won't work because of string and numeric indexes - would be double
			inst.product.colors[k].availability = {};
			var avail = inst.product.colors[k].availability;
			inst.numericPart1 = inst.product.colors[k].numericPart1 ? ' numeric' : '';
			inst.numericPart2 = inst.product.colors[k].numericPart2 ? ' numeric' : '';
			var skuLookup = inst.skuLookup[inst.product.colors[k].id] = {};
			
			for(var i=0; i<inst.product.colors[k].numSkus; i++){
				var sku = inst.product.colors[k].skus[i];
				var size = sku.size;
				
				if(typeof skuLookup['1:'+sku.size.namePart1] == 'undefined') skuLookup['1:'+sku.size.namePart1] = {};
				if(size.requiredDimensions == 1){
					skuLookup['1:'+sku.size.namePart1].sku = sku.id;
					skuLookup['1:'+sku.size.namePart1].available = sku.available;
					skuLookup['1:'+sku.size.namePart1].webOnly = sku.webOnly;
					if(size.id === inst.initialSize) initialSize[1] = '1:'+sku.size.namePart1;
				}else if(size.requiredDimensions == 2){
					skuLookup['1:'+sku.size.namePart1]['2:'+sku.size.namePart2] = {};
					skuLookup['1:'+sku.size.namePart1]['2:'+sku.size.namePart2].sku = sku.id;
					skuLookup['1:'+sku.size.namePart1]['2:'+sku.size.namePart2].available = sku.available;
					skuLookup['1:'+sku.size.namePart1]['2:'+sku.size.namePart2].webOnly = sku.webOnly;
					if(size.id === inst.initialSize)
					{
						initialSize[1] = '1:'+sku.size.namePart1;
						initialSize[2] = '2:'+sku.size.namePart2;
					}
				}
				
				if(sku.available){
					if(typeof avail['1:'+size.namePart1] == 'undefined') avail['1:'+size.namePart1] = {};
					avail['1:'+size.namePart1]['2:'+size.namePart2] = true;
					if(typeof avail['2:'+size.namePart2] == 'undefined') avail['2:'+size.namePart2] = {};
					avail['2:'+size.namePart2]['1:'+size.namePart1] = true;
				}
				for(var j=1; j<=inst.product.requiredDimensions; j++){
					if(typeof inst.sizeParts[j+':'+size['namePart'+j]] == 'undefined'){
						var data = {};
						data.name = size['namePart'+j];
						data.id = j+':'+data.name;
						data.sizeDimension = j;
						inst.sizeParts[j+':'+size['namePart'+j]] = new SizePart(data);
						inst['sizeParts'+j].push(j+':'+size['namePart'+j]);
					}
					inst.sizeParts[j+':'+size['namePart'+j]].addSku(sku);
				}
			}
		}
		inst.initialSizeButtons = [];
		for(var i=1; i<=inst.product.requiredDimensions; i++){
			var sizeParts = inst['sizeParts'+i];
			$.each(sizeParts, function(key, val){
				var btn = $('<a href="javascript:;" class="size available'+inst['numericPart'+i]+'">'+inst.sizeParts[val].name+'</a>').appendTo(inst.el['sizeContainer'+i]);
				btn.get(0).sizePart = inst.sizeParts[val].id;
				btn.get(0).availableState = true;
				btn.get(0).selectedState = false;
				btn.bind('click', selectSize);
				btn.bind('mouseover', mouseOverSizeButton);
				btn.bind('mouseout', mouseOutSizeButton);
				if(initialSize[i] === inst.sizeParts[val].id) inst.initialSizeButtons.push(btn);
			});
		}
		for(var i=1; i<=inst.product.requiredDimensions; i++){
			inst.el['sizeButtons'+i] = $(inst.el['sizeContainer'+i]).find('a.size');
		}
	}
	function selectSize(eventOrElement, hoverOnly)
	{
		if(typeof hoverOnly == 'undefined') hoverOnly = false;
		
		// set the element reference
		if(hoverOnly)
			var el = eventOrElement;
		else
		{
			eventOrElement.preventDefault();
			var el = $(this);
		}
		
		var sizePart = inst.sizeParts[el.get(0).sizePart];

		if(inst['selectedSize'+sizePart.sizeDimension] == sizePart.id) return; // don't select again if already selected
		
		if(hoverOnly)
		{
			inst['hoverSize'+sizePart.sizeDimension] = sizePart.id;
			selectButton(el);
		}
		else
		{
			inst['selectedSize'+sizePart.sizeDimension] = sizePart.id;
			selectButton(el, inst.el['sizeButtons'+sizePart.sizeDimension]);
			checkForSkuSelection();
		}
		
		setSizeNameLabel(sizePart.sizeDimension, sizePart.name);
		showButtonStates('size'+sizePart.sizeDimension);
	}
	function setSizeNameLabel(dimension, value)
	{
		inst.el['sizeNameLabel'+dimension].text(value);
	}
	function mouseOverSizeButton(event)
	{
		var el = $(this);
		var sizePart = inst.sizeParts[el.get(0).sizePart];
		if(inst['selectedSize'+sizePart.sizeDimension] != sizePart.id) selectSize(el, true); // no need to do the hover work if that color is already selected
	}
	function mouseOutSizeButton(event)
	{
		var el = $(this);
		var sizePart = inst.sizeParts[this.sizePart];
		inst['hoverSize'+sizePart.sizeDimension] = null;
		if(inst['selectedSize'+sizePart.sizeDimension] != sizePart.id){ // only deselect the button if it's not the selected color
			showButtonStates('size'+sizePart.sizeDimension);
			deselectButton(el);
			if(inst['selectedSize'+sizePart.sizeDimension] != null) setSizeNameLabel(sizePart.sizeDimension, inst.sizeParts[inst['selectedSize'+sizePart.sizeDimension]].name);
			else setSizeNameLabel(sizePart.sizeDimension, '');
		}
	}
	
	function showButtonStates(actionGroup)
	{
log('actionGroup:'+actionGroup);
		var useColor = (inst.hoverColor != null) ? inst.hoverColor : inst.selectedColor;
log('useColor:'+useColor);
		var useSize = [];
		for(var i=1; i<=inst.product.requiredDimensions; i++){
			useSize[i] = (inst['hoverSize'+i] != null) ? inst['hoverSize'+i] : inst['selectedSize'+i];
log('useSize['+i+']:'+useSize[i]);
		}
		
		if(actionGroup != 'color')
		{
			inst.el.colors.each(function(key, btn){
				log('calling isAvailable for btn: '+btn.colorProdId);
				var avail = isAvailable(btn.colorProdId, useSize[1], useSize[2]);
				if(btn.availableState != avail) setButtonAvailabilityState(btn, avail);
			});
		}
		if(actionGroup != 'size1')
		{
			inst.el.sizeButtons1.each(function(key, btn){
				log('calling isAvailable for btn: '+btn.sizePart);
				var avail = isAvailable(useColor, btn.sizePart, useSize[2]);
				if(btn.availableState != avail) setButtonAvailabilityState(btn, avail);
			});
		}
		if(inst.product.requiredDimensions > 1 && actionGroup != 'size2')
		{
			inst.el.sizeButtons2.each(function(key, btn){
				log('calling isAvailable for btn: '+btn.sizePart);
				var avail = isAvailable(useColor, useSize[1], btn.sizePart);
				if(btn.availableState != avail) setButtonAvailabilityState(btn, avail);
			});
		}
		log('===============');
		
		var checkWebExclusive = true;
		if(useColor == null) checkWebExclusive = false;
		for(var i=1; i<=inst.product.requiredDimensions; i++){
			if(useSize[i] == null) checkWebExclusive = false;
		}
		var sku = null;
		var msg = '';
		var ttMsg = '';
		if(checkWebExclusive){
			sku = lookupSku(useColor, useSize[1], useSize[2]);
			if(sku != null){
				if(sku.available){
					msg = inst.opts.inventoryMsgInStock;
					ttMsg = inst.opts.tooltipMsgInStock;
					inst.bagEnabled = true;
					enableCheckOut = true;
				}else{
					msg = inst.opts.inventoryMsgNotInStock;
					ttMsg = inst.opts.tooltipMsgNotInStock;
					inst.bagEnabled = false;
					enableCheckOut = true;
				}
				if(sku.webOnly) setInventoryMessage(msg+' '+inst.opts.inventoryMsgWebExclusive);
				else setInventoryMessage(msg+' '+getLocateInStoreLink());
				setTooltipMessage(ttMsg);
			}else{
				setInventoryMessage(inst.opts.inventoryMsgNoSku+' '+getLocateInStoreLink());
				setTooltipMessage(inst.opts.tooltipMsgNoSku);
				inst.bagEnabled = false;
				enableCheckOut = false;
			}
		}else{
			setInventoryMessage(inst.opts.inventoryMsgNoSelection+' '+getLocateInStoreLink());
			setTooltipMessage(inst.opts.tooltipMsgNoSelection);
			inst.bagEnabled = false;
			enableCheckOut = false;
		}
		updateAddToBagButtonState();
	}
	
	function checkForSkuSelection()
	{
		var fullSelection = true;
		if(inst.selectedColor == null) fullSelection = false;
		for(var i=1; i<=inst.product.requiredDimensions; i++){
			if(inst['selectedSize'+i] == null) fullSelection = false;
		}
		if(fullSelection) selectSku();
	}
	
	function lookupSku(useColor, useSize1, useSize2)
	{
		var sku = null;
		skuLookup = inst.skuLookup[useColor];
		if(!isEmpty(skuLookup)){
			if(inst.product.requiredDimensions == 1){
				sku = skuLookup[useSize1];
			}else if(inst.product.requiredDimensions == 2){
				if(!isEmpty(skuLookup[useSize1]))
					sku = skuLookup[useSize1][useSize2];
			}
		}
		return sku;
	}
	
	function selectSku()
	{
		var sku = lookupSku(inst.selectedColor, inst.selectedSize1, inst.selectedSize2)
		if(typeof sku != 'undefined'){
			if(sku.available){
				inst.el.skuInput.val(sku.sku);
			}
			else{
				inst.el.skuInput.val('');
			}
			inst.el.findItSkuInput.val(sku.sku);
		}else{
			inst.el.skuInput.val('');
			inst.el.findItSkuInput.val('');
		}
	}
	
	function updateAddToBagButtonState()
	{
		if(inst.bagEnabled) inst.el.addToBagButton.removeClass('disabled');
		else inst.el.addToBagButton.addClass('disabled');
	}
	
	function isAvailable(checkColor, checkSize1, checkSize2)
	{
		var avail = false;
		var availMap = inst.product.colors[checkColor].availability;
		log('isAvailable('+checkColor+', ['+checkSize1+','+checkSize2+'])');
		if(!isEmpty(availMap)){
			if(checkSize1 != null && checkSize2 != null){ if(!isEmpty(availMap[checkSize1])) log('1:'+availMap[checkSize1][checkSize2]); else log('1:empty');
				if(!isEmpty(availMap[checkSize1]) && availMap[checkSize1][checkSize2] === true){ avail = true; log('y'); }
			}else if(checkSize1 != null){ log('2:'+availMap[checkSize1]);
				if(!isEmpty(availMap[checkSize1])){ avail = true; log('y'); }
			}else if(checkSize2 != null){ log('3:'+availMap[checkSize2]);
				if(!isEmpty(availMap[checkSize2])){ avail = true; log('y'); }
			}else{ log('4:y');
				avail = true;
			}
		}else log('availMap is empty');
		log('verdict:'+avail);
		log('');
		return avail;
	}
	function setButtonAvailabilityState(el, available)
	{
		log('setting available state of '+el+' to '+available);
		if(available){
			if(el.selectedState){
				$(el).removeClass(inst.opts.unavailableSelectedClass);
				$(el).addClass(inst.opts.availableSelectedClass);
			}else{
				$(el).removeClass(inst.opts.unavailableClass);
				$(el).addClass(inst.opts.availableClass);
			}
		}
		else{
			if(el.selectedState){
				$(el).addClass(inst.opts.unavailableSelectedClass);
				$(el).removeClass(inst.opts.availableSelectedClass);
			}else{
				$(el).addClass(inst.opts.unavailableClass);
				$(el).removeClass(inst.opts.availableClass);
			}
		}
		el.availableState = available;
	}
	
	function replaceSkuInput(){
		var el = inst.el.container.find(inst.opts.skuInput);
		var elId = el.attr('id');
		el.replaceWith('<input type="hidden" id="'+elId+'" name="'+elId+'" />');
		inst.el.skuInput = inst.el.container.find('input#'+elId);
		inst.el.findItSkuInput = inst.el.container.find(inst.opts.findItSkuInput);
		log(inst.el.skuInput);
	}
	
	// TODO these update DOM each time, not just when msg changes
	function setInventoryMessage(msg)
	{
		inst.el.inventoryMessage.html(msg);
	}
	function setTooltipMessage(msg)
	{
		inst.el.addToBagToolTipMsg.html(msg);
		inst.el.wishListToolTipMsg.html(msg);
	}
	function getLocateInStoreLink()
	{
		// TODO this link is different for the bundle page
		if(jsContextRoot != '77kids') return '&nbsp; <a href="javascript:LaunchFindIt()" onMouseOver="window.status=\'\';return true;" style="text-decoration:underline;">Locate in Store</a>';
		else return '';
	}
	function showAddToBagToolTip()
	{
		if(inst.bagEnabled) return;
		inst.el.addToBagToolTipMsg.show();
		inst.el.addToBagToolTipBg.show();
	}
	function hideAddToBagToolTip()
	{
		inst.el.addToBagToolTipMsg.hide();
		inst.el.addToBagToolTipBg.hide();
	}
	function showWishListToolTip()
	{
		if(inst.bagEnabled) return;
		inst.el.wishListToolTipMsg.show();
		inst.el.wishListToolTipBg.show();
	}
	function hideWishListToolTip()
	{
		inst.el.wishListToolTipMsg.hide();
		inst.el.wishListToolTipBg.hide();
	}
	
	inst.setProduct = function(prodId)
	{
		inst.product = products[prodId];
		inst.imageView = new ImageView({prodId:inst.opts.prodId, quickView:inst.opts.quickView});
	}
	inst.getProduct = function()
	{
		return inst.product;
	}
	inst.getManagerKey = function()
	{
		return inst.opts.key;
	}
	inst.init = function(initOpts)
	{
		setConfig(initOpts);
		if(!!inst.opts.prodId) inst.setProduct(inst.opts.prodId); // set the product now if the prodId was passed in
		inst.el.container = $(inst.opts.container);
		replaceSkuInput();
		initColors();
		inst.initialSize = inst.el.container.find(inst.opts.initialSize).val();
		if(typeof inst.initialSize == 'undefined' || inst.initialSize == '') inst.initialSize = false;
		writeSizes();
		
		inst.el.addToBagButton = inst.el.container.find(inst.opts.addToBagButton);
		inst.el.wishListButton = inst.el.container.find(inst.opts.wishListButton);
		updateAddToBagButtonState();
		inst.el.addToBagToolTipMsg = inst.el.container.find(inst.opts.addToBagToolTipMsg);
		inst.el.wishListToolTipMsg = inst.el.container.find(inst.opts.wishListToolTipMsg);
		inst.el.addToBagToolTipBg = inst.el.container.find(inst.opts.addToBagToolTipBg);
		inst.el.wishListToolTipBg = inst.el.container.find(inst.opts.wishListToolTipBg);
		
		inst.el.availabilityWrapper = inst.el.container.find(inst.opts.availabilityWrapper);
		inst.el.availabilityWrapper.show();
		inst.el.inventoryMessage = inst.el.availabilityWrapper.find(inst.opts.inventoryMessage);
		setInventoryMessage(inst.opts.inventoryMsgNoSelection+' '+getLocateInStoreLink());
		setTooltipMessage(inst.opts.tooltipMsgNoSelection);
		
		inst.el.addToBagButton.bind('mouseover', showAddToBagToolTip);
		inst.el.addToBagButton.bind('mouseout', hideAddToBagToolTip);
		inst.el.wishListButton.bind('mouseover', showWishListToolTip);
		inst.el.wishListButton.bind('mouseout', hideWishListToolTip);
		
		if(inst.initialColorElement != null) inst.initialColorElement.trigger('click'); // if there's an inital color select it after all swatches are initialized
		for(var i=1; i<=inst.product.requiredDimensions; i++){ // see if you can preselect any size buttons that are by themselves
			if(inst.el['sizeButtons'+i].length == 1) inst.el['sizeButtons'+i].trigger('click');
		}
		$.each(inst.initialSizeButtons, function(key, val){ // preselected any size(s) set in inst.opts.initialSize element
			val.trigger('click');
		});
	}
	inst.init(userOpts);
}
function isEmpty(o) {
	for(var p in o) {
		if (o[p] != o.constructor.prototype[p])
			return false;
	}
	return true;
}
debug = false;
function log(msg){
	if(debug) console.log(msg);
}
function dir(msg){
	if(debug) console.dir(msg);
}
