/*
Package contents:

  ProductItem
  ProductManager
  ProductRequest
  ProductList
  
*/

/*
 @author Dan Morris / Picture
 version: 0.1
 last modified: 9.IX.2007
 
 Description:
 This class describes the items that make up a product.
 An item is defined as a combination of img variant id and group variant ids.
*/

// trace function to degrade console logging
var trace = function(str){

    try {
        opera.postError(str);
    } 
    catch (e) {
        try {
            console.log(str);
        } 
        catch (f) {
            //alert(str);
        }
    }

}

var ProductItem = new Class ({

  initialize: function(_itemID, _itemPrice, _itemOnSale, _itemOnSalePrice, _itemWeight, _itemDescription, _itemQuantityInStock, _imgVarID, _groupVarIDs, _groupVarInfo) {
    this.itemID = new Number(_itemID).toInt();
    this.imgVarID = new Number(_imgVarID).toInt();
    var type = $type(_groupVarIDs);
    if ($chk(type) && (type != 'array')) { _groupVarIDs = [_groupVarIDs]; }
    this.groupVarIDs = _groupVarIDs;
    this.groupVarInfo = _groupVarInfo;
    this.price = new Number(_itemPrice);
    this.weight = new Number(_itemWeight).toInt();
    this.onSale = new Boolean(_itemOnSale);
    this.onSalePrice = this.onSale ? new Number(_itemOnSalePrice) : null;
    this.description = _itemDescription;
    this.quantityInStock = new Number(_itemQuantityInStock).toInt();
  }
  // returns this item if the passed img var id and all groupvar ids match this items
, matchItem: function(_imgVarID, _groupVarIDs) {
    if (window.debugging) { trace('ProductItem.matchItem(): this.itemID : ' + this.itemID + ' _imgVarID : ' + _imgVarID + ' : _groupVarIDs : ' + _groupVarIDs); }
    return ((this.imgVarID === _imgVarID) && this.groupVarIDs.every(function(item, index){ return _groupVarIDs.contains(item); })) ?  this : null;
  }
  
 ,toString:               function() { return this.itemID + ' &#163' + this.price + ' ' + this.quantityInStock; }
 ,getCartPrice:           function() { return ((this.onSale == false) || (this.onSalePrice == null)) ? this.price : this.onSalePrice; }
 ,getPrice:               function() { return this.price; }
 ,getWeight:              function() { return this.weight; }
 ,getOnSale:              function() { return this.onSale; }
 ,getOnSalePrice:         function() { return this.onSalePrice; }
 ,getQuantityInStock:     function() { return this.quantityInStock; }
 ,takeQuantityFromStock:  function(_qty) { this.quantityInStock -= new Number(_qty); }
 ,getSizeName:            function() {
     var str="";
     this.groupVarInfo.each(function(obj){
         str+=obj.groupName+" "+obj.varName+" ";
     }.bind(this));
     return str;
 }  
  
});

/*
 @author Dan Morris / Picture
 version: 0.1
 last modified: 9.IX.2007
 
 Description:

 This class is like a shelf that contains all the colourway / size variants that define each individual item that belong
 to this page's product. We need to know about how many of each item (and its name/price/desc details) there exists.
 We then need to know the id of the text box that has the quantity of item to add, which dropdowns contain the 
 group and groupvar info, the id of the add button, and then work out which item is selected when each one of these 
 dropdowns changes (or imgvars is clicked). if there are sufficient items in stock, we need to tell the cart manager 
 which item we want to add to their cart on the server. the cart manager takes care of updating the cart.
 
*/

var ProductManager = new Class({

    options: {
        productID: false
   , imgVarID: false
   , detailID: false
   , productName: false
   , productRequestUrl: false
   , addButtonID: false
   , qtyTextID: false
   , mainImg: false
   , pnlPrice: false
   , pnlOnSale: false
   , pnlColourID: false
   , pnlImgVarID: false
   , pnlDetailID: false
   , pnlGroups: false
   , items: []
   , imgVars: []
   , groups: []
   , imgVarPath: false
   , imgVarThumbPath: false
   , detailPath: false
   , detailThumbPath: false
   , thumbWidth: false
   , convEuro: false
   , convYen: false
   , showZeroStock: false
   , messageAdd: false
   , messageBusy: false
   , messageZeroUnavailable: false
   , messageNoZeroNotAnItem: false
   , messageNoZeroOutOfStock: false
   , propagateLinks: true
    }

, initialize: function(_cartManager, options) {
    if (window.debugging) trace('ProductManager.initialize()');
    // gather args and assign those that need no special setting
    this.setOptions(options);
    if ($chk(_cartManager)) { this.setCartManager(_cartManager); }
    this.addButton = $(this.options.addButtonID);
    this.addButton.addEvent('click', this.setCartItem.bind(this));
    this.addButton.setStyle('cursor', 'pointer');

    //TODO -- make this a value passed in
    this.options.stocklink = (this.options.stocklink) ? this.options.stocklink : "mailto:info@garbstore.com";
    this.options.stockSubject = (this.options.stockSubject) ? this.options.stockSubject : "info@garbstore.com";
    this.options.stocktext = (this.options.stocktext) ? this.options.stocktext : "info@garbstore.com";
    this.options.stockclass = (this.options.stockclass) ? this.options.stockclass : "stocklink";

    this.stockmessage = new Element('div', { 'style': 'display: block; width: 100%; padding-top: 20px;' });
    this.stockmessage.innerHTML = "Enquire about this product";

    this.stockmaillink = new Element('a', { 'href': this.options.stocklink + "?subject=" + this.options.stockSubject, 'class': this.options.stockclass });
    this.stockmaillink.setHTML(this.options.stocktext);
    this.stockmessage.injectAfter(this.addButton);
    //this.stockmaillink.injectAfter(this.addButton);
    this.stockmaillink.injectAfter(this.stockmessage);

    this.qtyText = $(this.options.qtyTextID);
    this.oldImgVarID = false;
    this.mainImg = $(this.options.mainImg);
    this.nextSrc = false;
    this.imgContainer = this.mainImg.getParent();
    this.displayImage = new Hash();
    this.pnlPrice = $(this.options.pnlPrice);     // panel we write prices to
    this.pnlOnSale = $(this.options.pnlOnSale);   // panel that indicates currently selected item is onsale
    this.pnlColour = $(this.options.pnlColourID); // panel we add imgvar ddls to
    this.ddlImgVar = false;                       // imgVar ddl obj
    this.pnlImgVar = $(this.options.pnlImgVarID); // panel we add imgvar's clickable thumbs to
    this.pnlDetail = $(this.options.pnlDetailID); // panel we add imgvar's detail image thumbs to
    this.pnlGroups = $(this.options.pnlGroups);   // panel we add group dropdowns to
    this.groupDdls = [];                          // arr of group ddl objs
    this.items = [];
    this.itemsDdl = null; // dropdown list with various items options in 
    this.imgVars = this.options.imgVars;
    this.groups = this.options.groups;
    this.imgVarPath = this.options.imgVarPath;
    this.imgVarThumbPath = this.options.imgVarThumbPath;
    this.detailPath = this.options.detailPath;
    this.detailThumbPath = this.options.detailThumbPath;
    this.thumbWidth = new Number(this.options.thumbWidth).toInt();
    this.convEuro = new Number(this.options.convEuro);
    this.convYen = new Number(this.options.convYen);
    this.variationsCreated = false;

    this.mainImgFx = new Fx.Style(this.imgContainer, 'opacity', {
        'wait': false
       , 'duration': 600
       , 'transition': Fx.Transitions.Quart.easeInOut
       , 'onComplete': this.loadMainImg.bind(this)
    });

    this.pnlOnSaleFx = new Fx.Style(this.pnlOnSale, 'opacity', {
        'wait': false
       , 'duration': 600
       , 'transition': Fx.Transitions.Quart.easeInOut
    });
    this.pnlOnSaleFx.set(0);

    this.currItem = null;

    this.setImgVars();
    this.setImgVarsDdl();

    // used to set dropdowns based on the products group vars, then work out which item to select - superceeded by item dropdowns
    //this.setGroups(); 

    this.getProductItems();  // this gets the products items via ajax and set the current item when it's done
}

, updateStockEmailSubject: function() {

    if (!this.stockmaillink) return;

    var pn = (this.options.productName) ? this.options.productName : "";
    var pid = (this.options.productID) ? this.options.productID : "";
    var vid = (this.currItem) ? this.currItem.imgVarID : "";
    var iid = (this.currItem) ? this.currItem.itemID : "";
    var desc = (this.currItem) ? this.currItem.description : "";

    var body = "Please don't edit this part of the mail";
    body += "%0D%0A" + pn + " " + desc;
    body += "%0D%0A[p:" + pid + " v: " + vid + " i:" + iid + "]";
    body += "%0D%0AThank you, please feel free to add any further questions or comments.";

    var link = this.options.stocklink + "?subject=" + this.options.stockSubject + '&body=' + body;
    this.stockmaillink.setProperty('href', link);

}


    // set up the product's group var ddls
, setGroupDdls: function(_groupDdlIds) {
    this.groupDdls.each(function(el) { this.groupDdlIDs.include($(el)); } .bind(this));
}

    // set up the product's items based on the following json dfn:
    /*
    [
    { itemID: 1000, active: true, price: 100.00, weight: 1000, onSale: false, onSalePrice: null, description: 'SUM-XYZ-CTN-BLK-REG', quantityInStock: 5, imgVarID: 1000, groupVarIDs: [2] }
    , { itemID: 1001, active: true, price: 100.00, weight: 1000, onSale: false, onSalePrice: null, description: 'SUM-XYZ-CTN-BLK-LRG', quantityInStock: 0, imgVarID: 1000, groupVarIDs: [3] }
    ...
    , { itemID: 1006, active: false, price: 100.00, weight: 1000, onSale: false, onSalePrice: 75.00, description: 'SUM-XYZ-CTN-BLU-LRG', quantityInStock: 0, imgVarID: 1003, groupVarIDs: [3] }
    ]
    */
, setItems: function(_items) {
    if (window.debugging) { trace('ProductManager.setItems()'); }
    this.items = [];
    _items.each(function(el) {

        var groupVarInfo = [];
        var len = el.groupVarIDs.length;

        for (var i = 0; i < len; i++) {
            var info = this.getGroupVarInfoByID(el.groupVarIDs[i]);
            groupVarInfo.push(info);
        }
        groupVarInfo.sort(function(a, b) { return a.groupID - b.groupID });

        this.items.include(new ProductItem(el.itemID, el.price, el.onSale, el.onSalePrice, el.weight, el.description, el.quantityInStock, el.imgVarID, el.groupVarIDs, groupVarInfo));
    } .bind(this));
    if (window.debugging) { trace(' -- this.items '+this.items); }
    
    this.items.sort(function(a, b) { return a.itemID - b.itemID });
}

    // creates a dropdown with the passed id and text label belonging to the passed parent
 , createDropDown: function(ddlName, labelText, parentEl) {
     var label;
     if ((labelText == 'Size') || (labelText == 'Waist') || (labelText == 'One Size') || (labelText == 'Shoe')) {
         label = new Element('label', { 'for': ddlName, 'class': 'variation-float' });
         label.setHTML(labelText + '&nbsp;');
     }
     else {
         if (labelText == 'Variations') {
             //             if (!(this.variationsCreated)) {
             //                 label = new Element('label', { 'for': ddlName, 'class': 'variation' });
             //                 label.setHTML(labelText);
             //                 this.variationsCreated = true;
             //             }
         }
         else {
             label = new Element('label', { 'for': ddlName, 'class': 'variation' });
             label.setHTML(labelText);
         }
     }

     //var waist = new Element('div', { 'id': 'waist', 'class': 'productvariationselect-left' });

     if (labelText == 'Waist') {
         var waist = new Element('div', { 'id': 'waist', 'class': 'productvariationselect-left' });
         label.injectInside(waist);
         waist.injectInside(parentEl);
     }
     else {
         if (labelText == 'Leg') {
             var leg = new Element('div', { 'id': 'leg', 'class': 'productvariationselect-right' });
             label.injectInside(leg);
             leg.injectInside(parentEl);
         }
         else {
             if (!(labelText == 'Variations'))
                 label.injectInside(parentEl);
             else {
                 var br = new Element('br');
                 br.injectInside(parentEl);
             }
         }
     }

     if ((labelText == 'Size') || (labelText == 'One Size') || (labelText == 'Shoe')) {
         var sizeLabel = new Element('label', { 'class': 'sizeGuide-float' });
         sizeLabel.setHTML('(see guide)');
         sizeLabel.setAttribute('id', 'sizeGuide');
         sizeLabel.addEvent('click', function(event) {
             jQuery.blockUI.defaults.css.border = '';
             var width = parseInt($('sizeGuideTable').getProperty('width')) + 26;
             jQuery.blockUI.defaults.css.width = width;
             jQuery.blockUI({ message: jQuery('#domMessage') });
             $('domMessage').setAttribute('style', 'cursor: pointer;');
             $('domMessage').addEvent('click', function(event) { jQuery.unblockUI(); });
         });

         if (labelText != 'Waist' || labelText != 'Leg') {
             sizeLabel.injectInside(parentEl);
         }
     }

     if (labelText == 'Waist') {

         var ddl = new Element('select', { id: ddlName, 'class': 'productvariationselect' });
         ddl.injectInside($('waist'));

     } else {

         if (labelText == 'Leg') {
             var ddl = new Element('select', { id: ddlName, 'class': 'productvariationselect' });
             ddl.injectInside($('leg'));
         } else {
             var ddl = new Element('select', { id: ddlName, 'class': 'productvariationselect' });
             ddl.injectInside(parentEl);
         }

     }

     if (labelText == 'Leg') {
         var sizeLabel = new Element('label', { 'class': 'sizeGuide-float' });
         sizeLabel.setHTML('(see guide)');
         sizeLabel.setAttribute('id', 'sizeGuide');
         sizeLabel.addEvent('click', function(event) {
             jQuery.blockUI.defaults.css.border = '';
             var width = parseInt($('sizeGuideTable').getProperty('width')) + 26;
             jQuery.blockUI.defaults.css.width = width;
             jQuery.blockUI({ message: jQuery('#domMessage') });
             $('domMessage').setAttribute('style', 'cursor: pointer;');
             $('domMessage').addEvent('click', function(event) { jQuery.unblockUI(); });
         });
         sizeLabel.injectInside(parentEl);
     }

     return ddl;
 }


    // set up the img variant client controls based on the following json dfn
    // [ {imgVarID: 1000, color: 'Black'} , {imgVarID: 1002, color: 'Red'} , {imgVarID: 1003, color: 'Blue'} ]
, setImgVars: function() {
    if (window.debugging) { trace('ProductManager.setImgVars()'); }

    if (!this.options.imgVarID) {
        this.options.imgVarID = this.imgVars[0].imgVarID;
    }

    // make sure there's nothing in the img var panels
    this.pnlImgVar.empty();
    this.pnlDetail.empty();

    if (this.imgVars.length > 1) {
        var span = new Element('span', { 'class': 'variation' });
        span.appendText('Variations');
        span.injectInside(this.pnlImgVar);
    }

    if (this.imgVars.length > 1) {
        this.imgVars.each(function(el, index) {

            el.div = new Element('div', { styles: { 'border-style': 'solid', 'border-color': '#D0D0D0', 'border-width': '1px 0px 1px 1px', 'padding': '4px 0px 0px 4px', 'height': '50px', 'width': '50px', 'float': 'left', 'overflow': 'hidden'} });
            if (index == (this.imgVars.length - 1)) {
                el.div = new Element('div', { styles: { 'border-style': 'solid', 'border-color': '#D0D0D0', 'border-width': '1px 1px 1px 1px', 'padding': '4px 0px 0px 4px', 'height': '50px', 'width': '50px', 'float': 'left', 'overflow': 'hidden'} });
            }

            el.img = new Element('img', {
                src: this.imgVarThumbPath.replace(/\{0\}/, this.options.productID).replace(/\{1\}/, el.imgVarID),
                styles: { 'cursor': 'pointer', 'width': '45px' }
            }).addEvents({
                'load': this.setImgDim.bind(this, [el]),
                'click': this.setImgVarByThumb.bind(this, [el.imgVarID])
            });

            el.div1 = new Element('div', { styles: { 'height': '45px', 'width': '45px', 'overflow': 'hidden'} });

            el.img.injectInside(el.div1);
            el.div1.injectInside(el.div);
            el.div.injectInside(this.pnlImgVar);
            if (window.debugging) {
                trace('ProductManager.setImgVars(): el.img.src = ' + el.img.src);
            }
        } .bind(this)); // end imgvars.each
    } // end if length > 1
}


, setImgVarsDdl: function() {
    if (window.debugging) { trace('ProductManager.setImgVarsDdl()'); }

    // remove any change event that exists
    if ($chk(this.ddlImgVar)) {
        this.ddlImgVar.removeEvent('change', this.setCurrentItem);
    }
    if (!this.options.imgVarID) {
        this.options.imgVarID = this.imgVars[0].imgVarID;
    }

    // make sure there's nothing in the img var panels
    this.pnlColour.empty();
    if (this.imgVars.length > 1) {

        // add the items to the img var dropdown if not already there
        this.ddlImgVar = this.createDropDown('ddlImgVar', 'Variations', this.pnlColour);
        this.ddlImgVar.addEvent('change', this.setCurrImgVar.bind(this));
        this.imgVars.each(function(el) {

            var opt = new Element('option', { 'value': el.imgVarID }).setHTML(el.name);
            if (el.imgVarID == this.options.imgVarID) {
                opt = new Element('option', { 'value': el.imgVarID, 'selected': 'selected' }).setHTML(el.name);
            }
            opt.injectInside(this.ddlImgVar);
            if (window.debugging) { trace('ProductManager.setImgVarsDdl(): this.ddlImgVar.options[i].value = ' + this.ddlImgVar.options[this.ddlImgVar.options.length - 1].value + ' :: currimgVarID=' + el.imgVarID + ' :: this.imgVarID=' + this.options.imgVarID + ' :: selected=' + (el.imgVarID.toInt() === this.options.imgVarID.toInt())); }
        } .bind(this));
    }
}

, setImgDim: function() {
    var img = arguments[0].img;
    if (window.debugging) { trace('ProductManager.setImgDim(): img: w x h = %i x %i', img.width, img.height); }
    // scale to half width
    img.width = img.width / 2;
    if (window.ie) {
        img.height = img.height / 2;
    }
}

    // this is the setter of the current imgVarID
, setCurrImgVar: function() {
    if (window.debugging) { trace('ProductManager.setCurrImgVar() '); }

    if (this.ddlImgVar.length > 0)
        this.options.imgVarID = this.ddlImgVar.getProperty('value').toInt();

    if (window.debugging) { trace(' this.options.imgVarID ' + this.options.imgVarID); }

    this.setItemDropDown();
    this.setCurrentItem();
}

    // when an image var thumb is clicked, we want to set the drop down and look up the item
, setImgVarByThumb: function() {
    this.options.imgVarID = arguments[0];
    if (window.debugging) { trace('ProductManager.setImgVarByThumb(): this.imgVarID = ' + this.options.imgVarID); }
    this.setImgVarsDdl();
    this.setItemDropDown();
    this.setCurrentItem();
}

    // set up the group variants dropdown based on the following json dfn
    /*
    [
    { groupID: 4, name: 'Waist', groupVars: [ { groupVarID: 10, name:'W28'}, { groupVarID: 11, name:'W30'}, ... { groupVarID: 17, name:'W42'} ] }
    ,{ groupID: 5, name: 'Leg', groupVars: [ { groupVarID: 18, name:'L30'}, { groupVarID: 19, name:'L32'}, { groupVarID: 20, name:'L35'} ] }
    ]
    */

    // old method for setting product size dropdowns, based on product groups
    /*
    , setGroups: function() {
    this.options.groups.each(function(group) {
    var ddl = this.createDropDown('ddlGroup' + group.groupID, group.name, this.pnlGroups);
    ddl.addEvent('change', this.setCurrentItem.bind(this));
    group.groupVars.each(function(gv) {
    this.options[this.length] = new Option(gv.name, gv.groupVarID);
    } .bind(ddl));
    this.groupDdls.include(ddl);
    this.groups.include(group);
    } .bind(this));
    }
    */

, setItemDropDown: function() {
    if (window.debugging) { trace('ProductManager.setItemDropDown(): this.imgVarID = ' + this.options.imgVarID); }
    if (!this.itemsDdl) {
        this.itemsDdl = this.createDropDown('items', 'Size', this.pnlGroups);
        this.itemsDdl.addEvent('change', this.setCurrentItem.bind(this));
    }

    this.itemsDdl.empty();
    var items = this.items.filter(function(item, index) { return item.imgVarID == this.options.imgVarID; } .bind(this));


    items.each(function(itm) {
        var sizename = itm.getSizeName();
        var id = itm.itemID;
        var stock = itm.getQuantityInStock();
        if (stock<1) sizename += " Out of Stock";

        var opt = new Element("option", { 'value': id });
        opt.setHTML(sizename);
        if (stock < 1) opt.addClass('disabledOption');

        opt.injectInside(this.itemsDdl);

    } .bind(this));
}

    // this is the method that is called to set a new main detail image triggering the opacity transition
, setNextSrc: function(newSrc) {
    var thisHost = location.protocol + '//' + location.host;
    if (window.debugging) { trace('ProductManager.setNextSrc: %o %o', thisHost, this.mainImg.src); }
    if (newSrc != this.mainImg.src.replace(thisHost, '')) {
        this.nextSrc = newSrc;
        this.transitionMainImg();
    }
}

, transitionMainImg: function() {
    if (window.debugging) { trace('ProductManager.transitionMainImg: %o', this.nextSrc); }
    this.mainImgFx.start(1, 0);
}

, loadMainImg: function() {
    if (window.debugging) { trace('ProductManager.loadMainImg: %o %o', this.nextSrc, this.imgContainer.getStyle('opacity')); }

    if (this.imgContainer.getStyle('opacity') < 0.1) { // only start if we just completed a transition to 0
        if (!this.displayImage.hasKey(this.nextSrc)) { // add the asset to the hash table if not there, and show when loaded
            this.displayImage.set(this.nextSrc, new Asset.image(this.nextSrc, { id: this.mainImg.id, onload: this.showMainImg.bind(this, this.nextSrc) }));
        }
        else {
            this.showMainImg();
        } // otherwise begin the transition back
    }
}

, showMainImg: function() {
    if (window.debugging) { trace('ProductManager.showMainImg: %o', this.nextSrc); }
    this.mainImgFx.set(0);
    this.mainImg.setProperty('src', this.displayImage.get(this.nextSrc).getProperty('src'));
    this.mainImgFx.start(0, 1);

    try {
        window.fixTabs();
    } catch (e) {

    }
}

    // grabs the selected ddl vals and tries to find a match in our items
, setCurrentItem: function() {
    if (window.debugging) { trace('ProductManager.setCurrentItem(): img' + this.imgVarPath.replace(/\{0\}/, this.options.productID).replace(/\{1\}/, this.options.imgVarID)); }
    this.currItem = null;

    // set the main image
    this.setNextSrc(this.imgVarPath.replace(/\{0\}/, this.options.productID).replace(/\{1\}/, this.options.imgVarID));

    // populate the detail images
    // find the imgvar in this.imgVars
    this.iv = this.imgVars.filter(function(item, index) { return item.imgVarID === this.options.imgVarID; } .bind(this));


    // if this imgvar has no details, find the first imgvar that does
    if (this.iv[0].details.length == 0) { this.iv = this.imgVars.filter(function(item, index) { return item.details.length > 0; }); }

    if ($chk(this.iv[0]) && this.iv[0].details.length > 0) {

        // clear out the detail imgs
        this.pnlDetail.empty();

        // add this imgvar
        var span = new Element('span', { 'class': 'views' });
        span.appendText('Views');
        span.injectInside(this.pnlDetail);

        var div;
        if (this.iv[0].details.length > 0) {
            div = new Element('div', { styles: { 'border-style': 'solid', 'border-color': '#D0D0D0', 'border-width': '1px 0px 1px 1px', 'padding': '4px 0px 0px 4px', 'height': '50px', 'width': '50px', 'float': 'left'} });
        } else {
            div = new Element('div', { styles: { 'border-style': 'solid', 'border-color': '#D0D0D0', 'border-width': '1px 1px 1px 1px', 'padding': '4px 0px 0px 4px', 'height': '50px', 'width': '50px', 'float': 'left'} });
        }

        var img = new Element('img', { src: this.imgVarThumbPath.replace(/\{0\}/, this.options.productID).replace(/\{1\}/, this.options.imgVarID), styles: { 'cursor': 'pointer', 'width': '45px'} }).addEvents({ 'click': this.setNextSrc.bind(this, this.imgVarPath.replace(/\{0\}/, this.options.productID).replace(/\{1\}/, this.options.imgVarID)) })

        div1 = new Element('div', { styles: { 'height': '45px', 'width': '45px', 'overflow': 'hidden'} });

        img.injectInside(div1);
        div1.injectInside(div);

        div.injectInside(this.pnlDetail);

        var index = 1;
        // add all details for the found img var
        this.iv[0].details.each
        (
            function(item, ix) {
                item.div = new Element('div', { styles: { 'border-style': 'solid', 'border-color': '#D0D0D0', 'border-width': '1px 0px 1px 1px', 'padding': '4px 0px 0px 4px', 'height': '50px', 'width': '50px', 'float': 'left'} });

                if (ix == (this.iv[0].details.length - 1))
                    item.div = new Element('div', { styles: { 'border-style': 'solid', 'border-color': '#D0D0D0', 'border-width': '1px 1px 1px 1px', 'padding': '4px 0px 0px 4px', 'height': '50px', 'width': '50px', 'float': 'left'} });

                if (index > 3) {
                    if (ix == (this.iv[0].details.length - 1))
                        item.div = new Element('div', { styles: { 'border-style': 'solid', 'border-color': '#D0D0D0', 'border-width': '0px 1px 1px 1px', 'padding': '4px 0px 0px 4px', 'height': '50px', 'width': '50px', 'float': 'left'} });
                    else
                        item.div = new Element('div', { styles: { 'border-style': 'solid', 'border-color': '#D0D0D0', 'border-width': '0px 0px 1px 1px', 'padding': '4px 0px 0px 4px', 'height': '50px', 'width': '50px', 'float': 'left'} });
                }
                else {
                    if (index > 1)
                        item.div = new Element('div', { styles: { 'border-style': 'solid', 'border-color': '#D0D0D0', 'border-width': '1px 1px 1px 0px', 'padding': '4px 0px 0px 4px', 'height': '50px', 'width': '50px', 'float': 'left'} });
                    else
                        item.div = new Element('div', { styles: { 'border-style': 'solid', 'border-color': '#D0D0D0', 'border-width': '1px 1px 1px 1px', 'padding': '4px 0px 0px 4px', 'height': '50px', 'width': '50px', 'float': 'left'} });
                }

                index = index + 1;

                item.img = new Element('img', { src: this.detailThumbPath.replace(/\{0\}/, this.options.productID).replace(/\{1\}/, this.iv[0].imgVarID).replace(/\{2\}/, item.detailID), styles: { 'cursor': 'pointer', 'width': '45px'} }).addEvents({ 'click': this.setNextSrc.bind(this, this.detailPath.replace(/\{0\}/, this.options.productID).replace(/\{1\}/, this.iv[0].imgVarID).replace(/\{2\}/, item.detailID))
                });

                item.div2 = new Element('div', { styles: { 'height': '45px', 'width': '45px', 'overflow': 'hidden'} });
                item.img.injectInside(item.div2);
                item.div2.injectInside(item.div);
                item.div.injectInside(this.pnlDetail);

            } .bind(this)
         );
    }

    // get a list of the possible group vars for this item
    /* old version
    var currGroupVarIDs = [];
    this.groupDdls.each(function(el) {
    currGroupVarIDs.include(el.getValue().toInt());
    } .bind(currGroupVarIDs));

    var i = 0;
    while ((this.currItem == null) && (i < this.items.length)) {
    this.currItem = this.items[i++].matchItem(this.options.imgVarID, currGroupVarIDs);
    }
    */

    var itmID;
    //if (this.itemsDdl.length > 0)
        itmID = this.itemsDdl.options[this.itemsDdl.selectedIndex].value.toInt();
    //else
    //    itmID = -1;
    var i = 0;
    while ((this.currItem == null) && (i < this.items.length)) {
        var item = this.items[i++];
        if (item.itemID == itmID) this.currItem = item;
    }


    this.updateStockEmailSubject();


    if (window.debugging) { trace('ProductManager.setCurrentItem() ' + this.currItem); }

    if ((this.currItem != null) && (this.currItem.quantityInStock > 0)) {
        if (window.debugging) { trace('ProductManager.setCurrentItem(): this.currItem.quantityInStock : %o', this.currItem.quantityInStock); }
        this.qtyText.disabled = false;
        this.addButton.setStyle('cursor', 'pointer');
        this.qtyText.value = 1;
        $('quantityRow').setStyle('display', 'block');
        this.stockmaillink.setStyle('display', 'none');
        this.stockmessage.setStyle('display', 'none');
    } else {
        this.qtyText.value = 0;
        this.addButton.setStyle('cursor', 'default');
        this.qtyText.disabled = true;
        $('quantityRow').setStyle('display', 'none');
        this.stockmaillink.setStyle('display', 'block');
        this.stockmessage.setStyle('display', 'block');
    }

    if (window.debugging) { trace('  ** quantityRow ' + $('quantityRow')); }

    if (this.options.showZeroStock) {
        this.addButton.disabled = ((this.currItem == null) || (this.currItem.quantityInStock <= 0));
        this.addButton.setProperty(
        ($chk(this.addButton.getProperty('src')) ? 'src' : 'value')
        , this.currItem == null ? this.options.messageNoZeroNotAnItem : ((this.currItem.quantityInStock <= 0) ? this.options.messageNoZeroOutOfStock : this.options.messageAdd)
      );
    } else {
        this.addButton.disabled = (this.currItem == null);
        this.addButton.setProperty(
        ($chk(this.addButton.getProperty('src')) ? 'src' : 'value')
        , this.currItem == null ? this.options.messageZeroUnavailable : this.options.messageAdd
      );
    }

    if (this.currItem != null) {
        // set up the price
        this.pnlPrice.setHTML();
        new Element('span', { 'class': 'pounds' }).setHTML('&#163;' + this.currItem.getCartPrice()).injectInside(this.pnlPrice);

        if (this.convEuro > 0)
            new Element('span', { 'class': 'euro' }).setHTML('&euro;' + (this.convEuro * this.currItem.getCartPrice()).round()).injectInside(this.pnlPrice);

        if (this.convYen > 0)
            new Element('span', { 'class': 'yen' }).setHTML('&yen;' + (this.convYen * this.currItem.getCartPrice()).round()).injectInside(this.pnlPrice);

        var onSaleVis = this.pnlOnSale.getStyle('opacity') > 0.1;
        var currItemOnSale = this.currItem.onSale == true;

        // if onsale panel is visible and curritem is onsale, do nothing
        // if onsale panel is nto visible and curritem is not onsale, do nothing
        // if onsale panel is visible and curritem is not onsale, fade out
        if (onSaleVis && !currItemOnSale) { this.pnlOnSaleFx.start(1, 0); }
        // if onsale panel is not visible and curritem is onsale, fade in
        if (!onSaleVis && currItemOnSale) { this.pnlOnSaleFx.start(0, 1); }

        if (currItemOnSale) {
            new Element('br').injectInside(this.pnlPrice);
            var oldPrice = new Element('small').injectInside(new Element('div')).injectInside(this.pnlPrice);
            new Element('span', { 'class': 'pounds strike' }).setHTML('&#163;' + this.currItem.getPrice()).injectInside(oldPrice);
            if(this.convEuro > 0)
                new Element('span', { 'class': 'euro strike' }).setHTML('&euro;' + (this.convEuro * this.currItem.getPrice()).round()).injectInside(oldPrice);
            if(this.convYen > 0)
                new Element('span', { 'class': 'yen strike' }).setHTML('&yen;' + (this.convYen * this.currItem.getPrice()).round()).injectInside(oldPrice);
        }
    }

}

, getGroupVarInfoByID: function(_id) {

    var groups = this.options.groups;
    var group, groupVar, groupVars = null;

    var retObj = {};
    retObj.groupName = null;
    retObj.groupID = null;
    retObj.varName = null;

    var len = groups.length;
    for (i = 0; i < len; i++) {
        group = groups[i];
        groupVar = null;
        groupVars = null;
        if (group) {

            groupVars = group.groupVars;

            var glen = groupVars.length;
            for (j = 0; j < glen; j++) {
                groupVar = groupVars[j];
                if (groupVar.groupVarID == _id) {
                    retObj.groupID = group.groupID;
                    retObj.groupName = group.name;
                    retObj.varName = groupVar.name;
                    return retObj;
                }
            }

        }
    }
    return null;
}

    // tells the cartmanager to attempt to add the item to the cart
, setCartItem: function(e) {

    if ((this.currItem != null) && (this.currItem.getQuantityInStock() > 0)) {
        qtyValid = /^\d+$/;
        if (qtyValid.test(this.qtyText.getValue())) {

            var qty = this.qtyText.getValue().toInt();
            if (qty > this.currItem.getQuantityInStock()) {
                qty = this.currItem.getQuantityInStock();
            }

            var cartItem = new CartItem(this.productName, this.currItem.description, this.currItem.itemID, this.currItem.getCartPrice(), qty);
            if (window.debugging) { trace("Product this.cartManager " + this.cartManager); }
            this.cartManager.requestAddCartItem(cartItem);

            this.addButton.src = this.options.messageBusy;
            this.addButton.disabled = true;
        }

        this.qtyText.setProperty('value', 1);
    }
}

, getProductItems: function() {
    // make the ajax request to update the productItems from the database
    this.productRequest = new ProductRequest({ requestURL: this.options.productRequestUrl, productID: this.options.productID, attempts: 1 });
    this.addProductRequestListeners();
    this.productRequest.request();
}

, onProductRequestSuccess: function(evt) {
    if (window.debugging) { trace('ProductManager.onProductRequestSuccess(): %o', evt.target.ajaxResponse.items); }
    this.removeProductRequestListeners();
    this.setItems(evt.target.ajaxResponse.items);
    this.setCurrImgVar();
    //this.setCurrentItem();
}

, onProductRequestFail: function(evt) {
    if (window.debugging) { trace('ProductManager.onProductRequestFail(): %o', evt.target); }
    this.removeProductRequestListeners();
    this.setItems(evt.target.ajaxResponse.items);
    this.setCurrImgVar();
    //this.setCurrentItem();
}

, addProductRequestListeners: function() {
    this.productRequest.addEvent('onRequestSuccess', this.onProductRequestSuccess.bind(this));
    this.productRequest.addEvent('onRequestFail', this.onProductRequestFail.bind(this));
    this.productRequest.addEvent('onRequestTimeout', this.onProductRequestFail.bind(this));
    this.productRequest.addEvent('onDestroy', this.onRequestDestroy.bind(this));
}

, removeProductRequestListeners: function() {
    this.productRequest.removeEvent('onRequestSuccess', this.onProductRequestSuccess);
    this.productRequest.removeEvent('onRequestFail', this.onProductRequestFail);
    this.productRequest.removeEvent('onRequestTimeout', this.onProductRequestFail);
    this.productRequest.removeEvent('onDestroy', this.onRequestDestroy);
}

, onRequestDestroy: function() {
}

, onCartItemUpdateSuccess: function(_event) {
    if (window.debugging) { trace('ProductManager.onCartItemUpdateSuccess()'); }
    // update the productItems from the database
    this.getProductItems();
}

, onCartItemUpdateFail: function(_event) {
    if (window.debugging) { trace('ProductManager.onCartItemUpdateFail()'); }
}

    // regular moo defnd object toString function
, toString: function() {
    var output = '';
    this.items.each(function(el) { output += 'itemID: ' + el.itemID + ' desc: ' + el.description; });
    return output;
}

    // makes sure that the cartmanager is of the correct type
    // remove listeners from old one (if any) add to new
, setCartManager: function(_cartManager) {
    if (window.debugging) { trace("Product setCartManager _cartManager " + _cartManager); }
    if ((_cartManager instanceof CartManager) && (_cartManager != this.cartManager)) {
        if (this.cartManager) {
            this.cartManager.removeEvent('onCartItemUpdateSuccess', this.onCartItemUpdateSuccess);
            this.cartManager.removeEvent('onCartItemUpdateFail', this.onCartItemUpdateFail);
        }
        this.cartManager = _cartManager;
        this.cartManager.addEvent('onCartItemUpdateSuccess', this.onCartItemUpdateSuccess.bind(this));
        this.cartManager.addEvent('onCartItemUpdateFail', this.onCartItemUpdateFail.bind(this));
    }
    else {
        if (window.debugging) { trace("Type mismatch in Product.setCartManager()."); }
    }
}

});

ProductManager.implement(new Options);


var ProductRequest = AjaxRequest.extend({
  
  options: {
    productID: false
  }
  
, initialize: function(options) {

    this.parent(options);
    this.setOptions(options);
    
    if (window.debugging) { trace("ProductRequest.initialize(): requestURL: " + this.options.requestURL + "; productID: " + this.options.productID + "; attempts: " + this.options.attempts); }
    
    // make sure enough data passed in to create request
    if (!this.options.productID || !this.options.requestURL) {
      if (window.debugging) trace('ProductRequest.initialize(): not enough arguments - destroying');
      this.destroy();
      return;
    }
    
    this.prepAjax();
  
  },

  prepAjax: function() {
    this.ajax = new Ajax(this.getRequestURL(), {
        method: 'post'
       ,data:       'productID=' + this.getProductID()
       ,onRequest:     this.onRequestStart.bind(this)
       ,onStateChange:   this.onRequestStateChange.bind(this)
       ,onSuccess:     this.onRequestSuccess.bind(this)
       ,onFailure:     this.onRequestFail.bind(this)
    });
  },
  
  
  getProductID: function() {
    return this.options.productID;
  },
  
  setproductID: function(_productID) {
    if (_productID) {
      this.options.cartID = _productID;
    }
  }
  
});



// takes the passed ul and grabs the first maxPerRow li's and puts the remainder in a new acoordion-able ul with toggler

var ProductList = new Class({

  options: {
    maxPerRow: 7
  }
  
, initialize: function(listElements,propagateLinks) {
    this.listElements = ($type(listElements) == 'array') ? listElements : $$(listElements);
    this.propagateLinks = $defined(propagateLinks)? propagateLinks : true;
    this.storeHoverManager = new StoreHoverManager();
    this.listElements.each(this.setupList.bind(this));
    this.accordion = null;
    
    if ($chk($('accordion'))) {
      this.setupAccordion();
    }

  }
  
, setupList: function(listElement, i) {
    if (window.debugging) trace('ProductList.setupList()');
    // make a copy of the listItems and remove from the listElement;
    var newItems = listElement.getElements('li').clone();
    
    // setup the hovers    
    newItems.each(this.setupHovers.bind(this));
    
    listElement.empty();
    
    var newList = listElement.clone();
    var currCount = 0;
    var maxItems = newItems.length;

    // grab the first maxPerRow li's    
    for (currCount = 0; currCount < maxItems && currCount < this.options.maxPerRow; currCount++)
    {
      newItems[currCount].injectInside(listElement);
    }

    // show 'more' button if maxItems > currCount
    if (maxItems > currCount) {
    
      var toggler = new Element('h4', { 'class': 'toggler atStart' });
      new Element('span').appendText('More').injectInside(toggler);
      toggler.injectAfter(listElement);
      
      // create a new ul.storeProducts and inject remaining inside
      var div = new Element('div', {'class': 'atStart'}).injectAfter(listElement);
      newList.injectInside(div);
      for (i = currCount; i < maxItems; i++)
      {
        newItems[i].injectInside(newList);
      }
      
    }

  }
  
, setupHovers: function(listItem, i) {
    var tempStoreItem = new StoreHover(listItem,{propagateLinks:this.propagateLinks});
    if (window.debugging) trace('ProductList.setupHovers(): %o' + tempStoreItem);
    this.storeHoverManager.addStoreHover(tempStoreItem);
    tempStoreItem.setItemIndex( this.storeHoverManager.inStoreHovers(tempStoreItem) );
    tempStoreItem.setBodyElem($('body'));
  }
  
, setupAccordion: function() {
    // set up the accordion
      this.accordion = new Accordion('h4.atStart', 'div.atStart', {
          opacity: false,
          display: -1,
          onActive: function(toggler, element){
              toggler.setStyle('visibility', 'hidden');
              element.setStyle('visibility', 'visible');
          },
          onBackground: function(toggler, element){
              toggler.setStyle('visibility', 'visible');
              element.setStyle('visibility', 'hidden');
          }
      }, $('accordion'));
      window.addEvent('load', function(){
            this.accordion.display(0);
      }.bind(this));
  }
  
});

ProductList.implement(new Options);
