// $Header: /home/cvs/cvsroot/site_data/001/00000001/static_data/js/don_premium_elements.js,v 1.26 2008/04/02 21:08:41 raghu Exp $

var DON_PS_PREM_SELECT_LIST_CLASS = 'PremiumSelectorSelect';
var DON_PS_PREM_RADIO_BUTTON_CLASS = 'PremiumSelectorRadio';
var DON_PS_PREM_NONE_AVAIL_ROW_ID = 'don_prem_none_avail_row';
var DON_PS_PREM_AVAIL_FOR_USER_SPECIFIED_AMT_ROW_ID = 'don_prem_avail_for_user_specified_amt_row';
var DON_PS_NO_SELECTION_PREM_PRODUCT_ID = -1;
var DON_PS_PREM_AVAIL_FOR_USER_SPECIFIED_AMT_PRODUCT_ID = -2;

var don_ps_premiumInfos = new Array();

var don_ps_radio_buttons;
var don_ps_searched_for_radios = false; // flag to save redundant searching

var don_ps_select_list;
var don_ps_select_list_clone;
var don_ps_searched_for_select = false; // flag to save redundant searching

var don_premium_map = new Object();  // to find by level ID
var don_ps_value_map = new Object(); // to find by level value
var don_ps_level_id = 0;
var don_ps_user_specified_level_id = 0;
var don_ps_user_specified_value = 0;

/**
 * Constructs a map entry for a level.
 * It will contain an array of premiums available to it.
 */
function DonLevelPremiums (_levelId, _levelValue)
{
	this.levelId = _levelId;
	this.levelValue = _levelValue;
	this.premiumIDs = new Array();
}

/**
 * Adds a premium ID to the list for this level.
 */
DonLevelPremiums.prototype.addPremium = function (_premId)
{
	this.premiumIDs[_premId] = _premId;
}

/**
 * Checks whether a premium ID is in the list for this level.
 */
DonLevelPremiums.prototype.hasPremium = function (_premId)
{
	return this.premiumIDs[_premId] ? true : false;
}

/**
 * Adds a mapping of a premium ID to a level.
 */
function don_ps_map_premium_to_level (_levelId, _levelValue, _premId)
{
	var lvlInfo = don_premium_map[_levelId]; // a DonLevelPremiums

	if (!lvlInfo) {
		var levelValue = parseInt (_levelValue);    
		lvlInfo = new DonLevelPremiums (_levelId, _levelValue);
		don_premium_map[_levelId] = lvlInfo;
		don_ps_value_map[levelValue] = lvlInfo;
	}

	lvlInfo.addPremium (_premId);
}

/**
 * Given a user-specified value, return the
 * DonLevelPremiums that has the highest value but is still less than
 * the user-specified value.
 * @member don_premium_elements
 * @param _userSpecifiedValue the user-specified value
 * @type DonLevelPremiums
 */
function don_ps_getHighestDonLevelPremiums (_userSpecifiedValue)
{
	var result = null;

	var resultValue = 0;
	for (var value in don_ps_value_map) {
		var intValue = parseInt (value);
		if (intValue > resultValue && intValue <= _userSpecifiedValue) {
			result = don_ps_value_map[value];
			resultValue = intValue;
		}
	}

	return result;
}

/**
 * Public method to set the ID of the selected level.
 */
function don_ps_set_selected_level_id (_levelId)
{
	don_ps_level_id = _levelId;
}

/**
 * Sets the level ID of the user-specified level.
 */
function don_ps_set_user_specified_level (_levelId)
{
	don_ps_user_specified_level_id = _levelId;
}

/**
 * Sets the user-specified value.
 */
function don_ps_set_user_specified_value (_value)
{
	don_ps_user_specified_value = _value;
}

/**
 * Returns the premium select radio buttons on this page.
 * Assumes that there is only one set, so returns all buttons having the same
 * name as the first 'premium' radio button found.
 * The list is cached so if the radio buttons are manipulated in the DOM then
 * it could be out of date.
 */
function don_ps_getRadioButtons()
{
	if (!don_ps_radio_buttons && !don_ps_searched_for_radios) {
		don_ps_searched_for_radios = true;
		var inputs = document.getElementsByTagName ('INPUT');
		don_ps_radio_buttons = filterByClass (inputs, DON_PS_PREM_RADIO_BUTTON_CLASS);
	}

	return don_ps_radio_buttons;
}

/**
 * Returns the premium select list on this page.
 * Assumes that there is only one, so returns the first one found.
 */
function don_ps_getSelectList()
{
	if (!don_ps_select_list && !don_ps_searched_for_select) {
		don_ps_searched_for_select = true;
		var sels = document.getElementsByTagName ('SELECT');

		for (var i = 0; (!don_ps_select_list && (i < sels.length)); i++)
			if (isOfClass (sels[i], DON_PS_PREM_SELECT_LIST_CLASS))
				don_ps_select_list = sels[i];

		if (don_ps_select_list)
			don_ps_select_list_clone = don_ps_select_list.cloneNode (true);
	}

	return don_ps_select_list;
}

/**
 * Returns a clone of the original state of the premium select list on
 * this page.
 */
function don_ps_getOrigSelectList()
{
	// If undefined, try to initialize it.
	if (!don_ps_select_list_clone)
		don_ps_getSelectList();

	return don_ps_select_list_clone;
}

/**
 * Resets the select list to a copy of the original, so that its options can be
 * trimmed. Necessary because for IE, trimming has to be done by removing
 * options (hiding via style.display does not work).
 * @return the new select list
 */
function don_ps_reset_select_list()
{
	var sel = don_ps_getSelectList();
	var origSel = don_ps_getOrigSelectList();

	if (sel && origSel) {
		don_ps_select_list = origSel.cloneNode (true);
		don_ps_select_list.selectedIndex = sel.selectedIndex;
		don_ps_select_list.value = sel.value;
		Utils.addEvent (don_ps_select_list, 'change', don_ps_premiumSelected);
		sel.parentNode.replaceChild (don_ps_select_list, sel);
	}

	return don_ps_select_list;
}

/**
 * Finds the appropriate SELECT list of premiums and filters it to only show
 * the premiums available for the given level ID.
 */
function don_ps_filter_by_level (_levelId)
{
	var map = don_premium_map[_levelId];
	var sel = don_ps_reset_select_list();

	if (sel)
		don_ps_filter_select_by_level (map, sel, _levelId);
	else {
		var radios = don_ps_getRadioButtons();

		if (radios && radios.length)
			don_ps_filter_radios_by_level (map, radios, _levelId);
	}
}

/**
 * Finds the appropriate list of premiums and filters it to only show
 * the premiums available for a specified amount.
 * @param is a String representing a monetary value.
 */
function don_ps_filter_by_string_value (_sAmount)
{
	var amount = parseCurrency (_sAmount);
	if (isNaN (amount)) amount = 0;
	don_ps_filter_by_value (amount);
}

/**
 * Finds the appropriate list of premiums and filters it to only show
 * the premiums available for the amount.
 * @param is a number representing a monetary value.
 */
function don_ps_filter_by_value (_amount)
{
	var donLevelPremiums = don_ps_getHighestDonLevelPremiums (_amount);
	if (donLevelPremiums) {
		var levelId = donLevelPremiums.levelId;
		don_ps_filter_by_level (levelId);
	}
	else {
		don_ps_filter_by_level (don_ps_user_specified_level_id);
	}
}

/**
 * Finds the appropriate radio buttons of premiums and filters it to only show
 * the premiums available for the given level ID.
 */
function don_ps_filter_radios_by_level (_map, _radios, _levelId)
{
	var firstVisible;
	var lastVisible;
	var numVis = 0;

	for (var r = 0; (r < _radios.length); r++) {
		var id = don_ps_get_premium_id (_radios[r].value);

		// If the checked one gets hidden, then check the first visible one
		// when done.
		if (don_ps_hide_or_show_premium_radio (_map, _radios[r], id, _levelId, numVis)) {
			numVis++;
			lastVisible = _radios[r];

			if (!firstVisible)
				firstVisible = _radios[r];
		}
	}

	// If only the 'no premium' choice is shown, replace it with text explaining
	// that there are not any premiums available.
	var unavail = document.getElementById (DON_PS_PREM_NONE_AVAIL_ROW_ID);
	var availForAmt = document.getElementById (DON_PS_PREM_AVAIL_FOR_USER_SPECIFIED_AMT_ROW_ID);
	var userSpecifiedSelected = _levelId == don_ps_user_specified_level_id;

	if ((numVis == 1) && firstVisible && unavail) {
		if (userSpecifiedSelected) {
			hide_element (unavail);
			show_element (availForAmt);
		}
		else {
			hide_element (availForAmt);
			show_element (unavail);
		}
		hide_element (fc_getFormRow (firstVisible));
		firstVisible.checked = false;
	}
	else {
		hide_element (unavail);
		hide_element (availForAmt);

		if (lastVisible) {
			var row = fc_getFormRow (lastVisible);
			row.className = (firstVisible == lastVisible) ? 'FormRow' : 'FormRowLast';
		}
	}
}

/**
 * Called by don_ps_filter_radios_by_level to determine whether to hide or show
 * an element that represents a premium.
 */
function don_ps_hide_or_show_premium_radio (_map, _element, _id, _levelId, _numVisible)
{
	var showIt = ((_id <= 0) || (_map && _map.hasPremium (_id)));

	if (showIt) {
		var row = fc_getFormRow (_element);
		show_element (row);
		row.className = _numVisible ? 'FormRowMiddle' : 'FormRowFirst';
	}
	else {
		hide_element (fc_getFormRow (_element));

		if (_element.checked)
			_element.checked = false;
	}

	return showIt;
}

/**
 * Finds the appropriate SELECT list of premiums and filters it to only show
 * the premiums available for the given level ID.
 */
function don_ps_filter_select_by_level (_map, _select, _levelId)
{
	// Iterate in descending order because items might be removed.
	for (var op = (_select.options.length - 1); (op >= 0); op--) {
		var opt = _select.options[op];
		var id = don_ps_get_premium_id (opt.value);
		don_ps_hide_or_show_premium_option (_map, opt, id, _levelId);

		// If an OPTGROUP is removed, then the list of options may have decreased
		// by more than one.  Ensure the index is within bounds.
		if (op > _select.options.length)
			op = _select.options.length;
	}

	// If the current selection has just been hidden, then select the 'prompt'
	// option.
	if (_select.selectedIndex > 0) {
		var opt = _select.options[_select.selectedIndex];

		if (opt.style.display == 'none') {
			_select.options[0].selected = true;
			_select.selectedIndex = 0;
			_select.value = _select.options[0].value;
		}
	}

	don_ps_simulateSelection (_select);
}

/**
 * Called by don_ps_filter_select_by_level to determine whether to hide or show
 * an element that represents a premium.
 * For IE, hiding has to be done by removing options (hiding via style.display
 * does not work).
 */
function don_ps_hide_or_show_premium_option (_map, _element, _id, _levelId)
{
	if (_id > 0) {
		if ((!_map || !_map.hasPremium (_id))) {
			removeOptionElement (_element);
		}
	}
	else {
		if (_id == DON_PS_NO_SELECTION_PREM_PRODUCT_ID && _levelId == don_ps_user_specified_level_id)
			removeOptionElement (_element);
		else if (_id == DON_PS_PREM_AVAIL_FOR_USER_SPECIFIED_AMT_PRODUCT_ID && _levelId != don_ps_user_specified_level_id) 
			removeOptionElement (_element);
	}
}

function removeOptionElement (_element)
{
	if (_element.tagName == 'OPTION') {
		if (_element.parentNode.tagName == 'OPTGROUP')
			_element.parentNode.parentNode.removeChild (_element.parentNode);
		else
			_element.parentNode.removeChild (_element);
	}
}

/**
 * Creates a don_ps_PremiumInfo which has information about the short
 * description for a single premium.
 */
function don_ps_PremiumInfo (_select, _contentHolder)
{
	subclass (this, new FCDynamicMessageInfo (_select, _contentHolder));
}

function don_ps_addPremiumInfo (_pi)
{
  don_ps_premiumInfos.push (_pi);
}

/**
 * Any changes to this must be coordinated with
 * premium_selector_drop_down_option_div.tpt.
 */
function don_ps_findPremiumInfoDiv (select, premiumID)
{
  // NB: corresponds to ID in component Java source.
  var divID = "donation_premium_info." + premiumID;
  var api = don_ps_findPremiumInfoDivs (select);

  for (var i = 0; i < api.length; i++) {
    if (api[i].id == divID)
      return api[i];
  }
  return null;
}

/**
 * Given a SELECT element, return all the associated
 * DIVs containing premium information.
 */
function don_ps_findPremiumInfoDivs (select)
{
  var premiumInfos = new Array();
  var cell = getAncestor ('TD', select);

  if (cell) {
    var divs = cell.getElementsByTagName ('DIV');

    for (var i = 0; i < divs.length; i++) {
      var div = divs[i];

      // NB: corresponds to class in premium_selector_select_info_div.tpt
      if (isOfClass (div, 'DonationPremiumInfo')) {
        premiumInfos.push (div);
      }
    }
  }

  return premiumInfos;
}

/**
 * Extracts the premium ID from an attribute value that may or may not have
 * a configuration option ID appended to it.
 */
function don_ps_get_premium_id (_value)
{
	var idxDot = _value.indexOf ('.');
	return (idxDot != -1) ? _value.substring (0, idxDot) : _value;
}

/**
 * Given a element and a premium/choice value, display information
 * for the premium.  The premium/choice value is encoded as
 * productID[.productOptionChoiceID].
 */
function don_ps_showPremiumMessage (el)
{
	var div;
  var value = get_input_value (el);

	if (value) {
		var id = don_ps_get_premium_id (value);
		div = don_ps_findPremiumInfoDiv (el, id);
	}

	fc_showOtherMessage (el, div, 'PremiumInfoBlock');
}

function don_ps_configSelected (_evt)
{
	_evt = _evt ? _evt : event;
	var el = _evt.target ? _evt.target : _evt.srcElement;
	var radio = fc_getPeerByClass (el, DON_PS_PREM_RADIO_BUTTON_CLASS);

	if (radio)
		radio.checked = true;
}

function don_ps_premiumSelected (_evt)
{
	_evt = _evt ? _evt : event;
	var el = _evt.target ? _evt.target : _evt.srcElement;
	don_ps_showPremiumMessage (el);
}

/**
 * Initializes the premium selection data element when the page loads.
 */
function don_ps_initPremiumInfo()
{
	var select = don_ps_getSelectList();

	if (select) {
		hide_element (DON_PS_PREM_NONE_AVAIL_ROW_ID);
		hide_element (DON_PS_PREM_AVAIL_FOR_USER_SPECIFIED_AMT_ROW_ID);

		// register all the premium info information
		var premiumInfos = don_ps_findPremiumInfoDivs (select);

		for (var j = 0; j < premiumInfos.length; j++) {
			var premiumInfo = premiumInfos[j];
			var premiumID = premiumInfo ? premiumInfo.id : '';
			don_ps_addPremiumInfo (new don_ps_PremiumInfo (select, premiumInfo));
		}

		// turn on display for this row, and turn on marker param
		var row = fc_getFormRow (select);

		if (row) {
			show_element (row);
			var submit = fc_getChildByClass (row, 'DonPremiumSubmit');

			if (submit)
				submit.value = 'true';
		}

		Utils.addEvent (select, 'change', don_ps_premiumSelected);
  }

	var radios = don_ps_getRadioButtons();

	for (var r = 0; (radios && (r < radios.length)); r++) {
		var cfgList = fc_getPeerByClass (radios[r], 'PremiumSelectorConfigSelect');

		if (cfgList && (cfgList.tagName == 'SELECT')) {
			Utils.addEvent (cfgList, 'change', don_ps_configSelected);
		}
	}

  // hide all the radio button rows that were rendered for noscript purposes
  var spans = document.getElementsByTagName ('SPAN');

  for (var i = 0; i < spans.length; i++) {
    if (isOfClass (spans[i], 'DonPremiumDeleteThisRow'))
      hide_element (fc_getFormRow (spans[i]));
  }
}

/**
 * Simulates a radio button or select list click for the premium that should be
 * initially displayed.
 */
function don_ps_checkInitial()
{
	var select = don_ps_getSelectList();

	if (select)
		don_ps_simulateSelection (select);
}

/**
 * Simulates the selection of a premium in a SELECT list.
 */
function don_ps_simulateSelection (_select)
{
	var event = new Object();
	event.target = _select;
	don_ps_premiumSelected (event);
}


var timerID = 0;

function don_ps_queue_filter_by_string_value (_component)
{
	var sAmount = _component.get();
	var code = "don_ps_filter_by_string_value ('" + sAmount + "')";
	timerID = setTimeout (code, 1000);
}

function don_ps_dequeue_filter_by_value()
{
	if (timerID != 0) clearTimeout (timerID);
	timerID = 0;
}

function don_ps_immediate_filter_by_value(_component)
{
	var sAmount = _component.get();
	don_ps_filter_by_string_value (sAmount);
}

/**
 * Construct an observer of a level selection observable component that updates
 * the premium selection when a level changes.
 */
function don_ps_LevelChangeObserver()
{
	this.observe = function (_event)
	{
		if (_event.component) {
			don_ps_dequeue_filter_by_value();

			var levelId = _event.component.get();
			don_ps_filter_by_level (levelId);

			if (levelId == don_ps_user_specified_level_id) {
				// TODO: eliminate coupling with don_level_radio_button_view.tpt
				var amountComp = get_observable_component (_event.component.prefix + levelId + "amount");
				if (amountComp) {
					don_ps_immediate_filter_by_value (amountComp);
				}
			}
		}
	}
}

/**
 * Construct an observer of a level selection observable component that updates
 * the premium selection when a level changes.
 */
function don_ps_OtherAmountChangeObserver()
{
	this.observe = function (_event)
	{
		var component = _event.component;
		if (component) {
			var evt = _event.evt;
			if (evt) {
				var isKeyupEvent = evt.type == "keyup";
				var isClickEvent = evt.type == "click";
				var isFocusEvent = evt.type == "focus";

				if (don_ps_getSelectList()) {
					if (isKeyupEvent || isClickEvent || isFocusEvent) {
						don_ps_immediate_filter_by_value (component);
					}
				}
				else {
					don_ps_dequeue_filter_by_value();

					if (isKeyupEvent) {
						don_ps_queue_filter_by_string_value (component);
					}
					else {
						don_ps_immediate_filter_by_value (component);
					}
				}
			}
		}
	}
}

/**
 * Initializes the premium selector data element.
 */
function don_ps_init()
{
  don_ps_initPremiumInfo();
	fc_setDimensions(don_ps_premiumInfos, 'PremiumInfoBlock');
	dl_observeLevelChange (new don_ps_LevelChangeObserver());
	dl_observeOtherAmountChange(new don_ps_OtherAmountChangeObserver());

	if (don_ps_level_id > 0) {
		if (don_ps_level_id != don_ps_user_specified_level_id)
			don_ps_filter_by_level (don_ps_level_id);
		else {
			don_ps_dequeue_filter_by_value();
			don_ps_filter_by_value (don_ps_user_specified_value);
		}
	}

	don_ps_checkInitial();
}

// Must wait to get the whole page loaded.
// Try to chain it to the level init. because the order that onload handlers
// execute cannot be assumed.
if (!dl_onload || !dl_onload (don_ps_init))
	Utils.addEvent (window, 'load', don_ps_init);

