/**
##########################################################################################

Part of Toolkit

##########################################################################################
**/

/**
  function in order to open anchors external (in new window),
  which is required due to target="_blank" is INVALID in XHTML strict.
  params:
    anchorNode = the anchor-node to be opened external ('this')
    windowName = a window-name in which to open the link, can be undefined
  returns:
    a boolean value to return (event bubbling) in your call
*/
function openExternal(anchorNode, windowName) {
  if (!windowName) {
    windowName = "_blank";
  }

  anchorNode.target = windowName;
  
  return true;
} // end openExternal(anchorNode, windowName)

/**
	function to get elements defined by a specificclass attribute
	params:
		className = class name attribute
		tag = elements to be checked (use "*" to check all)
		node = node container to be checked (use "document" to check full page)
*/
function getElementsByClass(className, tag, node) {
	alert(node);
	var matchingElements = new Array();
	if(node != 'document') {
		node = document.getElementById(node);
	} else {
		node = document;
	}
	var elements = node.getElementsByTagName(tag);
	for(var i=0;i<elements.length;i++) {
		var item = elements.item(i);
		var itemClass = item.className;
		if(itemClass == className) {
			matchingElements.push(elements[i]);
		}
	}
	return matchingElements;
}

/**
	function to toggle search div
	params:
		divName = name of div to change visibility
		anchorElm = id of the element containing the search LINK (needed since we change arrow img when toggling)
		trigger = id of the element with the trigger arrow
		state = on / off visibility of search div
		
*/
function toggleSearch(divName,anchorName,trigger,state) {
	var modalDiv = document.getElementById(divName);
	var anchorElm = document.getElementById(anchorName);
	var triggerElm = document.getElementById(trigger);
	if(state == "off") {
		modalDiv.style.visibility = "hidden";
		anchorElm.className = "searchClosed";
		triggerElm.className = "searchClosed";
	} else {
		modalDiv.style.visibility = "visible";
		anchorElm.className = "searchOpen";
		triggerElm.className = "searchOpen";
	}
}


/**
	function to toggle product Info overlays
	params:
		caller = element which calls the toggle
		toggleElm = class name of the element to be toggled
		state = on / off visibility state
		
	depending on state either the parent element is retrieved,
	DIV nodes of parent are retrieved
	DIV with styleclass matching param 'toggleElm' is set to visible
	for off state parent elements are retrieved until parent is a DIV with classname matching param 'toggleElm'
	toggleElm visibility is set to hidden

*/
function toggleProductInfo(caller, toggleElm, state) {
	if(state == "on") {
		var offElements = getElementsByClass(toggleElm,'DIV','document');
		for(var i=0;i<offElements.length;i++) {
			var hideElm = offElements[i];
			hideElm.style.visibility = "hidden";
		}
		var parentNode = caller.parentNode;
		var divNodes = parentNode.getElementsByTagName("DIV");
		for(var i=0;i<divNodes.length;i++) {
			var divNode = divNodes[i];
			if(divNode.className == toggleElm) {
				divNode.style.visibility = "visible";
			}
		}
	} else {
		var parentNode = caller.parentNode;
		var divNodes = parentNode.getElementsByTagName("DIV");
		for(var i=0;i<divNodes.length;i++) {
			var divNode = divNodes[i];
			if(divNode.className == toggleElm) {
				divNode.style.visibility = "hidden";
			}
		}
	}
}

// ///////////////////////////////////////////////////////
//
// COMMONLY USED TOOL-FUNCTIONS
//
// ///////////////////////////////////////////////////////

/**
 * Splits up the given path + filename to an array
 * of size 2. Returned array contains path (including trailing slash)
 * at array[0], which can be empty in case of no leading folders,
 * and array[1] the file name. Ex: splitFilePath('gfx/bla.gif') returns
 * ['gfx/', 'bla.gif'].
 * params:
 *   path = string holding a filepath (folderpath->optional) and a 
 *   filename (mandatory)
 */
function splitFilePath(path) {
  var result = [];
  var lastSlash = path.lastIndexOf('/');
  
  if (lastSlash == -1) {
    result.push('');
  } else {
    result.push(path.substring(0, lastSlash + 1));
  }
  
  result.push(path.substring(lastSlash + 1));
  
  return result;
} // end splitFilePath(path)

/**
 * Replaces filepath values by a new value. First, the given
 * attribute ('attr') value will be obtained, then split up
 * in 'path' and 'filename', then the regular expression will
 * be applied to the 'filename' part in order to replace that
 * by the given 'newVal'. 
 *
 * params:
 *   element = the element NODE to replace the attribute value
 *   attr = name of the attribute in whose value to replace
 *   regExp = regular expression for identifying a match
 *   newVal = string as replacement for each match
 *
 * Ex: 
 *   replaceInFilePathAttribute(someImgNode, 'src', /open/g, 'closed')
 *   replaces all occurances of 'open' in the filename-part of
 *   the given image nodes 'src' attribute by 'closed'
 * 
 */
function replaceInFilePathAttribute(element, attr, regExp, newVal) {
  var arr = splitFilePath(element.getAttribute(attr));
  arr[1] = arr[1].replace(regExp, newVal);
  element.setAttribute(attr, arr.join(''));
} // end replaceInFilePathAttribute(elementId, path)

/**
 * Sets up all trigger/slide combinations so each trigger and slide
 * knows it's global index and to which trigger/slide they refer
 * each other.
 *
 * Added node members after calling this:
 *   triggerNodes[n].instanceIndex = numerical index given by name id
 *   triggerNodes[n].slideInstance = reference to the slide-node which
 *                                   is made visible by the trigger
 *   triggerNodes[n].slideInstance.instanceIndex = numberical index given by name id
 *   triggerNodes[n].slideInstance.triggerInstance = triggerNodes[n]
 */
function setupTriggerSlides(triggerNodes, slidePrefix) {
  triggerNodes.each(function(trigger) {
    // extract numerical trigger index from name of shape 'somestring<numerical index>':
    var index = parseInt(/[0-9]+$/.exec(trigger.id));
    
    // [debug]
    if (isNaN(index)) { FAIL("setupTriggerSlides(...): Unparsable index using /[0-9]+$/ on id '"+trigger.id+"'!"); }
    
    // store that and create references between trigger<->slide
    trigger.instanceIndex = index;
    trigger.slideInstance = document.getElementById(slidePrefix+index);

    // [debug]
    if (!trigger.slideInstance) { FAIL("setupTriggerSlides(...): Missing slide with index '"+index+"' on id '"+trigger.id+"'!"); }

    trigger.slideInstance.instanceIndex = index;
    trigger.slideInstance.triggerInstance = trigger;
  });
} // end setupTriggerSlides(triggerPrefix, slidePrefix)

/**
 * Checks whether or not the given point (x,y) with the client viewport as origin
 * is inside or outside the given element, assuming the given pixel-tolerance to
 * be applied. The 'tolerance' is the width/height in pixels in which an 'outside'
 * is assumed even if only 'tolerance' pixels away from nearst border.
 * params:
 *   x = the client viewport x-position
 *   y = the client viewport y-position
 *   element = the element node to use for inside/outside decision
 *   tolerance = the positive tolerance, 3 seems to be a good decision to handle IE7s
 *               inaccurate mouseout event positions
 */
function pointOutsideElement(x, y, element, tolerance) {
  var p = element.viewportOffset();
  var s = element.getDimensions();
  
  if ((x < (p.left + tolerance)) || (x >= (p.left + s.width - tolerance)) ||
      (y < (p.top + tolerance)) || (y >= (p.top + s.height - tolerance))) {
    return true;
  }
  
  return false;
} // end pointOutsideElement(x, y, element, tolerance)

// ///////////////////////////////////////////////////////
//
// EFFECT SECTION
//
// ///////////////////////////////////////////////////////

/**
 * Prepares the given element NODE for being fade in/fade out
 * using the blinding effects. This call is necessary, because
 * creating another blind effect while another one runs makes
 * the following blind effect would use fucked up width and height.
 * 
 * params:
 *   element = the element node on which the blind effect will be used
 */
function prepareBlind(element) {
  element.isOpened = false;
  element.originalSize = Element.getDimensions(element);
} // end prepareBlind(elementId)

/**
 * Applies a blind up effect to  the given element. The effect will 
 * be queued in a two elements sized queue.
 *
 * HINT:
 * Calling this method on the element requires that 'prepareBlind(element)'
 * was called before using this effect.
 *
 * params:
 *   element = the element node on which the blind effect will be used
 */
function applyBlindUp(element) {
  var elementId = element.id;
  
  var queue = Effect.Queues.get(elementId);
  if ((queue.effects.length > 0) && (queue.effects[queue.effects.length-1].options.effectName === 'blindup')) { 
    // prevent the queue accepts two identical slides (caused by timing inaccuracies)
    return; 
  }
  
  element.makeClipping();
  return new Effect.Scale(element, 0,
    Object.extend({ 
      effectName: 'blindup',
      scaleContent: false,
      duration: 0.6,
      scaleX: false,
      scaleMode: {originalHeight: element.originalSize.height, originalWidth: element.originalSize.height},
      queue:{limit:2, scope:elementId, position:'end'},
      restoreAfterFinish: true,
      afterSetup: function(effect) {
        effect.element.makeClipping().show();   // bugfix TB: needed in order to chain effects in queue, misses in scriptaculous
        effect.element.isOpened = false;        // enhancement TB: not set in scriptaculous, but useful not working with prototype-interna state flags
      },
      afterFinishInternal: function(effect) {
        effect.element.hide().undoClipping();
      }
    }, arguments[1] || { })
  );
}; // applyBlindUp(elementId)

/**
 * Applies a blind down effect to  the given element. The effect will 
 * be queued in a two elements sized queue.
 *
 * HINT:
 * Calling this method on the element requires that 'prepareBlind(element)'
 * was called before using this effect.
 *
 * params:
 *   element = the element node on which the blind effect will be used
 */
function applyBlindDown(element) {
  var elementId = element.id;

  var queue = Effect.Queues.get(elementId);
  if ((queue.effects.length > 0) && (queue.effects[queue.effects.length-1].options.effectName === 'blinddown')) { 
    // prevent the queue accepts two identical slides (caused by timing inaccuracies)
    return; 
  }

  return new Effect.Scale(element, 100, 
  Object.extend({
    effectName: 'blinddown',
    duration: 0.6,
    queue:{limit:2, scope:elementId, position:'end'},
    scaleContent: false,
    scaleX: false,
    scaleFrom: 0,
    scaleMode: {originalHeight: element.originalSize.height, originalWidth: element.originalSize.height},
    restoreAfterFinish: true,
    afterSetup: function(effect) {
      effect.element.makeClipping().setStyle({height: '0px'}).show();
      effect.element.isOpened = true;        // enhancement TB: not set in scriptaculous, but useful not working with prototype-interna state flags
    },
    afterFinishInternal: function(effect) {
      effect.element.undoClipping();
    }
  }, arguments[1] || { }));
}; // end applyBlindDown(elementId)

// ///////////////////////////////////////////////////////
//
// ERROR REPORT SECTION
//
// ///////////////////////////////////////////////////////

/**
 * Shows a fatal problem, to be used in debug-versions.
 * params:
 *   msg = the message to display
 */
function FAIL(msg) {
  alert(msg);
} // end FAIL(msg)




/**
##########################################################################################

Part of ToggleMenu

##########################################################################################
**/

/**
*	function to toggle the arrow images
*	index: image to change
*	checkIndex: id to check against index
*   contextPath: path to images if caller page exists into a subfolder
*	if image and checkIndex match, the standard toggle between open/closed image is processed
*	if image and checkIndex do not match, the toggle only happens if the image defined by id is open
**/
function toggleImage(imageId,contextPath) {
	var toggleArrow = document.getElementById(imageId);
	var imageSource = toggleArrow.src;
	var openState = imageSource.indexOf('open',0);
	
	if(openState < 1) {
		toggleArrow.setAttribute('src',contextPath+'images/buttons/arrow_34_open.png');
	} else {
		toggleArrow.setAttribute('src',contextPath+'images/buttons/arrow_34_closed.png');
	}
}

function toggleMenu(divId, imageId) {
	Effect.toggle(divId, 'blind');
	toggleImage(imageId,'');
}

function toggleMenuDynamic(divId, imageId, contextPath) {
	Effect.toggle(divId, 'blind');
	toggleImage(imageId,contextPath);
}