// just something quick to avoid weirdness on the first mouseover
var img1 = new Image();
img1.src = '/images/shell/navigation-over.gif';



// Define what a FenceType should respond to, set out _basic_ functionality
// Each fence type with its associated product dont have codes that we can build in an ad hoc manner

// The basic idea of this class is to build up 2 sets of data:
// 1 - Human readable codes along with product names that represent dropdown items. They will be parsed in getMaterials(). The concatenated codes will _not_ be real product codes.
// 2 - A map of the _parsed_ human readable codes, along with their real product code equivelants. Used to translate dropdown choices into a bill of materials.

var FenceType = Class.create();
FenceType.prototype = {
   initialize: function(name){
      this.name = name;
      this.vals = {};
      this.finishes = {};
      this.heights = {};
      this.options = {};
      this.mapping = {};
      
      this.spacingMinimum = 0;
      this.spacingMaximum = 0;
   },
   
   // all types have finishes, this is used to populate the dropdown and build the bill of materials.
   // for readability on page load finishes are a simple key-value dict with 2 entries: code and name.
   addFinishes: function(finishes){
      for(var i = 0; i < finishes.length; i++){
         this.addFinish(finishes[i]);
      }
   },
   addFinish: function(f){
      this.finishes[f.code] = f.name;
   },
   getFinishes: function() {
      var result = [];
      for(var finish in this.finishes){
         result.push({code: finish, name: this.finishes[finish]});
      }
      return result;
   },
   
   // all types have heights, this is used to populate the dropdown and build the bill of materials.
   // there are 4 heights in total, but not every type is available at each height.
   // for readability on page load heights are a simple key-value dict with 2 entries: code and name.
   addHeights: function(heights){
      for(var i = 0; i < heights.length; i++){
         this.addHeight(heights[i]);
      }
   },
   addHeight: function(h){
      this.heights[h.code] = h.name;
   },
   getHeights: function() {
      var result = [];
      for(var height in this.heights){
         result.push({code: height, name: this.heights[height]});
      }
      return result;
   },
   
   // all types have options, this is used to populate the dropdown and build the bill of materials.
   // for readability on page load options are a simple key-value dict with 2 entries: code and name.
   // note: code _might_ not be used in the building of other product codes like type and finish are.
   addOptions: function(options){
      for(var i = 0; i < options.length; i++){
         this.addOption(options[i]);
      }
   },
   addOption: function(o){
      this.options[o.code] = o.name;
   },
   getOptions: function() {
      var result = [];
      for(var option in this.options){
         result.push({code: option, name: this.options[option]});
      }
      return result;
   },
   
   // all types have mappings, these translate dropdown choices into product codes
   // for readability on page load options are a simple key-value dict with 2 entries: code and prodCode.
   addMappings: function(map){
      for(var i = 0; i < map.length; i++){
         this.addMapping(map[i]);
      }
   },
   addMapping: function(m){
      this.mapping[m.code] = m.productCode;
   },
   getMappings: function() {
      var result = [];
      for(var map in this.mapping){
         result.push({code: map, prodCode: this.mapping[map]});
      }
      return result;
   },
   
   // these define validation rules on the configurator
   // spacing also affects the bill of materials
   setSpacingMinimum: function(n) {
      if(isFinite(n) && n >= 0)
         this.spacingMinimum = n;
   },
   setSpacingMaximum: function(n) {
      if(isFinite(n) && n >= 0)
         this.spacingMaximum = n;
   },
   
   // values given by the configurator are used to build the bill of materials
   setValues: function(vals){
      this.vals = vals;
   },
   
   // gives back an array of product codes/quantities based on configurator data
   // this will be overridden by subclasses to suit their particular needs
   getMaterials: function(){
      var vals = this.vals;
      var result = [];
      // do stuff with vals
      return result;
   },
   // Translates output from the selectors into an actual product code
   translateCode: function(code){
      return this.mapping[code];
   },
   extraValidation: function(typeSel, finishSel, heightSel, optionsSel, spacingSel, lengthSel){
      // on the fly validation rules
   }
}


PostAndRail = Class.create();
Object.extend(PostAndRail.prototype, FenceType.prototype);
Object.extend(PostAndRail.prototype, {
   initialize: function(name) {
      FenceType.prototype.initialize.call(this, name);
   },
   // bill of materials for a post and rail fence
   getMaterials: function(){
      var vals = this.vals;
      var result = [];
      // IMPORTANT: rail length is a product of the option selected!!!
      var railLength = vals.options.split('_')[1];
      var finish = vals.finish;
      var height = vals.height;
      var len = vals.len;
      var spacing = vals.spacing;
      var numSheets = Math.ceil(len / 0.76);
      var numPosts = Math.ceil(len / spacing) + 1;
      var numRails = Math.ceil(len / railLength) * 2; // rails are either 5 or 7.5m
      var numSaddles = numPosts * 2; // saddles support the rails
      var numJoiner = numRails - 2;
      var numFenceCaps = Math.ceil(len / 2.4);
      
      var colouredscrews = {
         quantity: 0,
         code: this.translateCode("SCREW-" + finish)
      };
      
      // Sheets
      result.push({
         quantity: numSheets,
         code: this.translateCode("SHEET-" + finish + "-" + height)
      });
      // 8 screws per sheet
      colouredscrews.quantity += numSheets * 8;
      
      // posts
      result.push({
         quantity: numPosts,
         code: this.translateCode("POST-" + height)
      });
      // 4 screws per post
      colouredscrews.quantity += numPosts * 4;
      
      // post caps
      result.push({
         quantity: numPosts,
         code: this.translateCode("POSTCAP")
      });
      
      // 2 saddles per post
      result.push({
         quantity: numSaddles,
         code: this.translateCode("SADDLE")
      });
      
      // rails
      result.push({
         quantity: numRails,
         code: this.translateCode("RAIL")
      });
      // every rail comes with a joiner
      // number of rails - 2, this is because there are 2 rails on a fence, the last ones aren't joined to anything
      result.push({
         quantity: numJoiner,
         code: this.translateCode("RAILJOINER")
      });
      // 2 screws per joiner
      colouredscrews.quantity += numJoiner * 2;
      
      // if caps selected
      if(vals.options.indexOf('CAPS') > -1){
         // fence caps are 2.4m long
         result.push({
            quantity: numFenceCaps,
            code: this.translateCode("CAP-" + finish)
         });
         // 4 screws per cap, coloured
         colouredscrews.quantity += numFenceCaps * 4;
      }
      
      colouredscrews.quantity = Math.ceil(colouredscrews.quantity / 50) * 50;
      if(colouredscrews.quantity > 0)
         result.push(colouredscrews);
      return result;
   }
});

Friendly = Class.create();
Object.extend(Friendly.prototype, FenceType.prototype);
Object.extend(Friendly.prototype, {
   initialize: function(name) {
      FenceType.prototype.initialize.call(this, name);
   },
   // bill of materials for a neighbour friendly fence
   getMaterials: function(){
      var vals = this.vals;
      var result = [];
      var finish = vals.finish;
      var height = vals.height;
      var sheetHeight = vals.height;
      var len = vals.len;
      var spacing = vals.spacing;
      var panels = Math.ceil(len / spacing);
      var opt = vals.options;
      var lattice = opt == 'LATTICE';
      
      // reduce sheet height if there is a lattice
      if(lattice){
         if(sheetHeight == '1.8M')
            sheetHeight = '1.5M';
         else
            sheetHeight = '1.8M';
         result.push({
            quantity: panels, 
            code: this.translateCode("LATTICE-" + finish)
         });
      }
      
      var screws = {
         quantity: (lattice ? 16 + 8 : 16) * panels,
         code: this.translateCode("SCREW-" + finish)
      };
      
      // Sheets
      result.push({
         quantity: panels * 3, 
         code: this.translateCode("SHEET-" + finish + "-" + sheetHeight)
      });
      
      // posts
      result.push({
         quantity: panels * 2,
         code: this.translateCode("POST-" + finish + '-' + height)
      });
      
      // rails
      result.push({
         quantity: (lattice ? 3 : 2) * panels,
         code: this.translateCode("RAIL-" + finish)
      });
      
      screws.quantity = Math.ceil(screws.quantity / 50) * 50;
      if(screws.quantity > 0)
         result.push(screws);
      return result;
   },
   extraValidation: function(typeSel, finishSel, heightSel, optionsSel, spacingSel, lengthSel){
      // on the fly validation rules
      
      // spacing is always constant on friendly fences.
      spacingSel.value = this.spacingMaximum;
      spacingSel.fire('custom:keyup');
      spacingSel.disable();
      
      // if the height is 2.1m, force lattice
      if(heightSel.value == '2.1M'){
         var options = optionsSel.getElementsBySelector('option');
         options[2].selected = true;
         optionsSel.selectedIndex = 2;
         optionsSel.fire('custom:change');
         optionsSel.disable();
      } else {
         optionsSel.enable();
         optionsSel.fire('custom:change');
      }
   }
});

var Configurator = Class.create();
Configurator.prototype = {
   initialize: function() {
      this.typeSel =  $('fence_type');
      Event.observe(this.typeSel, 'change', this.typeSelected.bind(this));
      this.finishSel =  $('fence_finish');
      this.heightSel =  $('fence_height');
      Event.observe(this.heightSel, 'change', this.heightSelected.bind(this));
      this.spacingSel =  $('fence_spacing');
      this.lengthSel =  $('fence_length');
      this.optionsSel =  $('fence_options');
      this.errBox =  $('fence_error');
      
      this.clearBut =  $('fence_clear');
      this.addBut =  $('fence_add');
      Event.observe(this.clearBut, 'click', this.clear.bind(this));
      Event.observe(this.addBut, 'click', this.addToCart.bind(this));
      
      // configurator data comes from the type
      this.types = [];
   },
   // returns an object with all out input values
   getValues: function(){
      var result = {type: null, finish: null, height: null, spacing: null, len: null, options: null};
      result.type = this.typeSel.value;
      result.finish = this.finishSel.value;
      result.height = this.heightSel.value;
      result.spacing = parseFloat(this.spacingSel.value) || '';
      result.len = parseFloat(this.lengthSel.value) || '';
      result.options = this.optionsSel.value;
      return result;
   },
   // this clears the form
   clear: function(){
      this.clearPartial();
      this.typeSel.enable();
      this.typeSel.value = -1;
      this.typeSel.fire('custom:change');
   },
   // clears all but the type selector, useful for when the type changes.
   clearPartial: function(){
      this.errBox.update('');
      this.finishSel.enable();
      this.heightSel.enable();
      this.optionsSel.enable();
      this.spacingSel.enable();
      this.lengthSel.enable();
      this.finishSel.value = -1;
      this.heightSel.value = -1;
      this.optionsSel.value = -1;
      this.spacingSel.value = "";
      this.lengthSel.value = "";
      this.spacingSel.fire('custom:keyup');
      this.lengthSel.fire('custom:keyup');
      
      while(this.finishSel.getElementsBySelector('option').length > 1){
         var opts = this.finishSel.getElementsBySelector('option');
         var opt = opts[opts.length - 1];
         opt.parentNode.removeChild(opt);
      }
      this.finishSel.fire('custom:change');
      while(this.heightSel.getElementsBySelector('option').length > 1){
         var opts = this.heightSel.getElementsBySelector('option');
         var opt = opts[opts.length - 1];
         opt.parentNode.removeChild(opt);
      }
      this.heightSel.fire('custom:change');
      while(this.optionsSel.getElementsBySelector('option').length > 1){
         var opts = this.optionsSel.getElementsBySelector('option');
         var opt = opts[opts.length - 1];
         opt.parentNode.removeChild(opt);
      }
      this.optionsSel.fire('custom:change');
   },
   heightSelected: function(){
      var vals = this.getValues();
      var type = this.types[vals.type];
      if(type){
         type.extraValidation(
            this.typeSel,
            this.finishSel,
            this.heightSel,
            this.optionsSel,
            this.spacingSel,
            this.lengthSel
         );
      }
   },
   //handler for type selector, rebuilds other selectors
   typeSelected: function(){
      var vals = this.getValues();
      this.clearPartial();
      var type = this.types[vals.type];
      if(type){
         // rebuild selectors, default to the first option of each
         var finishes = this.codesToOptions(type.getFinishes());
         var heights = this.codesToOptions(type.getHeights());
         var options = this.codesToOptions(type.getOptions());
         for(var i = 0; i < finishes.length; i++){
            this.finishSel.insert(finishes[i]);
            if(i == 0){
               this.finishSel.childElements()[0].selected = true;
               this.finishSel.fire('custom:change');
            }
         }
         for(var i = 0; i < heights.length; i++){
            this.heightSel.insert(heights[i]);
            if(i == 0){
               this.heightSel.childElements()[0].selected = true;
               this.heightSel.fire('custom:change');
            }
         }
         for(var i = 0; i < options.length; i++){
            this.optionsSel.insert(options[i]);
            if(i == 0){
               this.optionsSel.childElements()[0].selected = true;
               this.optionsSel.fire('custom:change');
            }
         }
         type.extraValidation(
            this.typeSel,
            this.finishSel,
            this.heightSel,
            this.optionsSel,
            this.spacingSel,
            this.lengthSel
         );
         
         // ie7 is destroying select widths on repopulation.
         if(navigator && navigator.appVersion.indexOf('MSIE 7') > -1){
            this.finishSel.style.width = '150px';
            this.heightSel.style.width = '150px';
            this.optionsSel.style.width = '150px';
         }
      }
   },
   // transforms {code: 'asd', name: 'cake'} into html options
   codesToOptions: function(codes){
      var result = [];
      for(var i = 0; i < codes.length; i++){
         var c = codes[i];
         var attr = {
            'value': c.code,
            'style': 'color: ' + enabledColour
         }
         var opt = new Element('option', attr);
         opt.update(c.name);
         result.push(opt);
      }
      return result;
   },
   // builds a form for the bill of materials and submits it.
   addToCart: function(){
      if(this.validate()){
         var type = this.types[this.getValues().type];
         type.setValues(this.getValues());
         var materials = type.getMaterials();
         var cont = new Element('div', {style: 'display: none;'});
         var mForm = new Element('form', {method: 'POST', action: '/cart'});
         for(var i = 0; i < materials.length; i++){
            mForm.insert('<input type="hidden" name="prodcode[]" value="' + materials[i].code + '" />');
            mForm.insert('<input type="hidden" name="quan[]" value="' + materials[i].quantity + '" />');
         }
         addToCart('/cart?action=add&json=true&' + mForm.serialize(), $('fence_add'), ['fence_options', 'fence_length', 'fence_spacing', 'fence_height', 'fence_finish', 'fence_type']);
         this.errBox.insert(cont);
      }
   },
   // Check that our inputs are filled out, min-maxes are satisfied etc.
   validate: function(){
      var vals = this.getValues();
      var err = [];
      var sel = {
         t: this.typeSel.parentNode,
         f: this.finishSel.parentNode,
         h: this.heightSel.parentNode,
         o: this.optionsSel.parentNode,
         s: this.spacingSel,
         l: this.lengthSel
      };
      var originalBorder = "#00693F";
      var errorBorder = "red";
      
      sel.t.style.borderColor = originalBorder;
      sel.f.style.borderColor = originalBorder;
      sel.h.style.borderColor = originalBorder;
      sel.o.style.borderColor = originalBorder;
      sel.s.style.borderColor = originalBorder;
      sel.l.style.borderColor = originalBorder;
      
      var displayRed = [];
      // validate etc
      if(vals.type < 0){
         err.push('Fence type is required.');
         sel.t.style.borderColor = errorBorder;
      }
      if(vals.finish < 0){
         err.push('Fence finish is required.');
         sel.f.style.borderColor = errorBorder;
      }
      if(vals.height < 0){
         err.push('Fence height is required.');
         sel.h.style.borderColor = errorBorder;
      }
      if(vals.spacing < 0){
         err.push('Fence finish is required.');
         sel.s.style.borderColor = errorBorder;
      }
      var type = this.types[this.getValues().type];
      if(type && vals.spacing != ''){
         sel.s.style.borderColor = errorBorder;
         if(type.spacingMaximum == type.spacingMinimum && vals.spacing != type.spacingMaximum)
            err.push('Post spacing is restricted to ' + type.spacingMaximum + 'm for this fence type.');
         else if(vals.spacing <= 0)
            err.push('Post spacing must be greater than 0m.');
         else if(vals.spacing > type.spacingMaximum)
            err.push('Post spacing is greater than the maximum allowed: ' + type.spacingMaximum + 'm.');
         else if(vals.spacing < type.spacingMinimum)
            err.push('Post spacing is smaller than the minimum allowed: ' + type.spacingMinimum + 'm.');
         else
            sel.s.style.borderColor = originalBorder;
      } else if(vals.spacing == ''){
         err.push('Post spacing is required.');
         sel.s.style.borderColor = errorBorder;
      }
      sel.l.style.borderColor = errorBorder;
      if(vals.len == '')
         err.push('Fence length is required.');
      else if(vals.len < vals.spacing)
         err.push('Fence length cannot be shorter than the post spacing.');
      else
         sel.l.style.borderColor = originalBorder;
      if(vals.options < 0){
         err.push('Fence options is required.');
         sel.o.style.borderColor = errorBorder;
      }
      if(err.length){
         var s = [];
         s.push('<p>Your fence can\'t be added to the cart until the following problems are rectified:</p><ul><li>');
         s.push(err.join('</li><li>'));
         s.push('</li></ul>');
         this.errBox.update(s.join(''));
         return false;
      } else {
         this.errBox.update('');
         return true;
      }
   },
   addType: function(type){
      var attr = {
         'value': this.types.length,
         'style': 'color: ' + enabledColour
      };
      var opt = new Element('option', attr);
      opt.update(type.name);
      this.typeSel.insert(opt);
      this.types.push(type);
   }
};
var CoveredInput = Class.create();
CoveredInput.prototype = {
   initialize: function(input) {
      this.input = input;
      this.cover = $(document.createElement('DIV'));
      this.setup();
   },
   setup: function(){
      this.cover.update(this.input.value);
      this.input.value = '';
      this.cover.className = this.input.className;
      this.cover.addClassName('cover');
      this.input.removeClassName('default');
      this.input.parentNode.insertBefore(this.cover, this.input);
      Element.clonePosition(this.cover, this.input);
      Event.observe(this.cover, 'click', this.focusInput.bind(this));
      Event.observe(this.input, 'blur', this.blurInput.bind(this));
      Event.observe(this.input, 'keydown', this.changeInput.bind(this));
      Event.observe(this.input, 'keyup', this.changeInput.bind(this));
      // cannot manually call native events using Event.fire()
      Event.observe(this.input, 'custom:keyup', this.changeInput.bind(this));
   },
   focusInput: function(e){
      this.cover.addClassName('coverclear');
      this.input.focus();
   },
   blurInput: function(e){
      if(this.input.value == '')
         this.cover.show();
      if(this.cover.className.indexOf('coverclear') > -1)
         this.cover.removeClassName('coverclear');
   },
   changeInput: function(e){
      if(this.input.value != ''){
         this.cover.hide();
         if(this.cover.className.indexOf('coverclear') > -1)
            this.cover.removeClassName('coverclear');
      } else {
         this.cover.show();
      }
   }
};
var coveredInputs = [];
var fence = null;
var disabledColour = '#939393';
var enabledColour = 'black';
var selectHandle = function(e){
   var el = $(this);
   if(el.value != -1){
      el.style.color = enabledColour;
   } else {
      el.style.color = disabledColour;
   }
}

Event.observe(window, 'load', function() {
   // set up text inputs with special behavior
   var inputs = $(document.body).getElementsBySelector('input.default');
   for(var i = 0; i < inputs.length; i++){
      coveredInputs.push(new CoveredInput(inputs[i]));
   }
   
   // Set up listeners and colours for select boxes
   var inputs = $(document.body).getElementsBySelector('select');
   for(var i = 0; i < inputs.length; i++){
      var el = $(inputs[i]);
      if(el.value != -1){
         el.style.color = enabledColour;
      } else {
         el.style.color = disabledColour;
      }
      Event.observe(inputs[i], 'change', selectHandle.bind(inputs[i]));
      // cannot manually call native events using Event.fire()
      Event.observe(inputs[i], 'custom:change', selectHandle.bind(inputs[i]));
   }
   
   // set the color of meaningful options
   var inputs = $(document.body).getElementsBySelector('select option');
   for(var i = 0; i < inputs.length; i++){
      var el = $(inputs[i]);
      if(el.value != -1){
         el.style.color = enabledColour;
      } else {
         el.style.color = disabledColour;
      }
   }
   
   if($('configurator')){
      var postHeights = [
         {code: '1.5M', name: '1.5m'},
         {code: '1.8M', name: '1.8m'},
         {code: '2.1M', name: '2.1m'},
         {code: '2.4M', name: '2.4m'}
      ];
      var postFinishes = [
         {code: 'ZINC',    name: 'Zincalume'},
         {code: 'CREAM',  name: 'Smooth Cream - Domain'},
         {code: 'MERINO',   name: 'Merino Terrace'},
         {code: 'GREY', name: 'Slate Grey - Grey Ridge'},
         {code: 'RIVERGUM', name: 'Rivergum - Willow'},
         {code: 'HARVEST', name: 'Harvest - Wheat'},
         {code: 'STONE', name: 'Stone - Beige - Riversand'},
         {code: 'GREEN', name: 'Caufield Green - Evergreen'},
         {code: 'MIST', name: 'Mist Green - Meadow'},
         {code: 'BRONZE', name: 'Bronze Olive - Brushwood'},
         {code: 'IRONBARK', name: 'Ironbark - Estate'},
         {code: 'HERITAGE', name: 'Heritage - Red Oak'},
         {code: 'OCEAN', name: 'Deep Ocean - Bluestone'},
         {code: 'TEA', name: 'Tea Tree'}
      ];
      var postMappings = [
         // saddle
         {code: 'SADDLE', productCode: 'MIS3825SAD'},
         
         // screws
         {code: 'SCREW', productCode: 'TEKS1016CL3'},
         // screws -> finish
         {code: 'SCREW-ZINC', productCode: 'TEKS1016CL3'},
         {code: 'SCREW-CREAM', productCode: 'TEKS1016SC'},
         {code: 'SCREW-MERINO', productCode: 'TEKS1016ME'},
         {code: 'SCREW-GREY', productCode: 'TEKS1016SG'},
         {code: 'SCREW-RIVERGUM', productCode: 'TEKS1016RG'},
         {code: 'SCREW-HARVEST', productCode: 'TEKS1016WH'},
         {code: 'SCREW-STONE', productCode: 'TEKS1016B'},
         {code: 'SCREW-GREEN', productCode: 'TEKS1016CG'},
         {code: 'SCREW-MIST', productCode: 'TEKS1016MG'},
         {code: 'SCREW-BRONZE', productCode: 'TEKS1016BO'},
         {code: 'SCREW-IRONBARK', productCode: 'TEKS1016IB'},
         {code: 'SCREW-HERITAGE', productCode: 'TEKS1016HR'},
         {code: 'SCREW-OCEAN', productCode: 'TEKS1016MB'},
         {code: 'SCREW-TEA', productCode: 'TEKS1016TT'},
         
         {code: 'POSTCAP', productCode: 'MIS50SQC'},
         
         // caps -> finish
         {code: 'CAP-ZINC', productCode: 'CAPPCTDZA2400'},
         {code: 'CAP-CREAM', productCode: 'CAPPCTDSC2400'},
         {code: 'CAP-MERINO', productCode: 'CAPPCTDME2400'},
         {code: 'CAP-GREY', productCode: 'CAPPCTDSG2400'},
         {code: 'CAP-RIVERGUM', productCode: 'CAPPCTDRG2400'},
         {code: 'CAP-HARVEST', productCode: 'CAPPCTDW2400'},
         {code: 'CAP-STONE', productCode: 'CAPPCTDST2400'},
         {code: 'CAP-GREEN', productCode: 'CAPPCTDCG2400'},
         {code: 'CAP-MIST', productCode: 'CAPPCTDMG2400'},
         {code: 'CAP-BRONZE', productCode: 'CAPPCTDBO2400'},
         {code: 'CAP-IRONBARK', productCode: 'CAPPCTDIB2400'},
         {code: 'CAP-HERITAGE', productCode: 'CAPPCTDHR2400'},
         {code: 'CAP-OCEAN', productCode: 'CAPPCTDMB2400'},
         {code: 'CAP-TEA', productCode: 'CAPPCTDTT2400'},
         
         // rails (I think they're suposed to have finishes but I dont have codes)
         {code: 'RAIL', productCode: 'RHSG382512/5'},
         // rail joiners (ditto about finishes)
         {code: 'RAILJOINER', productCode: 'MIS3825JOIN'},
         
         // sheets -> finish -> height
         {code: 'SHEET-ZINC-1.5M', productCode: 'RFS35ZA1500TD'},
         {code: 'SHEET-ZINC-1.8M', productCode: 'RFS35ZA1800TD'},
         {code: 'SHEET-ZINC-2.1M', productCode: 'RFS35ZA2100TD'},
         {code: 'SHEET-ZINC-2.4M', productCode: 'RFS35ZA2400TD'},
         {code: 'SHEET-CREAM-1.5M', productCode: 'RFS35DSSC1500TD'},
         {code: 'SHEET-CREAM-1.8M', productCode: 'RFS35DSSC1800TD'},
         {code: 'SHEET-CREAM-2.1M', productCode: 'RFS35DSSC2100TD'},
         {code: 'SHEET-CREAM-2.4M', productCode: 'RFS35DSSC2400TD'},
         {code: 'SHEET-MERINO-1.5M', productCode: 'RFS35DSME1500TD'},
         {code: 'SHEET-MERINO-1.8M', productCode: 'RFS35DSME1800TD'},
         {code: 'SHEET-MERINO-2.1M', productCode: 'RFS35DSME2100TD'},
         {code: 'SHEET-MERINO-2.4M', productCode: 'RFS35DSME2400TD'},
         {code: 'SHEET-GREY-1.5M', productCode: 'RFS35DSSG1500TD'},
         {code: 'SHEET-GREY-1.8M', productCode: 'RFS35DSSG1800TD'},
         {code: 'SHEET-GREY-2.1M', productCode: 'RFS35DSSG2100TD'},
         {code: 'SHEET-GREY-2.4M', productCode: 'RFS35DSSG2400TD'},
         {code: 'SHEET-RIVERGUM-1.5M', productCode: 'RFS35DSRG1500TD'},
         {code: 'SHEET-RIVERGUM-1.8M', productCode: 'RFS35DSRG1800TD'},
         {code: 'SHEET-RIVERGUM-2.1M', productCode: 'RFS35DSRG2100TD'},
         {code: 'SHEET-RIVERGUM-2.4M', productCode: 'RFS35DSRG2400TD'},
         {code: 'SHEET-HARVEST-1.5M', productCode: 'RFS35DSWH1500TD'},
         {code: 'SHEET-HARVEST-1.8M', productCode: 'RFS35DSWH1800TD'},
         {code: 'SHEET-HARVEST-2.1M', productCode: 'RFS35DSWH2100TD'},
         {code: 'SHEET-HARVEST-2.4M', productCode: 'RFS35DSWH2400TD'},
         {code: 'SHEET-STONE-1.5M', productCode: 'RFS35DSB1500TD'},
         {code: 'SHEET-STONE-1.8M', productCode: 'RFS35DSB1800TD'},
         {code: 'SHEET-STONE-2.1M', productCode: 'RFS35DSB2100TD'},
         {code: 'SHEET-STONE-2.4M', productCode: 'RFS35DSB2400TD'},
         {code: 'SHEET-GREEN-1.5M', productCode: 'RFS35DSCG1500TD'},
         {code: 'SHEET-GREEN-1.8M', productCode: 'RFS35DSCG1800TD'},
         {code: 'SHEET-GREEN-2.1M', productCode: 'RFS35DSCG2100TD'},
         {code: 'SHEET-GREEN-2.4M', productCode: 'RFS35DSCG2400TD'},
         {code: 'SHEET-MIST-1.5M', productCode: 'RFS35DSMG1500TD'},
         {code: 'SHEET-MIST-1.8M', productCode: 'RFS35DSMG1800TD'},
         {code: 'SHEET-MIST-2.1M', productCode: 'RFS35DSMG2100TD'},
         {code: 'SHEET-MIST-2.4M', productCode: 'RFS35DSMG2400TD'},
         {code: 'SHEET-BRONZE-1.5M', productCode: 'RFS35DSBO1500TD'},
         {code: 'SHEET-BRONZE-1.8M', productCode: 'RFS35DSBO1800TD'},
         {code: 'SHEET-BRONZE-2.1M', productCode: 'RFS35DSBO2100TD'},
         {code: 'SHEET-BRONZE-2.4M', productCode: 'RFS35DSBO2400TD'},
         {code: 'SHEET-IRONBARK-1.5M', productCode: 'RFS35DSIB1500TD'},
         {code: 'SHEET-IRONBARK-1.8M', productCode: 'RFS35DSIB1800TD'},
         {code: 'SHEET-IRONBARK-2.1M', productCode: 'RFS35DSIB2100TD'},
         {code: 'SHEET-IRONBARK-2.4M', productCode: 'RFS35DSIB2400TD'},
         {code: 'SHEET-HERITAGE-1.5M', productCode: 'RFS35DSHR1500TD'},
         {code: 'SHEET-HERITAGE-1.8M', productCode: 'RFS35DSHR1800TD'},
         {code: 'SHEET-HERITAGE-2.1M', productCode: 'RFS35DSHR2100TD'},
         {code: 'SHEET-HERITAGE-2.4M', productCode: 'RFS35DSHR2400TD'},
         {code: 'SHEET-OCEAN-1.5M', productCode: 'RFS35DSMB1500TD'},
         {code: 'SHEET-OCEAN-1.8M', productCode: 'RFS35DSMB1800TD'},
         {code: 'SHEET-OCEAN-2.1M', productCode: 'RFS35DSMB2100TD'},
         {code: 'SHEET-OCEAN-2.4M', productCode: 'RFS35DSMB2400TD'},
         {code: 'SHEET-TEA-1.5M', productCode: 'RFS35DSZA1500TD'},
         {code: 'SHEET-TEA-1.8M', productCode: 'RFS35DSZA1800TD'},
         {code: 'SHEET-TEA-2.1M', productCode: 'RFS35DSZA2100TD'},
         {code: 'SHEET-TEA-2.4M', productCode: 'RFS35DSZA2400TD'},
         
         // posts -> height
         {code: 'POST-1.5M', productCode: 'POST1800'},
         {code: 'POST-1.8M', productCode: 'POST2100'},
         {code: 'POST-2.1M', productCode: 'POST2400'},
         {code: 'POST-2.4M', productCode: 'POST2700'}
      ];
      var corroPostMappings = [
         // caps -> finish
         {code: 'CAP-ZINC', productCode: 'CAPPZACC2400'},
         {code: 'CAP-CREAM', productCode: 'CAP-CREAM'},
         {code: 'CAP-MERINO', productCode: 'CAPPCCME2400'},
         {code: 'CAP-GREY', productCode: 'CAPPCCSG2400'},
         {code: 'CAP-RIVERGUM', productCode: 'CAPPCCRG2400'},
         {code: 'CAP-HARVEST', productCode: 'CAPPCCWH2400'},
         {code: 'CAP-STONE', productCode: 'CAPPCCST2400'},
         {code: 'CAP-GREEN', productCode: 'CAPPCCCG2400'},
         {code: 'CAP-MIST', productCode: 'CAPPCCMG2400'},
         {code: 'CAP-BRONZE', productCode: 'CAPPCCBO2400'},
         {code: 'CAP-IRONBARK', productCode: 'CAPCCIB2400'},
         {code: 'CAP-HERITAGE', productCode: 'CAPPCCHR2400'},
         {code: 'CAP-OCEAN', productCode: 'CAPPCCMB2400'},
         {code: 'CAP-TEA', productCode: 'CAPPCCTT2400'},
         
         // sheets -> finish -> height
         {code: 'SHEET-ZINC-1.5M', productCode: 'RFS35ZA1500C'},
         {code: 'SHEET-ZINC-1.8M', productCode: 'RFS35ZA1800C'},
         {code: 'SHEET-ZINC-2.1M', productCode: 'RFS35ZA2100C'},
         {code: 'SHEET-ZINC-2.4M', productCode: 'RFS35ZA2400C'},
         {code: 'SHEET-CREAM-1.5M', productCode: 'RFS35DSSC1500C'},
         {code: 'SHEET-CREAM-1.8M', productCode: 'RFS35DSSC1800C'},
         {code: 'SHEET-CREAM-2.1M', productCode: 'RFS35DSSC2100C'},
         {code: 'SHEET-CREAM-2.4M', productCode: 'RFS35DSSC2400C'},
         {code: 'SHEET-MERINO-1.5M', productCode: 'RFS35DSME1500C'},
         {code: 'SHEET-MERINO-1.8M', productCode: 'RFS35DSME1800C'},
         {code: 'SHEET-MERINO-2.1M', productCode: 'RFS35DSME2100C'},
         {code: 'SHEET-MERINO-2.4M', productCode: 'RFS35DSME2400C'},
         {code: 'SHEET-GREY-1.5M', productCode: 'RFS35DSSG1500C'},
         {code: 'SHEET-GREY-1.8M', productCode: 'RFS35DSSG1800C'},
         {code: 'SHEET-GREY-2.1M', productCode: 'RFS35DSSG2100C'},
         {code: 'SHEET-GREY-2.4M', productCode: 'RFS35DSSG2400C'},
         {code: 'SHEET-RIVERGUM-1.5M', productCode: 'RFS35DSRG1500C'},
         {code: 'SHEET-RIVERGUM-1.8M', productCode: 'RFS35DSRG1800C'},
         {code: 'SHEET-RIVERGUM-2.1M', productCode: 'RFS35DSRG2100C'},
         {code: 'SHEET-RIVERGUM-2.4M', productCode: 'RFS35DSRG2400C'},
         {code: 'SHEET-HARVEST-1.5M', productCode: 'RFS35DSWH1500C'},
         {code: 'SHEET-HARVEST-1.8M', productCode: 'RFS35DSWH1800C'},
         {code: 'SHEET-HARVEST-2.1M', productCode: 'RFS35DSWH2100C'},
         {code: 'SHEET-HARVEST-2.4M', productCode: 'RFS35DSWH2400C'},
         {code: 'SHEET-STONE-1.5M', productCode: 'RFS35DSB1500C'},
         {code: 'SHEET-STONE-1.8M', productCode: 'RFS35DSB1800C'},
         {code: 'SHEET-STONE-2.1M', productCode: 'RFS35DSB2100C'},
         {code: 'SHEET-STONE-2.4M', productCode: 'RFS35DSB2400C'},
         {code: 'SHEET-GREEN-1.5M', productCode: 'RFS35DSCG1500C'},
         {code: 'SHEET-GREEN-1.8M', productCode: 'RFS35DSCG1800C'},
         {code: 'SHEET-GREEN-2.1M', productCode: 'RFS35DSCG2100C'},
         {code: 'SHEET-GREEN-2.4M', productCode: 'RFS35DSCG2400C'},
         {code: 'SHEET-MIST-1.5M', productCode: 'RFS35DSMG1500C'},
         {code: 'SHEET-MIST-1.8M', productCode: 'RFS35DSMG1800C'},
         {code: 'SHEET-MIST-2.1M', productCode: 'RFS35DSMG2100C'},
         {code: 'SHEET-MIST-2.4M', productCode: 'RFS35DSMG2400C'},
         {code: 'SHEET-BRONZE-1.5M', productCode: 'RFS35DSBO1500C'},
         {code: 'SHEET-BRONZE-1.8M', productCode: 'RFS35DSBO1800C'},
         {code: 'SHEET-BRONZE-2.1M', productCode: 'RFS35DSBO2100C'},
         {code: 'SHEET-BRONZE-2.4M', productCode: 'RFS35DSBO2400C'},
         {code: 'SHEET-IRONBARK-1.5M', productCode: 'RFS35DSIB1500C'},
         {code: 'SHEET-IRONBARK-1.8M', productCode: 'RFS35DSIB1800C'},
         {code: 'SHEET-IRONBARK-2.1M', productCode: 'RFS35DSIB2100C'},
         {code: 'SHEET-IRONBARK-2.4M', productCode: 'RFS35DSIB2400C'},
         {code: 'SHEET-HERITAGE-1.5M', productCode: 'RFS35DSHR1500C'},
         {code: 'SHEET-HERITAGE-1.8M', productCode: 'RFS35DSHR1800C'},
         {code: 'SHEET-HERITAGE-2.1M', productCode: 'RFS35DSHR2100C'},
         {code: 'SHEET-HERITAGE-2.4M', productCode: 'RFS35DSHR2400C'},
         {code: 'SHEET-OCEAN-1.5M', productCode: 'RFS35DSMB1500C'},
         {code: 'SHEET-OCEAN-1.8M', productCode: 'RFS35DSMB1800C'},
         {code: 'SHEET-OCEAN-2.1M', productCode: 'RFS35DSMB2100C'},
         {code: 'SHEET-OCEAN-2.4M', productCode: 'RFS35DSMB2400C'},
         {code: 'SHEET-TEA-1.5M', productCode: 'RFS35DSZA1500C'},
         {code: 'SHEET-TEA-1.8M', productCode: 'RFS35DSZA1800C'},
         {code: 'SHEET-TEA-2.1M', productCode: 'RFS35DSZA2100C'},
         {code: 'SHEET-TEA-2.4M', productCode: 'RFS35DSZA2400C'}
      ];
      var friendlyMappings = [
         {code: 'RAIL-ZINC', productCode: 'SFP0012'},
         {code: 'RAIL-CREAM', productCode: 'SFP0009'},
         {code: 'RAIL-MERINO', productCode: 'SFP0010'},
         {code: 'RAIL-GREY', productCode: 'SFP0008B'},
         {code: 'RAIL-RIVERGUM', productCode: 'SFP0011'},
         {code: 'RAIL-HARVEST', productCode: 'SFP2370RHA'},
         {code: 'RAIL-STONE', productCode: 'SFP0008'},
         {code: 'RAIL-GREEN', productCode: 'SFP0008A'},
         {code: 'RAIL-MIST', productCode: 'SFP0013'},
         {code: 'RAIL-BRONZE', productCode: 'SFP2370RBO'},
         {code: 'RAIL-IRONBARK', productCode: 'SFP2370RIB'},
         {code: 'RAIL-HERITAGE', productCode: 'SFP2370RHR'},
         {code: 'RAIL-OCEAN', productCode: 'SFP2370RDO'},
         {code: 'RAIL-TEA', productCode: 'SFP2370RTT'},
         
         {code: 'LATTICE-ZINC', productCode: 'SFZ0011'},
         {code: 'LATTICE-CREAM', productCode: 'SFZ0008'},
         {code: 'LATTICE-MERINO', productCode: 'SFZ0009'},
         {code: 'LATTICE-GREY', productCode: 'SFZ2370LSG'},
         {code: 'LATTICE-RIVERGUM', productCode: 'SFZ0010'},
         {code: 'LATTICE-HARVEST', productCode: 'SFZ2370LHA'},
         {code: 'LATTICE-STONE', productCode: 'SFZ0007'},
         {code: 'LATTICE-GREEN', productCode: 'SFZ2370LCG'},
         {code: 'LATTICE-MIST', productCode: 'SFZ2370LMG'},
         {code: 'LATTICE-BRONZE', productCode: 'SFZ2370LBO'},
         {code: 'LATTICE-IRONBARK', productCode: 'SFZ2370LIB'},
         {code: 'LATTICE-HERITAGE', productCode: 'SFZ2370LHR'},
         {code: 'LATTICE-OCEAN', productCode: 'SFZ2370LDO'},
         {code: 'LATTICE-TEA', productCode: 'SFZ2370LTT'},
         
         {code: 'POST-ZINC-1.8M', productCode: 'SFP0006'},
         {code: 'POST-ZINC-2.1M', productCode: 'SFP2700LZA'},
         {code: 'POST-CREAM-1.8M', productCode: 'SFP0003'},
         {code: 'POST-CREAM-2.1M', productCode: 'SFP00033'},
         {code: 'POST-MERINO-1.8M', productCode: 'SFP0004'},
         {code: 'POST-MERINO-2.1M', productCode: 'SFP00044'},
         {code: 'POST-GREY-1.8M', productCode: 'SFP0002B'},
         {code: 'POST-GREY-2.1M', productCode: 'SFP00022B'},
         {code: 'POST-RIVERGUM-1.8M', productCode: 'SFP0005'},
         {code: 'POST-RIVERGUM-2.1M', productCode: 'SFP0055'},
         {code: 'POST-HARVEST-1.8M', productCode: 'SFP2350LHA'},
         {code: 'POST-HARVEST-2.1M', productCode: 'SFP2700LHA'},
         {code: 'POST-STONE-1.8M', productCode: 'SFP0002'},
         {code: 'POST-STONE-2.1M', productCode: 'SFP00022'},
         {code: 'POST-GREEN-1.8M', productCode: 'SFP0002A'},
         {code: 'POST-GREEN-2.1M', productCode: 'SFP2700LCG'},
         {code: 'POST-MIST-1.8M', productCode: 'SFP2350LMG'},
         {code: 'POST-MIST-2.1M', productCode: 'SFP2700LMG'},
         {code: 'POST-BRONZE-1.8M', productCode: 'SFP2350LBO'},
         {code: 'POST-BRONZE-2.1M', productCode: 'SFP2700LBO'},
         {code: 'POST-IRONBARK-1.8M', productCode: 'SFP2350LIB'},
         {code: 'POST-IRONBARK-2.1M', productCode: 'SFP2700LIB'},
         {code: 'POST-HERITAGE-1.8M', productCode: 'SFP2350LHR'},
         {code: 'POST-HERITAGE-2.1M', productCode: 'SFP2700LHR'},
         {code: 'POST-OCEAN-1.8M', productCode: 'SFP2350LDO'},
         {code: 'POST-OCEAN-2.1M', productCode: 'SFP2700LDO'},
         {code: 'POST-TEA-1.8M', productCode: 'SFP2350LTT'},
         {code: 'POST-TEA-2.1M', productCode: 'SFP2700LTT'}
      ];
      
      var PR1 = new PostAndRail('TrimDek: Post & 5m Rails');
      PR1.addFinishes(postFinishes);
      PR1.addHeights(postHeights);
      PR1.setSpacingMinimum(0);
      PR1.setSpacingMaximum(2.4);
      PR1.addOptions([
         {code: 'NONE_5', name: 'None'},
         {code: 'CAPS_5', name: 'Fence Capping'}
      ]);
      PR1.addMappings(postMappings);
      
      var PR2 = new PostAndRail('TrimDek: Post & 7.5m Rails');
      PR2.addFinishes(postFinishes);
      PR2.addHeights(postHeights);
      PR2.setSpacingMinimum(0);
      PR2.setSpacingMaximum(2.4);
      PR2.addOptions([
         {code: 'NONE_7.5', name: 'None'},
         {code: 'CAPS_7.5', name: 'Fence Capping'}
      ]);
      PR2.addMappings(postMappings);
      // override the 7.5m specific products
      PR2.addMappings([
         {code: 'RAIL', productCode: 'RHSG382512/7.5'}
      ]);
      
      var PR3 = new PostAndRail('Corrugated: Post & 5m Rails');
      PR3.addFinishes(postFinishes);
      PR3.addHeights(postHeights);
      PR3.setSpacingMinimum(0);
      PR3.setSpacingMaximum(2.4);
      PR3.addOptions([
         {code: 'NONE_5', name: 'None'},
         {code: 'CAPS_5', name: 'Fence Capping'}
      ]);
      PR3.addMappings(postMappings);
      PR3.addMappings(corroPostMappings);
      
      var PR4 = new PostAndRail('Corrugated: Post & 7.5m Rails');
      PR4.addFinishes(postFinishes);
      PR4.addHeights(postHeights);
      PR4.setSpacingMinimum(0);
      PR4.setSpacingMaximum(2.4);
      PR4.addOptions([
         {code: 'NONE_7.5', name: 'None'},
         {code: 'CAPS_7.5', name: 'Fence Capping'}
      ]);
      PR4.addMappings(postMappings);
      PR4.addMappings(corroPostMappings);
      // override with corro products
      PR4.addMappings([
         {code: 'RAIL', productCode: 'RHSG382512/7.5'}
      ]);
      
      var NF = new Friendly('Neighbour Friendly');
      NF.addFinishes(postFinishes);
      NF.addHeights([
         {code: '1.8M', name: '1.8m'},
         {code: '2.1M', name: '2.1m'}
      ]);
      NF.setSpacingMinimum(2.4);
      NF.setSpacingMaximum(2.4);
      NF.addOptions([
         {code: 'NONE', name: 'None'},
         {code: 'LATTICE', name: 'Lattice'}
      ]);
      NF.addMappings(postMappings);
      NF.addMappings(friendlyMappings);
      
      
      fence = new Configurator();
      fence.addType(PR1);
      fence.addType(PR2);
      fence.addType(PR3);
      fence.addType(PR4);
      fence.addType(NF);
   }
});
var elems = [];
var tm;
function addToCart(url, o, f){
   var status = $('cartStatus').cloneNode(true);
   status.style.display = '';
   status.id = '';
   elems.push([status, f]);
   
   if(o){
      $(o).insert({ after: status });
      Element.clonePosition(status, o);
      // clonePos doesn't take borders into account
      status.style.width = (status.getWidth() - 12) + 'px';
      status.style.height = (status.getHeight() - 12) + 'px';
   }
   
   new Ajax.Request(url, {
      onSuccess: function(response) {
         response = response.responseText.evalJSON();
         if(response.success)
            status.addClassName('cartSuccess');
         else
            status.addClassName('cartFailure');
         if(response.cartHTML)
            $('cartBox').update(response.cartHTML);
         status.show();
         window.setTimeout('removeStatus()', 1500);
      },
      onFailure: function(response) {
         status.addClassName('cartFailure');
         status.show();
         window.setTimeout('removeStatus()', 1500);
      }
   });
}
function removeStatus(){
   var s = elems.shift();
   s[0].remove();
   
   // we now need to invoke the code that grays out the product inputs
   var fields = s[1];
   for(var i = 0; i < fields.length; i++){
      var f = $(fields[i]);
      if(f){
         // inputs are governed by the class: CoveredInput
         if(f.tagName.toLowerCase() == 'input'){
            var cInput;
            for(var j = 0; j < coveredInputs.length; j++){
               var ci = coveredInputs[j];
               if(ci.input.id == fields[i]){
                  cInput = ci;
                  j = coveredInputs.length;
               }
            }
            f.value = '';
            if(cInput)
               cInput.blurInput(null);
         } else if(f.tagName.toLowerCase() == 'select'){
            // selects are governed by custom events
            f.selectedIndex = 0;
            f.fire('custom:change');
         }
      }
   }
};

