// SPP functions
brand.spp = brand.spp || {};

// swatch display for thumbnail grid & name list
brand.spp.initSwatches = function(args) {
    if (!args.node) { return; }
    var swatchSet;
    var swatchArgs = args.swatchArgs;
    swatchArgs.parentId = args.node; //JSTEST trial
    var prodBrowserSkuField = args.pageArgs.prodBrowserSkuField;
    var product = swatchArgs.product;
    var skuField = swatchArgs.skuField;
    var favField = args.pageArgs.favField;
    var filters = {};
    var cartConfirm = args.pageArgs.cartConfirm;
    swatchArgs.isMultiShadedSingleSku = args.pageArgs.isMultiShadedSingleSku;
    var hasPhotosBySku = false;

    // swatch cards for all shades
    var swatchCard = new brand.product.swatchCard({
        id: "swatchcards",
        nodeToReplace: $("swatchcard-placeholder"),
        skus: product.skus,
        price: product.price,
        cartConfirm: cartConfirm,
        isMultiShadedSingleSku: args.pageArgs.isMultiShadedSingleSku,
        closeOnClickOutside: { 
            enable: true,
            nodesToExclude: [ $(swatchArgs.domParent) ] // don't allow clicks in thumbs area to bubble up to body (at which point it would cancel out the opening of the swatch card)
        }
    });

    if (swatchArgs.isMultiShadedSingleSku) {
        //console.log("brand.spp.swatchSet.init: isMultiShadedSingleSku"); 
        // prods that display multi-colored sets of swatches also only display 1 sku per page        
        var sku = product.skus[0];
        
        // inventory status
        site.product.inventoryStatus({
            shoppable: sku.shoppable,
            message: sku.inventory_status_message,
            messageNode: site.spp.inventoryStatusNode,
            containerNode: $("prod-details")
        });
        
        // on swatch select
        swatchArgs.onSelectCallback = function(selectedChild, args) {
            //console.log("swatchArgs.onSelectCallBack selectedChild = ",selectedChild);
                        
            // open card on selection if not triggered by load              
            if (swatchCard && (!args || args.event !== "load")) {
                swatchCard.onSwatchSelect({ sku: sku, swatchNode: selectedChild.domNode, swatchIdx: selectedChild.idx });
            }

        }
        swatchArgs.initDefault = false; // don't need to set default, since skuField set explicitly for multi's
        swatchSet = new brand.product.thumbSwatchSet(swatchArgs, args.node);
        skuField.value = sku.path;
        favField.value = skuField.value;
        cartConfirm.sku = sku;
        $("swatch-pop-container").removeClassName("hidden");
        
    } else {
        //console.log("brand.spp.swatchSet.init: !isMultiShadedSingleSku");

        // set up main image swapping by sku
        hasPhotosBySku = brand.spp.photoBySku.init();
        
        // on swatch select
        swatchArgs.onSelectCallback = function(selectedChild, args) {
            //console.log("swatchArgs.onSelectCallBack selectedChild = ",selectedChild);
            //console.log("swatchArgs.onSelectCallBack args = ",args);
                        
            // if selection wasn't triggered from name menu or initial load open the card
            // Note: swatch card internally handles the setting of its cart button 
            // open card on selection if not triggered by load or name menu
            if (!args || args.event !== "name-menu") {              
                if (swatchCard && (!args || args.event !== "load")) {
                    brand.spp.swatchSorters.updateNameMenu(selectedChild.idx); // can't do on load, since menu might not have been created
                    swatchCard.onSwatchSelect({ sku: selectedChild.sku, swatchNode: selectedChild.domNode });
                }
            }

            // handle page/main inventory status node display
            // (swatch card status node handled by swatchCard class)
            site.product.inventoryStatus({
                shoppable: selectedChild.sku.shoppable,
                message: selectedChild.sku.inventory_status_message,
                messageNode: site.spp.inventoryStatusNode
            });
                
            // tell page favorites button, cart confirm & color play button which sku has been selected
            // Note: swatchSet class internally handles setting skuField
            if (favField) favField.value = selectedChild.sku.path;
            cartConfirm.sku = selectedChild.sku;
            if (prodBrowserSkuField) prodBrowserSkuField.value = selectedChild.hex;           
            // swap main Image
            if (hasPhotosBySku) {
                brand.spp.photoBySku.onSkuSelect(selectedChild.sku, selectedChild.idx);
            }
        }
        
        //console.log("brand.product.initSwatchSet calling SC: " ,swatchArgs); 
        swatchSet = new brand.product.thumbSwatchSet(swatchArgs, args.node);
        
        // init swatch sorting/filtering logic
        brand.spp.swatchSorters.init({
            swatchSet: swatchSet,
            product: product,
            shadedType: swatchArgs.shadedType,
            hasTabs: args.pageArgs.hasTabs
        });
        
        // now that both swatches & menus have initialized, update name menu with pre-selected sku
        if (swatchSet.selectedChildWidget && typeof swatchSet.selectedChildWidget.idx !== "undefined") {
            brand.spp.swatchSorters.updateNameMenu(swatchSet.selectedChildWidget.idx);
        }
    }
   
    return swatchSet;
};

// sorting/filtering drop-downs
brand.spp.swatchSorters = {

    _currentFilter: "all", // "all" = showing all shades
    _savedFilterStates: {},
    _settingFilter: false,
    
    finishesKey: "finishes",
    nameKey: "name",
    searchKey: "search",
    
    init: function(args) {
        //console.log("brand.spp.swatchSorters");  
       
        var swatchSet = args.swatchSet;
        var product = args.product;
        this.filters = {}; // filter hash to pass to swatchSet
        var finishFilters = {};
        
        // dom nodes
        var nameMenuNode = $("menu-swatches-byname");
        this.nameMenuContainer = $("menu-swatches-byname-container");
        this.finishMenuContainer = $("menu-filter-byfinish");
        var searchNodes = {
            container: $("product-search"),
            fieldId: "product-search-field",
            button: $("product-search-button"),
            message: $("product-search-message")
        }
        
        this.nameMenu = this._initNameMenu(swatchSet, product, nameMenuNode);
        this.searchForm = this._initSearch(swatchSet, product, searchNodes);

        // get/set filters
        if (args.shadedType !== "duo") {
            // by finish
            finishFilters = this._getFinishFilters(product);
            if (finishFilters) {
                this.filters = finishFilters.filters; // save each finish is a sibling of other filters (i.e. "matte" & "limited")
                this.finishMenu = this._initFinishFiltering(swatchSet, finishFilters);
            }
        }

        // get best sellers data or pro products data but not both
        var showProProducts = (page_data.pro_member == 1 ? true : false);
        var otherFilters = ["limited_life"]; // page data keys
        if (showProProducts) {
            otherFilters.push("pro_products"); // page data key
        } else if (product.has_top_sellers == 1) {
            // top sellers: reformat data into common filters format
            var topsellerFilter = this._getFilterBySkuId({ product: product, skuArray: product["top_seller_skus"] });
            // page data may say "has_top_sellers == 1", but top_seller skus listed may not match any that are displayable on page
            if (topsellerFilter && topsellerFilter.length > 0) this.filters["top_sellers"] = topsellerFilter;
        }
        
        // get/set one-dimensional filter data (e.g. not top sellers or finishes)
        this._getFilters(product, otherFilters);

        // set filter property for swatchSet instance
        swatchSet.filters = this.filters;
            
        // if loading with a sku selected
        var firstSel = (swatchSet.selectedChildWidget ? swatchSet.selectedChildWidget.idx : null);
        if (firstSel) {
            this.updateNameMenu(firstSel);
        }
        
        // tab changes trigger changes in swatch display/sorting
        if (args.hasTabs && brand.spp.tabContainer) {
            this._enableTabs({ swatchSet: swatchSet });
        }
    },

    _initNameMenu: function(swatchSet, product, menu) { 
        // set up callback for sorting menu
        if (!menu) { return false; }
        
        var self = this;        
        var names = this._getNames(product);
        var optionCount = menu.options.length; // if there's a default label we want to add to it rather than starting options at 0
        this._savedFilterStates[this.nameKey] = "all";
        var count = 0;
        
        // if only 1 name, hide menu and container
        if (names.length <= 1) {
            if (this.nameMenuContainer) {
                this.nameMenuContainer.hide();
            } else {
                menu.hide();
            }
            return false;
        }
        
        names.each(function(opt, idx) {
            count = (optionCount + idx);
            menu.options[count] = new Option(opt.label, opt.num); 
        });

        var onChange = function() {  
            //console.log("brand.spp.swatchSorters._initNameMenu onChange ");
            var value = this.getValue();
            if (typeof(value) === "undefined") { return; }
            var swatch = $("swatch_" + product.skus[value].sku_id).widget;
            if (!swatch || swatchSet.selectedChildWidget == swatch) { return; }
            swatchSet.setSwatch(swatch, { event: "name-menu" });
            
            // if swatch seleted is not in current filter, set filter back to "all"
            var filter = self._currentFilter;  
            if (filter !== "all") {
                var hasSwatchInFilter = self.filters[filter].any(function(swatchIdx) { 
                    return (swatchIdx === value);
                }); 
                
                // reset filter display state to "all"
                if (!hasSwatchInFilter) {
                    self._setFilter(swatchSet, { value: "all", type: self.nameKey, event: "name-menu" });   
                }
            }
        }
        menu.observe("change", onChange);
        
        return menu;
    },
        
    _initFinishFiltering: function(swatchSet, finishFilters) {
        //console.log("_initFinishFiltering: "+menu);
        // populate filtering menu 
        if (!this.finishMenuContainer || !finishFilters) return false;
        
        var self = this;
        var labels = finishFilters.labels;
        var filters = finishFilters.filters;
        var count = 0;
        var type = this.finishesKey;
        var menu = this.finishMenuContainer.select("select")[0];
        var optionCount = menu.length;
        if (!menu) return false;

        for (var filter in filters) {
            menu.options[optionCount] = new Option(labels[filter], filter);
            optionCount++;
            count++;
        }
        
        // hide menu if no prod has no finishes
        if (count == 0) {
            this.finishMenuContainer.hide();
            return false;
        }
        
        // set up callback
        var onChange = function() {
            var value = this.getValue();
            //console.log("brand.spp.swatchSorters._initFinishFiltering onChange value = "+value+" self._currentFilter = "+self._currentFilter+" self._settingFilter = "+self._settingFilter);
            if (value !== self._currentFilter && !self._settingFilter) {
                self._setFilter(swatchSet, { value: value, type: type });
                swatchSet.domNode.show();
                self._savedFilterStates[type] = value; // save state
            }
        }
        menu.observe("change", onChange);
        
        return menu;
    },

    _initSearch: function(swatchSet, product, searchNodes) {
        if (!searchNodes || !searchNodes.container) return false;
        var self = this;
        var msgNode = searchNodes.message;
        msgNode.hide();
        var query = "";
        var isSearching = false;
        var progress = new brand.progress({
            containerNode: swatchSet.domNode,
            progressNode: searchNodes.container.select('.progress')[0]
        }); 
        
        var showSkus = function(response) {
            var data = response;        
            
            if (!data || !data.skus || data.skus.length < 1) {
                // empty results
                onNoResult(response);
                
            } else {
                var resultCount = data.skus.length;
                isSearching = false;
                // set filter of sku indices
                self.filters[self.searchKey] = self._getFilterBySkuId({ product: product, skuArray: data.skus });
                self._setFilter(swatchSet, { value: self.searchKey, type: self.searchKey, nocache: true });
                progress.clear();
                var resultMessage = site.product.rb.search_results.replace("QUERY", query);
                resultMessage = resultMessage.replace("RESULTS", resultCount);
                msgNode.update(resultMessage);
                msgNode.show();
            } 
        }

        var onNoResult = function(response) {
            console.log('RPC call successful, but no results returned. response = ',response);
            //var resultMessage = site.product.rb.search_no_results.replace("QUERY", query); // replace "QUERY" with search input
            var resultMessage = site.product.rb.search_no_results;
            onMessage({ message: resultMessage });
        }
        
        var onFailure = function(response) {
            var message = response.getMessages();
            console.log('Product Search JSON failed to load. response = ',message);
            onMessage({ message: "Error: "+message[0].text });
        }

        var onMessage = function(args) {
            isSearching = false;
            progress.showMessage({ messageNode: msgNode, message: args.message, hideContainer: true });
            self.filters[self.searchKey] = null;
        }
        
        var getSkus = function() {
            if (isSearching) return;
            isSearching = true;
            progress.start();
            query = $F(searchNodes.fieldId);

            var endecaArgs = {
                searchTerm: query,
                filterProducts: true,
                recsPerPage: 500,
                additionalFilters: 'p_PRODUCT_ID:' + product.product_id,
                searchKey: 'shade'
            };
        
        
            var shadeQuery = new EndecaQuery (
                Object.extend( endecaArgs, {
                    callbackCompleted: function() {
                        var eCatalog = new EndecaCatalog({jsonResult: this.jsonResult});
                        showSkus(eCatalog.productList[product.product_id]);
                    }       
                })
            );
            
            shadeQuery.makeRequest();

        }
        searchNodes.button.observe("click", getSkus);
        
        return searchNodes.container;
    },
    
    updateNameMenu: function(idx) {
        //console.log("brand.product.updateNameMenu "+typeof idx+" this.nameMenu = "+this.nameMenu); 
        if (this.nameMenu) {
            this.nameMenu.value = idx;
        }
    },
    
    _getNames: function(product) {
        var names = [];
        var sortedSkus = product.sorters.names;
        for (var i=0; i<sortedSkus.length; i++) {
            var name = {};
            var num = sortedSkus[i];
            name.num = num.toString();
            name.label = product.skus[num].shade_name;
            names[i] = name;
        }
        return names;            
    },

    _setFilter: function(swatchSet, args) {
        var prev = this._currentFilter;
        var value = args.value;
        this._currentFilter = value;
        if ((prev === this._currentFilter && !args.nocache) || this._settingFilter) { return; }
        this._settingFilter = true;
        
        // send sort/filter value to swatchSet instance
        //console.log("swatchSet filters = ",swatchSet.filters);
        swatchSet.processData("filter", value, args.nocache);
        //console.log("swatchSet.processData: _setFilter - to: "+value+" type = "+args.type);

        // name menu selection is forcing a re-display of all swatches so show its tab
        if (args.event === "name-menu" && value === "all") {
            brand.spp.tabContainer.setTabRemotely({ sortingKey: args.type });
        }
        
        this._settingFilter = false;
    },
    
    _getFinishFilters: function(product) {
        var filters = {};
        var labels = {};
        var skusByFinish = product.filters[this.finishesKey];
        var sortedFinishNames = product.filters.sorted_finishes;
        hasFinishes = false;
        if (!sortedFinishNames) return false;
        var finishCount = sortedFinishNames.length;  

        for (i=0; i<finishCount; i++) {
            var finishName = sortedFinishNames[i]; // finishId = id value for menu
            // convert indices to strings
            var skus = skusByFinish[finishName].toString();
            skus = skus.split(",");
            hasFinishes = true;
            var finishId = finishName.replace(/ /, ""); // finishId = id value for menu (lowercased, white-space, removeed, etc...)
            finishId = finishId.toLowerCase();
            var label = finishName; // label = display label for menu (entities stripped)
            // replace html entities
            var entitiesToUnicode = site.spp.entitiesToUnicode;
            if (entitiesToUnicode && (label.indexOf("&") > -1)) {
                for (var entity in entitiesToUnicode) {
                    var entityString = new RegExp(entity, 'g');
                    label = label.replace(entityString, entitiesToUnicode[entity]);
                }
            }
            
            labels[finishId] = label;
            filters[finishId] = skus;  
        } 

        if (!hasFinishes) return false;
        return { filters: filters, labels: labels };
    },

    // get skus when data is a set of sku_ids instead of a list of sku indices
    _getFilterBySkuId: function(args) {
        var filter = [];
        if (!args.product || !args.skuArray) return false;
        var product = args.product;
        var skuArray = args.skuArray;
        this.skuIndices = (this.skuIndices ? this.skuIndices : this._getSkuIndices(product.skus));
        if (!skuArray || skuArray.length == 0) return false;
        var resultIdx = i = 0;
        var count = skuArray.length;
        
        // loop thru skus to find index of top seller sku ids
        for (i=0; i<count; i++) {
            var skuId = skuArray[i];
            // json-rpc results return obj as: {SKU_ID="SKU1688"}
            if (typeof skuId === "object") {
                if (skuId.SKU_ID) skuId = skuId.SKU_ID;
            }
            var skuIdx = this.skuIndices[skuId];
            if (!skuIdx) continue;
            filter[resultIdx] = skuIdx;
            resultIdx++;
        }        
        return filter;             
    },
    
    _getFilters: function(product, dataKeys) {
        if (!product.filters) return;
        var self = this;
        
        dataKeys.each(function(key){
            var filterIndices = product.filters[key];
            if (filterIndices && filterIndices.length > 0) {
                // convert int indices into strings
                var filter = [];
                for (var i=0; i<filterIndices.length; i++) { 
                    var num = filterIndices[i];
                    filter.push(num.toString());
                }
                
                // add filter to master filter hash
                if (filter.length > 0) {
                    self.filters[key] = filter;
                }
            }
        });             
    },
    
    // store position of skus in sku array, keyed by sku ids
    _getSkuIndices: function(skus) {
        if (!skus) return false;
        var indices = {};
        var skuCount = skus.length;
        // loop thru skus to find index       
        for (i=0; i<skuCount; i++) {
            var skuId = skus[i].sku_id;
            indices[skuId] = i.toString(); // convert int indices into strings
        }
        return indices;    
    },

    _enableTabs: function(args) {
        if (!brand.spp.tabContainer.tabs) return;
        var self = this;
        generic.events.observe("tabs:beforeshow", function(eventArgs) {
            self.onTabChange(args.swatchSet, eventArgs);
        });

        // display tabs with sorting/filtering data
        var sortingKeys  = brand.spp.tabContainer.sortingKeys;
        for (var key in sortingKeys) {
            var tabId = sortingKeys[key];
            var tab = $(tabId);
            if (!tab) continue;
            var parent = tab.parentNode;
            if (!parent) continue;
            
            if (key === this.finishesKey && this.finishMenu) {
                // finishes tab
                parent.removeClassName("hidden");
            } else if (this.filters[key]) {
                // other tabs
                parent.removeClassName("hidden");
            }
        }
        
        // reset scrolling state now that content has loaded
        brand.spp.tabContainer.tabs.resetScrolling();
    },
    
    onTabChange: function(swatchSet, args) {
        //console.log("onTabChange args = ",args);
        //console.log("onTabChange, this._savedFilterStates = ",this._savedFilterStates);
        var selectedLink = args.selectedLink;
        if (!selectedLink) return;
        var selectedSort = (args.selectedSort ? args.selectedSort : this.nameKey);
        var activeSort = (args.activeSort ? args.activeSort : this.nameKey);
        var finishMenu = this.finishMenu;
        var searchForm = this.searchForm;
        var sortValue = (this._savedFilterStates[selectedSort] ? this._savedFilterStates[selectedSort] : selectedSort);

        // toggle display of swatches, filter menu & search form when tabbing away from their tab
        if (finishMenu && activeSort === this.finishesKey) {
            this.finishMenuContainer.hide();
            swatchSet.domNode.show();
        } else if (searchForm && activeSort === this.searchKey) {
            searchForm.hide();
            swatchSet.domNode.show();           
        }
            
        // case: filter by finish        
        if (finishMenu && selectedSort === this.finishesKey) {
            // toggle display of filter menu
            this.finishMenuContainer.style.display = "block";
            if (finishMenu.selectedIndex == 0) {
                swatchSet.domNode.hide();
            } else {
                // show the state of the finish filter with last known selected finish
                this._setFilter(swatchSet, { value: sortValue, type: selectedSort });
            }

        // case: search results
        } else if (searchForm && selectedSort === this.searchKey) {
            // toggle display of search form
            searchForm.style.display = "block";
            // show swatches if there's a previous result set to show
            var searchResults = this.filters[this.searchKey];
            if (searchResults && searchResults.length > 0) {
                this._setFilter(swatchSet, { value: sortValue, type: selectedSort, nocache: true });
            } else {
                swatchSet.domNode.hide();
            }
          
        // case: other tabs
        } else {
            
            // set display of swatches based on selected tab
            this._setFilter(swatchSet, { value: sortValue, type: selectedSort });
        }
    
    }
};


// spp tab handler
brand.spp.tabContainer = {

    // tab names as paired with swatch sorting types 
    sortingKeys: {
        "name": "tab-shades",
        "pro_products": "tab-pro",
        "limited_life": "tab-limited",
        "top_sellers": "tab-bestsellers",
        "finishes": "tab-byfinish",
        "search" : "tab-search"
    },
    
    init: function() {
        var self = this;
        this.tabs = new brand.tabs("prod-tabs-nav",
            {
                tabContainer: $("prod-tabs"),
                activeClassName: "tab-active",
                beforeShow: function(link) {
                    self.beforeShow(link);
                },              
                useImageHeaders: true,
                scrollbar: {
                    contentNode: $('scroll-content-container'),
                    containerNode: $("scrollbar-container"),
                    handleId: "scrollbar-handle",
                    trackId: "scrollbar-track",
                    enabledClass: "scrollbar-enabled"  
                }
            }
        );
        
        // save sorting types by tab
        var tabKeys = {};
        for (var key in this.sortingKeys) {
            var value = this.sortingKeys[key];
            tabKeys[value] = key;
        }
        this.tabKeys = tabKeys;
    },
    
    beforeShow: function(link) {
        var activeLink = (this.tabs ? this.tabs.activeLink : null);
        if (!link || !activeLink) return;
        if (link.id === this.tabs.activeLink.id) return;
        
        // broadcast tab change for swatch sorting based on tab
        generic.events.fire({event: "tabs:beforeshow", msg: { selectedLink: link, selectedSort: this.tabKeys[link.id], activeSort: this.tabKeys[activeLink.id] } });    
    },
    
    setTabRemotely: function(args) {
        var sortingKey = args.sortingKey;
        var linkId = args.linkId;
        if (!sortingKey && !linkId) return;
        var link = (sortingKey ? $(this.sortingKeys[sortingKey]) : $(linkId));
        if (!link || (link.id === this.tabs.activeLink.id)) return;
        this.tabs.setActiveTab(link);
    }
    
};

// "more" description
brand.spp.initDescription = function(args) {
    var linkNode = args.linkNode;
    var descriptionNode = args.descriptionNode;
    if (!linkNode || !descriptionNode || !args.hasDescription) return;
    
    linkNode.removeClassName("hidden");
    
    // event handlers
    linkNode.observe("mouseover", function() {
        descriptionNode.style.visibility = "visible";
        brand.spp.toggleFormSelectForIE6(false);
    });
    descriptionNode.observe("mouseout", function() {
        descriptionNode.style.visibility = "hidden";
        brand.spp.toggleFormSelectForIE6(true);
    });
};


// color play link
brand.spp.initColorPlayButton = function(field) {        
    var url = "/flash/color_play/index.tmpl";
    var param = "?colorplaysample=";
    if (!field) return false;
        
    var _onClick = function(e) {
        var hex;
        hex = field.value.split("#")[1];
        if(hex) {
            hex = "0x" + hex;
            location.href = url + param + hex;
        } else {
            location.href = url;
        }
    }
    field.observe("click", _onClick);
}

// main image rollover
brand.spp.photoRollover = {
    hasRollover: false,
    overImg: null,
    outImg: null,
    init: function(outImg, overImg) {
        var node = $("prod-image");
        if (!node) {
            return;
        }
        // if first set of image paths is passed then set to true
        // otherwise will start off as false, but can be set to true if brand.spp.photoBySku
        // passes valid per-sku image paths on sku selection
        if (outImg && overImg) {
            this.hasRollover = true;
            this.outImg = outImg;
            //this.overImg = overImg;
            this.overImg = this.defaultOverImg = overImg; // Note: assumes that brand wants a single sku's over/_alt image to act as the default overImg for any skus that don't have one
        } else {
            return; // SS NOTE: for now ignore if no default product.image_medium_rollover since many skus with sku.image_medium_rollover seem to be 404
        }

        var self = this;
        
        var over = function(e) {
            if (!self.hasRollover) return;
            e.target.src = self.overImg;
        }
        
        var out = function(e) {
            if (!self.hasRollover) return;
            e.target.src = self.outImg;
        }
        node.observe("mouseover", over);
        node.observe("mouseout", out);
    }
};

// main image swap on shade selection
brand.spp.photoBySku = {
    init: function() {
        this.node = $("prod-image");
        if (!this.node) return false;
        this.preloaded = {};
        return true;
    },
    
    onSkuSelect: function(sku, swatchIdx) {
        var img = sku.sku_image; // sku-specific image that shows on swatch click
        if (!img) return;
        var overImg = (sku.image_medium_rollover ? sku.image_medium_rollover : null); // sku-specific "on" state of outImg
        
        // preloads image (of not already pre-loaeded) & sets new src
        var preloaded = brand.loadImage({
            node: this.node,
            imagePath: img,
            imageStore: this.preloaded,
            imgId: swatchIdx
        });
        this.preloaded = preloaded;
  
        // if photo rollover, set on & off state to currently selected "special" image
        var pr = brand.spp.photoRollover;
        if (pr.hasRollover) {
            pr.outImg = img;
            if (overImg) {
                pr.overImg = overImg;
            } else {
                pr.overImg = pr.defaultOverImg;
            }
        }
        /* SS note: use this if sku.image_medium_rollover is meant to be reliable
        if (overImg) {
            pr.hasRollover = true;
            pr.outImg = img;
            pr.overImg = overImg;
        } else {
            pr.hasRollover = false;
        }
        */
    } 
};

// products with multiple skus based on size (non-shaded)
brand.spp.initSized = function(args) {
    var menu = args.menuNode;
    var skus = args.skus;
    var skuCount = skus.length;
    if (skuCount < 1) return;
    var firstSkuId = 0;

    // populate menu
    if (!args.menuNode) {
        site.spp.setSkuSelection({ sku: skus[0], cartConfirmMsg: args.cartConfirmMsg });
        return; // if returning here, then this method was somehow applied to a single-skued product in which case we still want to do sku selection
    }

    var skuIndices = {};
    var skuIdArray = new Array();
    for (var i=0; i<skuCount; i++) {
        var skuId = skus[i].sku_base_id;
        skuIdArray.push(skuId);
        skuIndices[skuId] = i; // keep track of sku index in data
    }
    var sizeNode = $$("div#prod-container span.size")[0];
    var priceNode = $$("div#prod-container span.price")[0];

    // Sort by sku_base_id to get Small, Medium, Large order
    skuIdArray = skuIdArray.sort();
    for (var i=0; i<skuCount; i++) {
        var skuId = skuIdArray[i];
        var skuIndex = skuIndices[skuId];
        var sizeInfo = skus[skuIndex].product_size;
        var label = (sizeInfo ? sizeInfo : "");
        menu.options[i] = new Option(label, skuIndex);
        if (i == 0) {
            firstSkuIdx = skuIndex;
        }
    }

    var setSkuSelection = function(skuIdx) {
        var sku = skus[skuIdx];
        //console.log("sized sku selection = "+sku.sku_base_id+" / "+sku.product_size);
        site.spp.setSkuSelection({ sku: sku, cartConfirmMsg: args.cartConfirmMsg });
        if (sizeNode) sizeNode.innerHTML = sku.product_size;
        if (priceNode) priceNode.innerHTML = sku.formatted_price;
    }
    // pre-select first sku
    setSkuSelection(firstSkuIdx, "size");
    
    // menu event callback
    var onChange = function() {  
        //console.log("brand.spp sized onChange ");
        var value = this.getValue();
        //console.log("brand.spp sized onChange value = "+value);
        if (typeof(value) === "undefined") { return; }
        // set selected sku
        setSkuSelection(value);
    }
    menu.observe("change", onChange);
};

// IE6 workaround: toggle display of form select(s) when popovers are showing
brand.spp.toggleFormSelectForIE6 = function(show) {
    if (generic.env.isIE6) {
        var container = $("prod-container");
        if (container) {
            if (show) {
                container.removeClassName("popup-visible");
            } else {
                container.addClassName("popup-visible");
            }
        }
    }
};
