// ===============
// = Terminology =
// ===============
// Separate = An individual clothing item that is being displayed. Only a nonstandard bikini (separates) will have more than one
// Item     = An actual item composed of a style, fabric, colour, size and any other options
// Selector = The drop down type system that is used to select a product from the available properties
// Property = The options that need to be selected to choose an item (colour, size, options etc)
// Option   = An individual option that can be selected to choose a property eg: (x_small, red, triangle back)

// =======================
// = ItemContainer Class =
// =======================
// An ItemContainer contains everything that is required to select one or more items usings an ItemSelector.
// A single ItemContainer may contain many ItemSelectors by pressing the 'add one' button
var ItemContainer = Class.create({

	initialize: function(element) {
    // The container is the div.item_selector which will contain all the html for all the ItemSelectors under this ItemContainer
		this.container      = $(element);

    // This contains the index value of the separate that is on the page.
    // This will always be 0 for a Clothing buy page but may be 1 for a Bikini page that displays
    // 2 separates instead of one bikini. This index is required so we know which product selector to target.
		this.separate_index = this.container.id.substr(9,1);

    // The item_index refers to the index of the item that is displayed on the page.
    // A bikini page will have two items while a clothing page will just have the one item
		this.item_index     = this.container.id.substr(16,1);

    // As a single item may have many selectors (after pressing 'add one') this index will track the selector index
		this.selector_index = $(element).select('.selector').size();

    // This contains an array of string that are used to display the property name ie: [colour, size, options]
		this.property_names = all_property_names[this.separate_index];

    // Create the initial item selector
		this.createItemSelector();
	},

	createItemSelector : function() {
	  var headings = this.container.select('.selector_headings').first();
	  if (this.selector_index > 0 || !headings) {
      var unique_val = + new Date; // generate a unqiue value to use as the id of this new heading
      var heading = "<div class=\"selector_headings\"> \
        <div class=\"first selector_heading\"> \
          <table> \
            <tbody> \
              <tr class=\"right\"> \
                <td class=\"close_row\" colspan=\"2\"> \
                  <a onclick=\"$(this).up('.selector').remove(); Tips.removeAll()\" id=\"remove_0\" href=\"javascript:void(0)\"> \
                    <img src=\"/images/buy_page/cross.gif\" alt=\"Cross\"/> \
                  </a> \
                </td> \
              </tr> \
              <tr class=\"top\"> \
                <td class=\"pad_left\">";
                if (!is_accessory) {
                  heading += "<img src=\"http://cdn.wickedweasel.com/assets/icons/styles/"+style_codes[this.item_index]+"_50.png\" class=\"diagram\" />";
                }
    heading += "</td> \
                <td> \
                  <h2 class=\"relative\">"+item_names[this.item_index]+"</h2> \
                </td> \
              </tr> \
            </tbody> \
          </table> \
        </div> \
      </div>";
  	  var div = '<div id="separate_'+this.separate_index+'_item_'+this.item_index+'_selector_'+this.selector_index+'" class="selector">'+heading+'</div>';
      this.container.insert({bottom: div});
    } else {
      new Element.wrap(headings, 'div', { id: 'separate_'+this.separate_index+'_item_'+this.item_index+'_selector_'+this.selector_index }).addClassName('selector');
    }

    // add the hover tool tip to the heading link
    this.container.select('.selector_heading a').each(function(link) {
      new Tip( link.readAttribute('id'),
        _('click here to remove this item'), { className: 'silver'}
      );
    });

		var currentItemSelector = new ItemSelector(this.separate_index, this.item_index, this.selector_index);
		this.selector_index ++;
	}
});
// end of ItemSelector class


// ======================
// = ItemSelector Class =
// ======================
var ItemSelector = Class.create({

	initialize: function(separate_index, item_index, selector_index) {
		this.container        = $('separate_'+separate_index+'_item_'+item_index+'_selector_'+selector_index);

    // The hash of all the properties and the item ids for this item selector
		this.item             = $H(item_ids[separate_index][item_index]);

    // current_options holds all the properties and the item ids for this item that haven't been selected.
		this.current_options  = this.item;

    this.separate_index   = separate_index;

    // Records the item index that this ItemSelector targets
		this.item_index       = item_index;

    // Records the selector index that this ItemSelector targets
		this.selector_index   = selector_index;

    // An array of strings that indicate the selections that have already been made
		this.selections       = [];

    // Records which property that is currently waiting to be selected
		this.property_index   = 0;

		this.property_names   = all_property_names[separate_index][item_index].clone();

		// If we have two property names of 'variation' in this selector we will combine them into one now
    // This basically combines the back style and the varation into one selectable option
    if ($A(this.property_names).select(function(e){return e.match(/variation/)}).size() > 1) {
      this.combineVariations();
    }

    // Boolean to determine if the initialisation has been completed
		this.initialised      = false;

		this.appendProperty(this.current_options.keys());
	},

  // Adds a property selection box to the DOM
	appendProperty: function(options) {
		if(!options) return;
		if(options.length == 1)
			this.showOption(options.first());
		else
			this.showOptions(options);
	},

	// returns a string that is used as the ID for a property div made up of
	// the separate_index, item_index, selector_index and property_index
	propertyId: function() {
		return "separate_"+this.separate_index+"_item_"+this.item_index+"_selector_"+this.selector_index+"_property_"+this.property_index;
	},

  // Displays the only options that is available for this property eg: "only available in snakeskin"
	showOption: function(option) {
		// Insert the word 'standard' into blank option
    // if (option != "standard" && this.property_names[this.property_index] != "variation") {
    if (!option.match(/standard/)) {
      html = "<div class='single_property' id='"+this.propertyId()+"'>" +_('only available in {{thing}}', this.removePrefixes(option)) +"</div>";
      this.container.insert({bottom: html});
      // this.property_index++;
    }
		this.addOptionToSelections(option);
    this.displayNextProperty();
	},

  // Display a property selection box.
  showOptions: function(options) {
    var position_count = 0;

    var property_div = new Element('div', {
      'id': this.propertyId()
    }).addClassName('property '+this.property_names[this.property_index]+'_property');
    this.container.insert(property_div);

    var property_heading = new Element('h3', {
      'id': this.propertyId() + "_" + this.english(this.property_names[this.property_index])
    }).addClassName('select').update(_('choose a {{thing}}', this.removePrefixes(this.property_names[this.property_index])));
    property_div.insert(property_heading);

    var property_contents_div = new Element('div').addClassName('property_contents');
    property_div.insert(property_contents_div);

    var options_div = new Element('div').addClassName('options');
    property_contents_div.insert(options_div);

    options.sort().each(function(option, index) {
      var option_name = this.removePrefixes(option);
      // kludge to insert the word standard into blank option
      if(option_name.length == 0) option_name = _("standard");

      var link_id = this.propertyId() + "_option_"+index;
      var extra_classes = "";
      var property_name = this.english(this.property_names[this.property_index]);

      if (property_name == "colour") var extra_classes = "bordered";

      if (property_name.match(/variation|trouser|print/)) {
        var option_div = new Element('div').addClassName('option variation_option');

        var option_link = new Element('a', {
          'id': link_id,
          'href': 'javascript: void(0)'
        }).update(_(option_name));
        option_div.insert(option_link);

      } else {
        var option_div = new Element('div').addClassName('option');

        var option_link = new Element('a', {
          'id': link_id,
          'href': 'javascript: void(0)'
        });

        var option_image = new Element('img', {
          'src': this.imagePath("small", this.english(option))
        }).addClassName(extra_classes);

        var option_label = new Element('div').addClassName('option_label').update(_(option_name));

        option_link.insert(option_image);
        option_div.insert(option_link);
        option_div.insert(option_label);
        // Some version of IE were having problems displaying the images, it would generate a Broken pipe
        // error in the logs if this slight pause wasn't there.
        if (Prototype.Browser.IE && !window.XMLHttpRequest) {
          // IE 6
          this.sleep(100);
        }
      }
      options_div.insert(option_div);

      position_count++;
      if(position_count == 3) position_count = 0;
    }.bind(this));

    $(this.propertyId()).select('.option_label').invoke('hide');

    this.addOnclickToPropertyAnchors();
  },

  sleep : function(delay) {
    var start = new Date().getTime();
    while (new Date().getTime() < start + delay);
  },

	addOnclickToPropertyAnchors: function() {
		// Add the onclick event to each of the anchors inside the property
		$(this.propertyId()).select('a').each(function(anchor) {
			Event.observe(anchor, 'click', this.collapseProperty.bindAsEventListener(this));
			if (!this.english(this.property_names[this.property_index]).match(/variation|trouser|print/)) {
  			Event.observe(anchor, 'mouseover', function(){ this.next().show(); });
  			Event.observe(anchor, 'mouseout', function(){ this.next().hide(); });
  		}
		}.bind(this));

	},

	collapseProperty: function(event) {
		var clicked_anchor		 = Event.element(event);
		var property_container = clicked_anchor.up('.property');
		var heading            = property_container.select('h3.select').first();
		var options_container  = property_container.select('.options').first();
		var property_contents  = property_container.select('.property_contents').first();

    heading.hide();

		// find which option has been selected
		if (this.english(this.property_names[this.property_index]).match(/variation|trouser|print/)) {
		  var selected_option = clicked_anchor.up('.option').select('a').first().innerHTML.strip();
		} else {
  		var selected_option = clicked_anchor.up('.option').select('.option_label').first().innerHTML;
		}

		// define extra classes for the image tag so it will have a border if it is a colour swatch
		var extra_classes = "";
		if (this.english(this.property_names[this.property_index]) == "colour") {
      // add the 'bordered' class to colour icons
			var extra_classes = "bordered";
		}

    // hide the currently displayed options
    options_container.hide();

		// insert a small image of the selection with the name to the right
		if (this.english(this.property_names[this.property_index]).match(/variation|trouser|print/)) {
  		options_container.insert({after:
  									"<div class='selection'> \
  										 <p>"+selected_option+"</p> \
  									 </div>"});
		} else {
  		options_container.insert({after:
  									"<div class='selection'> \
  									   <img src='"+ this.imagePath("small", this.translateProperty(selected_option)) +"' class='"+extra_classes+"'> \
  										 <p>"+selected_option+"</p> \
  									 </div>"});
		}

		// Add the edit link to the selected name
    options_container.next('.selection').down('p').insert({
      bottom: ' <a style="font-size:9px;" href="javascript: void(0);">&nbsp; '+_("change")+'</a>'
    });

		// Add the onclick event to the edit anchor
		options_container.next('.selection').down('p a').observe('click', this.expandProperty.bindAsEventListener(this));
		this.addOptionToSelections(selected_option);

    // remove any properties that follow this one
    $(property_container).nextSiblings().invoke('remove');
    this.displayNextProperty();
	},

	// returns the path to an image based on the property type and size
	imagePath: function(size, name) {
		var property_name = this.english(this.property_names[this.property_index]);
		if (property_name == "colour") {
			return "http://cdn.wickedweasel.com/assets/images/"+ this.propertyDirectory(property_name) +"/"+ this.fabricColourCode(name) +"_"+ size +".jpg";
		} else {
			return "http://cdn.wickedweasel.com/assets/icons/"+ this.propertyDirectory(property_name) +"s/"+ name.gsub(/[ ,]+/,"-") +"_"+ size +".jpg";
		}
	},

	// works out the name of the directory where the images are based on the property name
	propertyDirectory: function(name) {
		switch(name) {
			case "colour":
				return "fabric_colour_images";
				break;
			case "variation":
				return "option";
				break;
			default:
				return name;
		}
	},

	// works out the fabric colour code base on the name of the colour using the look_up_table defined in _selector.html.haml
	fabricColourCode: function(colour_name) {
		return fabric_colour_codes[colour_name.gsub(" ", "-")];
	},

	addOptionToSelections: function(option) {
		// add the selected option to the selections array
		var trans = this.translateProperty(this.convertHTML(this.removePrefixes(option)));
		this.selections[this.property_index] = this.translateProperty(this.convertHTML(this.removePrefixes(option)));
		// remove all the options after the one we just added
		this.selections = this.selections.slice(0, parseInt(this.property_index) + 1);
	},

  // converts characters such as &amp; into the standard characters
	convertHTML: function(string) {
	  return string.gsub("&amp;", "&");
	},

	removePrefixes: function(option) {
	  // remove all prefixes from the passed in string, the prefixes are used to set information about the option
    // such as the position is should be in or the english word for the option
    // eg: [pos:2][en:micro]micro => micro
    return option.gsub(/\[[^\]]+\]/,"")
	},

  // return the english translation of the passed in property
	english: function(option) {
	  var english = "";
	  var options = option.split(",");
	  for (var i=0; i < options.length; i++) {
  	  options[i] = options[i].gsub(/^\[.*en:/,"").gsub(/\].*/, "");
	  };
	  return options.join(", ");
	},

	matched : "",

  // recursively goes through all the properties in the items and returns the english translation
	translateProperty: function(string) {
	  var item_copy = this.item;
	  this.matched = "";
    this.findProperty(item_copy._object, string);
    return this.matched;
	},

	findProperty: function(properties, string) {
    $H(properties).each(function(pair) {
      if (string == this.removePrefixes(pair.key)) {
        this.matched = this.english(pair.key);
        throw $break;
      } else {
        // don't loop again if the next object contains a number ie: it is an item id
        if (pair.value != null && typeof(pair.value) != "string" && typeof(pair.value[0]) != "number") {
          this.findProperty(pair.value, string);
        }
      }
    }.bind(this));
	},

	displayNextProperty: function() {
		var item_copy = this.item;
		var item_id   = false;
		this.selections.each(function(selection, index) {
			item_copy.each(function(property, item_copy_index) {
				if(this.english(property[0]) == selection) {
					next_options = property[1];
          if(typeof(property[1][0]) == "number") { item_id = property[1][0]; }
				}
			}.bind(this));
			item_copy = $H(next_options);
		}.bind(this));
		this.property_index++;

		if(item_id) {
			this.addItemField(item_id);
			return false;
		} else {
			this.appendProperty($H(item_copy).keys());
			return false;
		}
	},

  // This will go through each of the sizes and combine the two variation hashes into a single
  // variation hash, this means instead of making a selection like triangle back then selecting side clips
  // you will just be able to select triangle back with side clips as one option
  combineVariations: function() {
    var new_item_hash = $H();
    // loop over each of the sizes
    this.item.each(function(item, index) {
      var combinedVariations = $H();
      // loop over each of the back styles
      $H(item.value).each(function(firstVariation) {
        var secondVariations = $H(firstVariation.value)
        // loop over each of the variations
        secondVariations.each(function(secondVariation) {
          // create the variation name buy combining the back style and variation
          var variation_name = firstVariation.key
          // if (this.removePrefixes(secondVariation.key) != _('standard')) variation_name += ", " + secondVariation.key
          if (this.english(secondVariation.key) != 'standard') variation_name += ", " + secondVariation.key
          combinedVariations.set(variation_name, secondVariation.value)
        }.bind(this));
      }.bind(this))
      // store the new hash in a tempory spot
      new_item_hash.set(item.key, combinedVariations);
    }.bind(this))
    // reset the item hash to the new values
    this.item = new_item_hash;
    // remove the first variation from the property names list
    var variation_name = this.property_names.detect(function(e){return e.match(/variation/)});
    this.property_names.splice(this.property_names.indexOf(variation_name), 1);
  },

	expandProperty: function(event) {
		var clicked_anchor		 = Event.element(event);
		var property_container = clicked_anchor.up('.property');
		var heading            = property_container.down('h3');
		var options_container  = property_container.down('.options');
		var property_contents  = property_container.down('.property_contents');

		this.property_index    = property_container.id.gsub(/^.*property_/,"");

    property_container.nextSiblings().invoke('remove');

		var hidden_field = property_container.select('input').first();
		if(hidden_field) hidden_field.remove();

    // heading.innerHTML = _("choose a")+" "+this.property_names[this.property_index];
    // heading.addClassName('select');
    heading.show();

    property_container.select('.selection').first().hide();
    options_container.show();
	},

	addItemField: function(item_id) {
		this.container.insert({bottom: "<input type='hidden' class='item_id_hidden_field' name='item_ids[]' value='"+item_id+"'>"});
	}
});
// end ItemSelector class


// ====================
// = CartButton Class =
// ====================
var CartButton = Class.create({

	initialize : function(element) {
		Event.observe(element, 'click', this.confirmSelections.bindAsEventListener(this));
	},

	confirmSelections: function(event) {
		var clicked_button = Event.element(event);
		if(clicked_button.form.select('.item_id_hidden_field').size() < 1) {
			alert(_("Please select all the options for at least one of the items on this page."));
			Event.stop(event);
		} else {
			if(clicked_button.form.select('.selector').size() > clicked_button.form.select('.item_id_hidden_field').size()) {
				if (!confirm(_("You have not selected all options for one or more of the items on this page. Do you want to continue and only add the selected items to the cart?"))) Event.stop(event);
			}
		}
	}
});


document.observe('dom:loaded', function() {
	$$('.item_selector').each(function(e) {
  	// remove any hidden fields that may have been set previously
    e.select('input[type=hidden]').invoke('remove');
	  var mainContainer = new ItemContainer(e);
	});
	$$('div.cart_button').each(function(e) { var cartButton = new CartButton(e); });
	$$('div.wishlist_button').each(function(e) { var wishlistButton = new CartButton(e); });
});
