
/**
 * project: barmer web
 * type: javascript
 * description: load javascript files and set global variables
 * @author: Heimann, 31.08.2009
 * @copyright: T-Systems 2005-2009. All rights reserved.
 */



/**
 * The "classic" theme markup for Shadowbox.
 *
 * This file is part of Shadowbox.
 *
 * Shadowbox is an online media viewer application that supports all of the
 * web's most popular media publishing formats. Shadowbox is written entirely
 * in JavaScript and CSS and is highly customizable. Using Shadowbox, website
 * authors can showcase a wide assortment of media in all major browsers without
 * navigating users away from the linking page.
 *
 * Shadowbox is released under version 3.0 of the Creative Commons Attribution-
 * Noncommercial-Share Alike license. This means that it is absolutely free
 * for personal, noncommercial use provided that you 1) make attribution to the
 * author and 2) release any derivative work under the same or a similar
 * license.
 *
 * If you wish to use Shadowbox for commercial purposes, licensing information
 * can be found at http://mjijackson.com/shadowbox/.
 *
 * @author      Michael J. I. Jackson <mjijackson@gmail.com>
 * @copyright   2007-2008 Michael J. I. Jackson
 * @license     http://creativecommons.org/licenses/by-nc-sa/3.0/
 * @version     SVN: $Id: skin.js,v 1.2 2009-08-25 17:11:04 hst Exp $
 */

if(typeof Shadowbox == 'undefined'){
    throw 'Unable to load Shadowbox skin, base library not found.';
}

/**
 * The HTML markup to use for Shadowbox.
 *
 * IMPORTANT: The script depends on most of these elements being present.
 *
 * @property    {Object}    SKIN
 * @public
 * @static
 */
Shadowbox.SKIN = {

    markup:     '<div id="shadowbox_container">' +
                    '<div id="shadowbox_overlay"></div>' +
                    '<div id="shadowbox">' +
                        '<div id="shadowbox_title">' +
                            '<div id="shadowbox_title_inner"></div>' +
                        '</div>' +
                        '<div id="shadowbox_body">' +
                            '<div id="shadowbox_body_inner" class="sb_content"></div>' +
                            '<div id="shadowbox_loading">' +
                                '<div id="shadowbox_loading_indicator"></div>' +
                                '<span><a onclick="Shadowbox.close();">{cancel}</a></span>' +
                            '</div>' +
                        '</div>' +
                        '<div id="shadowbox_info">' +
                            '<div id="shadowbox_info_inner">' +
                                '<div id="shadowbox_counter"></div>' +
                                '<div id="shadowbox_nav">' +
                                    '<a id="shadowbox_nav_close" title="{close}" onclick="Shadowbox.close()"></a>' +
                                    '<a id="shadowbox_nav_next" title="{next}" onclick="Shadowbox.next()"></a>' +
                                    '<a id="shadowbox_nav_play" title="{play}" onclick="Shadowbox.play()"></a>' +
                                    '<a id="shadowbox_nav_pause" title="{pause}" onclick="Shadowbox.pause()"></a>' +
                                    '<a id="shadowbox_nav_previous" title="{previous}" onclick="Shadowbox.previous()"></a>' +
                                '</div>' +
                                '<div class="shadowbox_clear"></div>' +
                            '</div>' +
                        '</div>' +
                    '</div>' +
                '</div>',

    png_fix:    [
        'shadowbox_nav_close',
        'shadowbox_nav_next',
        'shadowbox_nav_play',
        'shadowbox_nav_pause',
        'shadowbox_nav_previous'
    ]

};
	


/**
 * global variables
 * assetPath: path to static external assets (e.g. stylesheets, javascript files)
 */ 
var assetPath = '\/barmer\/assets\/_shared\/';


/**
 * component: config options
 * description: configurable text assets
 * @author: Stefan Heimann (03.04.2009)
 */


/* ----------  Values in this section can be modified  ---------- */
// external links
bm.el = {
	// Hint: text asset
	hint: 'Hinweis:',
	
	// External links: text assets
	linkTitlePrefixExternal: 'Externer Link Ã¶ffnet sich in neuem Fenster: ',
	linkTitleHintExternal: 'Dieser externe Link Ã¶ffnet sich in einem neuen Fenster.',

	// Links to open in a new window: text assets
	linkTitlePrefixWindow: 'Link Ã¶ffnet sich in neuem Fenster: ',
	linkTitleHintWindow: 'Dieser Link Ã¶ffnet sich in einem neuen Fenster.'
};


/* "fontSizer": text assets */
bm.fs = {
	text: 'SchriftgrÃ¶ÃŸe: ',
	linkSmall: {
		icon: '-',
		text: 'A',
		title: 'SchriftgrÃ¶ÃŸe verkleinern'
	},
	linkReset: {
		icon: '',
		text: 'A',
		title: 'Standard SchriftgrÃ¶ÃŸe'
	},
	linkBig: {
		icon: '+',
		text: 'A',
		title: 'SchriftgrÃ¶ÃŸe vergrÃ¶ÃŸern'
	},
	separator: ' | ',
	hint: 'Hinweis: Sie haben die letzte Verkleinerungsstufe erreicht.'
};




/* ----------  Values in this section SHOULD NOT be modified !!!  ---------- */
/* External links: CSS IDs and class names */
bm.el.linkRelationExternal = 'external';
bm.el.linkRelationWindow = 'window';
/* Links to open in a new window: CSS IDs and class names */
bm.el.linkClass = 'tooltip';
bm.el.spanClass = 'title';


/* "fontSizer": variables for calculation */
bm.fs.initialSize = 16;			// value must match (in px) to body default font-size for css2 capable browsers
bm.fs.step = 1;					// in-/decrement value (in px)
bm.fs.minSize = 12;				// value (in px) sets minimal font-size

/* "fontSizer": cookie */
bm.co = {
	name: 'BARMER-TextSize',			// name of cookie
	domain: '.barmer-gek.de',	// domain of cookie
	path: "/",							// path of cookie
	days: ''							// days to store the cookie. Empty means session cookie
}

/* "fontSizer": CSS IDs and class names */
bm.fs.parentId = 'help';
bm.fs.pClass = 'fontSize';
bm.fs.hiddenClass = 'hd';
bm.fs.linkSmall.id = 'fsSmall';
bm.fs.linkReset.id = 'fsReset';
bm.fs.linkBig.id = 'fsBig';

/* forum editor: CSS IDs */
bm.ed = {
	iframeId: 'mce_editor_0',	// tiny mce editor
	initialSize: 11				// value must match (in px) to body default font-size for css2 capable browsers
}

/* zoom links in image material application */
bm.zo = {
	id: 'imageMaterial',
	linkRelation: 'zoom',
	fieldsetClass: 'big',
	linkZoomIn: 'Bild vergrÃ¶ÃŸern',
	linkZoomOut: 'Bild verkleinern'
}	


/**
 * component: various
 * description: provides additional content and functionality for DOM capable browsers
 *              - launch a window
 *              - onfocus fix for mozilla based browsers
 *              - mark all external links
 *              - add fontsizer
 *              - add zoom functionality for images
 * @author: Stefan Heimann (14.11.2007)
 */


/* functions to be processed when the DOM is ready */
window.addEvent('domready', function() {
	createContent();
	externalLinks();
	inspectLinks();
	imageMaterialLinks();
});


/* open a new window */
function launchWindow(objAnchor, objEvent) {
    var iKeyCode;
    if (objEvent && objEvent.type == 'keypress') {
        if (objEvent.keyCode) {
            iKeyCode = objEvent.keyCode;
        } else if (objEvent.which) {
            iKeyCode = objEvent.which;
        }

        if (iKeyCode != 13 && iKeyCode != 32) {
            return true;
        }
    }

    var bmWin = window.open(objAnchor,'bm');
    bmWin.focus();

    return false;
}


/* crawler for all links with inner elements
    sets focus on parent node: Fix for bug in Mozilla based browsers
*/
function inspectLinks() {
    var objChildren, objChild;
    var objAnchors = $$('a');

    for (var i=0; i<objAnchors.length; i++) {
        if (objAnchors[i].hasChild()) {
            objChildren = objAnchors[i].getChildren();
            for (var j=0; j<objChildren.length; j++) {
                objChild = objChildren.item(j);

                if (objChild.nodeType == '1' && objChild.nodeName != 'img') {
                    objChild.addEvent('focus', function() {
                        this.parentNode.focus();
                    });
                }
            }
        }
    }
}


/* crawler for external links
   Thanks to Bruce Lawson
*/
function externalLinks() {
    if (document.getElementsByTagName) {
    	processExternalLinks( $$('a'), true );
    }
}

/**
 * 
 * @param anchors Array<Element> Array von Mootool-Anchor-Elementen
 * @param createTitle bollean Gibt an ob ein Titel für den Anchor erzeugt werden soll oder nicht
 */
function processExternalLinks( objAnchors, createTitle ) {
    
	if (objAnchors) {
        
		var linkTitlePrefix, linkTitleHint;

        for (var i=0; i<objAnchors.length; i++) {
            var objAnchorRel = objAnchors[i].getProperty('rel');
            if (objAnchors[i].getProperty('href') && objAnchorRel && (objAnchorRel == bm.el.linkRelationExternal || objAnchorRel == bm.el.linkRelationWindow)) {
                if (objAnchorRel == bm.el.linkRelationExternal) {
                    linkTitlePrefix = bm.el.linkTitlePrefixExternal;
                } else {
                    linkTitlePrefix = bm.el.linkTitlePrefixWindow;
                }

                if( createTitle ) {
                	objAnchors[i].title = linkTitlePrefix + objAnchors[i].title;
                }
                
                objAnchors[i].onclick = function(evt) {
					return launchWindow(this, evt);
				}
                objAnchors[i].onkeypress = function(evt) {
					return launchWindow(this, evt);
				}
                objAnchors[i].onblur = function(evt) {
					return hideLinkTitle(this, evt);
				}
                objAnchors[i].onfocus = function(evt) {
                    if (this.getProperty('rel') == bm.el.linkRelationExternal) {
                        linkTitleHint = bm.el.linkTitleHintExternal;
                    } else {
                        linkTitleHint = bm.el.linkTitleHintWindow;
                    }
                    return showLinkTitle(this, evt, linkTitleHint);
                }
                objAnchors[i].onmousedown = function(evt) {
					this.onfocus = null;
				}
                objAnchors[i].onmouseover = function(evt) {
					return hideLinkTitle(this, evt);
				}
            }
        }
    }
}


/* show link title, when link gets focus */
function showLinkTitle(objAnchor, objEvent, linkTitleHint) {
    hideLinkTitle(objAnchor, objEvent);

    var objTooltip = new Element('span', {
		'class' : bm.el.spanClass
	});
    
    var objTooltipHeadline = new Element('em').appendText(bm.el.hint);
    objTooltipHeadline.injectInside(objTooltip);

    objTooltip.appendText(' ' + linkTitleHint);
    
    objAnchor.addClass(bm.el.linkClass);
    objTooltip.injectInside(objAnchor);
}


/* hide link title, when link looses focus */
function hideLinkTitle(objAnchor, objEvent) {
    var objSpans = objAnchor.getElementsByTagName('span');

    for (var i=0; i<objSpans.length; i++) {
        if (objSpans[i].hasClass(bm.el.spanClass)) {
            objAnchor.removeClass(bm.el.linkClass).removeChild(objSpans[i]);
        }
    }
}


/* get position in the document and create content for "fontSizer" */
function createContent() {
    // get the parent Element
    var parent = $(bm.fs.parentId);
    var contentTextSize = initTextSize();

    if (parent) {
        parent.insertBefore(createFontSizer(), parent.firstChild);
        setContentSzenario(contentTextSize);
    }
}


/* paragraph with "fontSizer" content */
function createFontSizer() {
    // paragraph
    var fsPara = new Element('p', {'class' : bm.fs.pClass});
    
    // description
    fsPara.appendText(bm.fs.text);

    // link: small
    fsPara.appendChild(createLink(bm.fs.linkSmall));
    // separator
    fsPara.appendChild(createSeparator(bm.fs.separator));
    // current
    fsPara.appendChild(createCurrent(bm.fs.linkReset));
    // separator
    fsPara.appendChild(createSeparator(bm.fs.separator));
    // link: big
    fsPara.appendChild(createLink(bm.fs.linkBig));

    return fsPara;
}


/* link in "fontSizer" */
function createLink(cfg) {
    var fsLink = new Element('a', {
        'id' : cfg.id,
        'title' : cfg.title,
        'href' : '#' + cfg.id
        });

	fsLink.appendChild(new Element('span').appendText(cfg.text));
	fsLink.appendChild(new Element('sup').appendText(cfg.icon));
	fsLink.appendChild(new Element('span').addClass(bm.fs.hiddenClass).appendText(' ' + cfg.title));

    fsLink.addEvent('click', function(e) {
        changeTextSize(this, e);
        new Event(e).preventDefault();
    });

    return fsLink;
}


/* enhanced link in "fontSizer" */
function enhanceLink(cfg) {
    var parent = $(cfg.id);
    parent.replaceChild(new Element('em').appendText(cfg.text), parent.firstChild);
}


/* reset link in "fontSizer" */
function resetLink(cfg) {
    var parent = $(cfg.id);
    parent.replaceChild(new Element('span').appendText(cfg.text), parent.firstChild);
}


/* current element in "fontSizer" */
function createCurrent(cfg) {
    var fsEm = new Element('em', {'id' : cfg.id});

	fsEm.appendChild(new Element('span').appendText(cfg.text));
	fsEm.appendChild(new Element('sup').appendText(cfg.icon));
	fsEm.appendChild(new Element('span').addClass(bm.fs.hiddenClass).appendText(' ' + cfg.title));
    
    return fsEm;
}


/* enhance current element in "fontSizer" */
function enhanceCurrent(cfg) {
    var obj = $(cfg.id);
    obj.getParent().replaceChild(createLink(cfg), obj);
}


/* reset current element in "fontSizer" */
function resetCurrent(cfg) {
    var obj = $(cfg.id);
    obj.getParent().replaceChild(createCurrent(cfg), obj);
}


/* separator in "fontSizer" */
function createSeparator(text) {
    return document.createTextNode(text);
}


/* set status for elements in "fontSizer" */
function setContentSzenario(size) {
    var ratio = size / bm.fs.initialSize;

    if (ratio > 1) {
        resetLink(bm.fs.linkSmall);
        enhanceCurrent(bm.fs.linkReset);
        enhanceLink(bm.fs.linkBig);
    } else if (ratio < 1) {
        enhanceLink(bm.fs.linkSmall);
        enhanceCurrent(bm.fs.linkReset);
        resetLink(bm.fs.linkBig);
    } else {
        resetLink(bm.fs.linkSmall);
        resetCurrent(bm.fs.linkReset);
        resetLink(bm.fs.linkBig);
    }
}


/* get text size from cookie or initial size */
function initTextSize() {
    bm.fs.actualSize = parseInt(Cookie.get(bm.co.name));

    if (bm.fs.actualSize) {
        getDocumentBody(bm.fs.actualSize);
    }
    else {
        bm.fs.actualSize = bm.fs.initialSize;
    }

    return bm.fs.actualSize;
}


/* change text size */
function changeTextSize(obj, evt) {
    var newSize, trigger;

    if (!evt.srcElement) {
        trigger = obj.id;
    } else {
        trigger = evt.srcElement.parentNode.id;  
    }

    switch (trigger) {
        case bm.fs.linkBig.id:
            newSize = bm.fs.actualSize + bm.fs.step;
            break;
        case bm.fs.linkSmall.id:
            newSize = bm.fs.actualSize - bm.fs.step;
            break;
        case bm.fs.linkReset.id:
            newSize = bm.fs.initialSize;
            break;
        default:
            newSize = bm.fs.actualSize;
    }

    if (newSize < bm.fs.minSize) {
        newSize = bm.fs.minSize;
        alert(bm.fs.hint);
    }

    setContentSzenario(newSize);
    getDocumentBody(newSize);

    Cookie.set(bm.co.name, newSize, {domain: bm.co.domain, path: bm.co.path, duration: bm.co.days});
    
    return false;
}


/* get body element (parent document and iframes) */
function getDocumentBody(newTextSize) {
    var bodyInit = $$('body')[0];
    setTextSize(bodyInit, newTextSize);

    bm.fs.actualSize = newTextSize;

    // iframe extension
    getFrameBody();
}


/* iframe editor extension for fontsizer */
function getFrameBody() {
    if ($(bm.ed.iframeId)) {
        var editorFrame = $(bm.ed.iframeId);
        var editorFrameBody;
        var editorFrameNewTextSize = bm.fs.actualSize - (bm.fs.initialSize - bm.ed.initialSize);
    
        if (editorFrame.contentDocument) {
            editorFrameBody = editorFrame.contentDocument.getElementsByTagName('body')[0];
        } else if (document.all) {
            editorFrameBody = document.frames(bm.ed.iframeId).document.body;
        }
    
        if (editorFrameBody && !isNaN(editorFrameNewTextSize)) {
            setTextSize(editorFrameBody, editorFrameNewTextSize);
        }
    }
}


/* set new text size on body element */
function setTextSize(obj, newTextSize) {
    if (obj.style.setProperty) {
        obj.style.setProperty('font-size', newTextSize + 'px', '');
        if (typeof(getComputedStyle) == 'undefined') {
            obj.style.setProperty('margin','1px',''); // workaround for opera 7 (W32) to force reflow
            obj.style.setProperty('margin','0','');
        }
    } else if (obj.currentStyle) {
        newTextSize = newTextSize / bm.fs.initialSize * 100 + '%';
        obj.style.fontSize = newTextSize;
    }
}


/* image material: crawler for links */
function imageMaterialLinks() {
    if ($(bm.zo.id) && document.getElementsByTagName) {
        var imageApp = $(bm.zo.id);
        var imageAppAnchors = imageApp.getElementsByTagName('a');

        for (var i=0; i<imageAppAnchors.length; i++) {
            if (imageAppAnchors[i].getAttribute('href') && imageAppAnchors[i].getAttribute('rel')) {
                if (imageAppAnchors[i].getAttribute('rel') == bm.zo.linkRelation) {
                    imageAppAnchors[i].onclick = function(evt) { return imageMaterialZoom(this, evt); }
                    imageAppAnchors[i].onkeypress = function(evt) { return imageMaterialZoom(this, evt); }
                }
            }
        }
    }
}


/* image material: zoom functionality for thumbnails */
function imageMaterialZoom(objAnchor, objEvent) {
    var parentSpan = getSpecificParent(objAnchor, 'SPAN');
    var parentFieldset = getSpecificParent(parentSpan, 'FIELDSET');
    var imgLinks = parentSpan.getElementsByTagName('a');

    for (var i=0; i<imgLinks.length; i++) {
        imgLinks[i].title = modifyLinkTitle(imgLinks[i]);
        modifyLinkText(imgLinks[i]);
    }

    if (parentFieldset.hasClass(bm.zo.fieldsetClass)) {
        parentFieldset.removeClass(bm.zo.fieldsetClass);
    } else {
        parentFieldset.addClass(bm.zo.fieldsetClass);
    }

    return false;
}


/* image material: get specific parent (tag)  */
function getSpecificParent(obj, tag) {
    do {
        obj = obj.getParent();
    } while (obj.tagName != tag);
    
    return obj;
}


/* image material: modify link title  */
function modifyLinkTitle(obj) {
    var objTitle = obj.getAttribute('title');
    
    if (objTitle.indexOf(bm.zo.linkZoomIn) != -1) {
        objTitle = objTitle.substring(0,objTitle.indexOf(bm.zo.linkZoomIn)) + bm.zo.linkZoomOut;
    } else if (objTitle.indexOf(bm.zo.linkZoomOut) != -1) {
        objTitle = objTitle.substring(0,objTitle.indexOf(bm.zo.linkZoomOut)) + bm.zo.linkZoomIn;
    }
    
    return objTitle;
}


/* image material: modify link text  */
function modifyLinkText(obj) {
    var objLastChild = obj.lastChild;
    
    if (objLastChild.nodeType == '3') {
        objLastChildValue = objLastChild.nodeValue;
        if (objLastChildValue.indexOf(bm.zo.linkZoomIn) != -1) {
            objLastChildValue = objLastChildValue.substring(0,objLastChildValue.indexOf(bm.zo.linkZoomIn)) + bm.zo.linkZoomOut;
        } else if (objLastChild.nodeValue.indexOf(bm.zo.linkZoomOut) != -1) {
            objLastChildValue = objLastChildValue.substring(0,objLastChildValue.indexOf(bm.zo.linkZoomOut)) + bm.zo.linkZoomIn;
        }

       obj.lastChild.nodeValue = objLastChildValue;
    }
}
	
/**
 * component: ajax
 * description: helper methods for ajax integration
 * @author: Sebastian Bub (03.08.2007)
 */


/* functions to be processed when the DOM is ready */
window.addEvent('domready', function() {
	if(self.addAjaxEvents){
		addAjaxEvents();
	}
});


// to use a newly created object it must be known globally for mootools
var myAjaxParentHack = null;

// for alert debugs
var debug = true;

/* function to register a checkbox for ajax calls*/
function registerCheckboxForAjax(item){
	$(item).addEvent('click', function(e){
		ajaxRequestFullForm(item, e);
	});
}

/* function sends the whole form
 * and adds dynamically a hidden field named ajaxRequst set to true
 * after the request the hidden field is removed again
 */
function ajaxRequestFullForm(item, e) {
    var formObj = getForm(item);
    formObj = $(formObj);
    var actionUrl = null;
    actionUrl = formObj.getProperty('action') +
        '?' + formObj.toQueryString() +
        '&ajaxRequest=' + item;
    var request = new Json.Remote(actionUrl, {
        onComplete: function(jsonObj) {
                        try{
                            if(null != jsonObj && null == jsonObj.error){
                                ajaxResponseAction(jsonObj.domActions,  item, 'preCondition');
                                ajaxResponseRemovals(jsonObj.domRemovals,  item);
                                ajaxResponseAdditions(jsonObj.domAdditions, item);
                                ajaxResponseChanges(jsonObj.domChanges,   item);
                                ajaxResponseAction(jsonObj.domActions,  item, 'postCondition');
                            } else {
                                if(debug) alert(getErrorMsg(jsonObj.error));
                            }
                        }catch(e){
                            throw e;
                        }
                    }
            }).send();
}

/* function which expects json formatted object and handles
 * necessary error msg
 */
function getErrorMsg(errorMsgs, item){
    var retString = '';
    if(null != errorMsgs){
        errorMsgs.each(function(msgObj){
            retString = retString + msgObj.msg + '\n';
        });
    }
    return retString;
}

/* function which expects json formatted object and handles
 * necessary actions for inter-JSON-communication
 */
function ajaxResponseAction(actionItems,  item, actionType){
    if(null != actionItems){
        actionItems.each(function(actionItem){
            if(actionItem.actionType == actionType){
                eval(actionItem.actionEvent);
            }
        });
    }
}

/* function which expects json formatted object and handles
 * necessary removals from DOM
 */
function ajaxResponseRemovals(removalItems,  item){
    if(null != removalItems){
        removalItems.each(function(removalItem){
            var doWork = true;
            if(null != removalItem.actionObserver)
                doWork = eval(removalItem.actionObserver);
            if(!doWork) return;
            
            if(removeNode(removalItem.tagId)){
                if(null != removalItem.actionEvent){
                    eval(removalItem.actionEvent);
                }
            }
        });
    }
}


/* function which expects json formatted object and handles
 * necessary additions to DOM
 */
function ajaxResponseAdditions(additionItems, item){
    if(null != additionItems){
        additionItems.each(function(addedItem){
            var doWork = true;
            if(null != addedItem.actionObserver)
                doWork = eval(addedItem.actionObserver);
            if(!doWork) return;

            var currentAdd = null;
            if("simpleTextNode" == addedItem.tagType){
                var parId = document.getElementById(addedItem.addToId);
                if(null != parId){
                    var txtNode = document.createTextNode(addedItem.textNodeValue);
                    parId.appendChild(txtNode);
                }
            } else {
                if(null == document.getElementById(addedItem.tagId)){
                    // create new Element
                    currentAdd = 'new Element(' + "'" + addedItem.tagType + "',";
                    currentAdd = currentAdd + "{'id': '" + addedItem.tagId +"'";
                    if(null != addedItem.className){
                        currentAdd = currentAdd + ",'class': '" + addedItem.className +"'";
                    }
                    if(null != addedItem.title){
                        currentAdd = currentAdd + ",'title': '" + addedItem.title +"'";
                    }
                    if(null != addedItem.href){
                        currentAdd = currentAdd + ",'href': '" + addedItem.href +"'";
                    }
                    currentAdd=currentAdd+ '})'
                    var addObj = eval(currentAdd);
                }
                if(null != addObj){
                    // add firstChildNodeValue
                    if(null != addedItem.firstChildNodeValue){
                        changeOrCreateFirstChildNodeValue(addObj, addedItem.firstChildNodeValue);
                    }

                    // set function for #fieldAnker focus
                    if("a" == addedItem.tagType && addedItem.href.indexOf("#") > -1){
                        addObj.onclick = function(event){return focusFormField(this, event);}
                        addObj.onkeypress = function(event){return focusFormField(this, event);}
                    }

                    // add element to id
                    currentAdd = 'addObj.' + addedItem.relativePosition + '(';
                    if("self.parent" == addedItem.addToId){
                        currentAdd = currentAdd + 'document.getElementById(item).parentNode';
                    } else {
                        myAjaxParentHack = document.getElementById(addedItem.addToId);
                        currentAdd = currentAdd + 'myAjaxParentHack';
                    }
                    currentAdd = currentAdd + ')';
                    eval(currentAdd);
                    
                    if(null != addedItem.actionEvent){
                        eval(addedItem.actionEvent);
                    }
                    
                    if("true" == addedItem.setFocus){
                        addObj.focus();
                    }
                }
            }
        });
    }
}


/* function which expects json formatted object and handles
 * necessary changes to DOM
 */
function ajaxResponseChanges(changesItems,   item){
    if(null != changesItems){
        changesItems.each(function(changeItem){
            var doWork = true;
            if(null != changeItem.actionObserver)
                doWork = eval(changeItem.actionObserver);
            if(!doWork) return;
            
            var currentTag = document.getElementById(changeItem.tagId);
            if(null != currentTag){
                if(null != changeItem.attributeType){
                    // value of attributeType set in String
                    // attributeValue is interpreted in eval-function
                    var currentChange = '';
                    if("firstChild.nodeValue" == changeItem.attributeType){
                        changeOrCreateFirstChildNodeValue(currentTag, changeItem.attributeValue);
                    } else {
                        currentChange = 'currentTag.' + changeItem.attributeType +
                                        ' = changeItem.attributeValue';
                    }
                    eval(currentChange);
                }
                if(null != changeItem.actionEvent){
                    eval(changeItem.actionEvent);
                }
                if("true" == changeItem.setFocus){
                    currentTag.focus();
                }
            }
        });
    }
}


/* function removes a node. return true if really removed */
function removeNode(nodeId){
    var nodeObj = document.getElementById(nodeId);
    if(null != nodeObj && null != nodeObj.parentNode){
        nodeObj.parentNode.removeChild(nodeObj);
        return true;
    } else {
        return false;
    }
}

/* function that sets focus on form field where #anchor = idWithout# */
function focusFormField(objAnchor, objEvent){
	// Allow keyboard navigation over links
	if (objEvent && objEvent.type == 'keypress')
		if (objEvent.keyCode != 13 && objEvent.keyCode != 32)
			return true;
	
	// set focus to the form control
	var strFormField = objAnchor.href.match(/[^#]\w*$/);
	var objForm = getForm(strFormField);
	objForm[strFormField].focus();
	return false;
}

/* Function to return the form element from a given form field name */
function getForm(strField){
	var objElement = document.getElementById(strField);
	
	// Find the appropriate form
	do {
		objElement = objElement.parentNode;
	} while (!objElement.tagName.match(/form/i) && objElement.parentNode); 

	return objElement;
}

function changeOrCreateFirstChildNodeValue(elementId, newValue){
    if(null != elementId){
        if(null == elementId.firstChild){
            var myText = document.createTextNode(newValue);
            elementId.appendChild(myText);
        } else { 
            elementId.firstChild.nodeValue = newValue;
        }
    }
}

	
/**
 * component: tax and duties
 * description: show and hide tax result information
 * @author: mhs (11.01.2009)
 */


/* functions to be processed when the DOM is ready */
window.addEvent('domready', function() {
	if(self.initTaxResultLinkTxt){
		initTaxResult();
	}
});


/* Global text assets */
var showTaxResultLink;
var hideTaxResultLink;

	 
/* tax and duties link */ 
var txLink = {
	taxResultDiv : 'taxResultDiv',
	taxResultLinkId : 'taxResultLinkId'
}

/* init tax result info */
function initTaxResult() {
	var taxResultDiv = $(txLink.taxResultDiv);
	
	if (taxResultDiv != null) {
		initTaxResultLinkTxt();
		taxResultDiv.className = 'hd';
		createShowTaxResultLink();
	}	
}

function initResultShowLinkText(showText){
	showTaxResultLink=showText;
}

function initResultHideLinkText(hideText){
	hideTaxResultLink=hideText;
}

/* create a link to show tax result info */
function createShowTaxResultLink() {
	var taxResultDiv = $(txLink.taxResultDiv);

	if (taxResultDiv != null) {
		var paragf = new Element('p', {'class' : 'button'});
		paragf.id = txLink.taxResultLinkId;
		var span = new Element('span', {'class' : 'but'});
		var taxResultLink = new Element('a', {'class' : 'ic'});
		taxResultLink.href = '#';
		taxResultLink.innerHTML = showTaxResultLink;
		taxResultLink.onclick = showTaxResultInfo;
		span.appendChild(taxResultLink);  
		paragf.appendChild(span);	
		$(taxResultDiv).parentNode.insertBefore(paragf, $(taxResultDiv));
	}
}

/* create a link to hide tax result info*/
function createHideTaxResultLink() {
	var taxResultDiv = $(txLink.taxResultDiv);

	if (taxResultDiv != null) {
		var paragf = new Element('p', {'class' : 'button'});
		paragf.id = txLink.taxResultLinkId;
		var span = new Element('span', {'class' : 'but'});
		var taxResultLink = new Element('a', {'class' : 'ic'});
		taxResultLink.id = txLink.taxResultLinkId;
		taxResultLink.href = '#';
		taxResultLink.innerHTML = hideTaxResultLink;
		taxResultLink.onclick = hideTaxResultInfo;
		span.appendChild(taxResultLink);  
		paragf.appendChild(span);
		$(taxResultDiv).parentNode.insertBefore(paragf, $(taxResultDiv));
	}
}

/* show tax result info*/
function showTaxResultInfo() {
	var taxResultDiv = $(txLink.taxResultDiv);
	taxResultDiv.className = '';

	var taxResultLinkId = $(txLink.taxResultLinkId);
	var form = document.getElementsByTagName("form");
	form[1].removeChild(taxResultLinkId);
	createHideTaxResultLink();
	
	return false;
}


/* hide tax result info */
function hideTaxResultInfo() {
	var taxResultDiv = $(txLink.taxResultDiv);
	taxResultDiv.className = 'hd';

	var taxResultLinkId = $(txLink.taxResultLinkId);
	var form = document.getElementsByTagName("form");
	form[1].removeChild(taxResultLinkId);
	createShowTaxResultLink();
	
	return false;
}
	
/**
 * component: shadowbox config
 * @description: Shadowbox configuration (skin, options)
 */

bm.shadowbox = {
	/**
	 * flag for shadowbox setup being done
	 */
	isinit : false,

	/**
	 * initialize function
	 * @param none
	 */
	init: function() {
		if(!this.isinit) {
			Shadowbox.init({
				skipSetup: true 
			});
			bm.shadowbox.override();
		}
		
		this.isinit = true;
	},
	
	/**
	 * shadowbox config
	 * Inner height by 1024x768px resolution
	 * - FF3: 627px (without tabs) => 565px
	 *        598px (with tabs) => 536px
	 * - IE6: 624px => 562px
	 * - IE7: 616px => 554px
	 */
	options: {
		continuous: true,
		displayNav: false,
		enableKeys: false,
		fadeDuration: 0.2,
		handleOversize: 'resize',
		height: 500,
		initialHeight: 150,
		initialWidth: 200,
		modal: false,
		overlayColor: '#fff',
		overlayOpacity: 0.8,
		player: 'html',
		resizeDuration: 0.35,
		width: 560
	},

	/**
	 * add the 'print specific' css class to the body
	 */
	override: function() {
		Shadowbox.originalOpen = Shadowbox.open;
		Shadowbox.open = function(obj, opts) {
			Shadowbox.originalOpen(obj, opts);
			bm.shadowbox.addPrintClass();
		}

		Shadowbox.originalClose = Shadowbox.close;
		Shadowbox.close = function() {
			Shadowbox.originalClose();
			bm.shadowbox.removePrintClass();
		}
	},

	/**
	 * add the 'print specific' css class to the body
	 */
	addPrintClass: function() {
		$('bm').addClass('pageSB');
	},

	/**
	 * remove the 'print specific' css class from the body
	 */
	removePrintClass: function() {
		$('bm').removeClass('pageSB');
	}
};

/**
 * component: agency search
 * @description: adds functionality to switch the display of agency information in text and google maps
 */

// add component to domready event list
window.addEvent('domready', function() {
	bm.agencysearch.init();
});

bm.agencysearch = {

	/**
	 * language properties
	 */
	lang: {
		agencySwitch: {
			headline: 'Gesch\u00E4ftsstelle ausw\u00E4hlen'
		}
	},
	
	/**
	 * agency location array 
	 */
	locations: null,

	/**
	 * initialize the component
	 */
	init: function() {
		if (bmConfig.testComponent('google') && (this.locations = bmConfig.getComponent('google').locations)) {
			if ($E('.agencySearch .google_maps')) {
				if (this.locations.length > 1) {
					bm.agencysearch.createList();
					bm.agencysearch.addLinkEvents();
				} else if (!window.ie6) {
					$E('.agencySearch .google_maps').setStyle('margin-bottom', '2em');
				}
			}
		}
	},

	/**
	 * create a list with links to agencies
	 * hide all locations despite the first one
	 */
	createList: function() {
		var result = new Element('div', {
			'id': 'agencySwitch',
			'class': 'result'
		});
		var headline = new Element('h3').setText(bm.agencysearch.lang.agencySwitch.headline).injectInside(result);

		var list = new Element('ul', {
			'id': 'agencyList',
			'class': 'icList'
		});

		var link = '';
		for (var i = 0; i < this.locations.length; ++i) {
			var linktext = this.locations[i].zipcode + ' ' + this.locations[i].city + ', ' + this.locations[i].street;

			if (i==0) {
				link += '<li><a class="selected" href="#" rel="' + this.locations[i].id + '">' + linktext + '</a></li>';
			} else {
				link += '<li><a href="#" rel="' + this.locations[i].id + '">' + linktext + '</a></li>';
				this.hideLocation(this.locations[i].id);
			}
		}

		list.setHTML(link).injectInside(result);
		
		result.injectAfter($E('.agencySearch .google_maps'));
		
		if (!(window.ie6 || window.ie7)) {
			window.setTimeout(function(){
				bm.agencysearch.switchLocation(bm.agencysearch.locations[0].id);
			}, 2000);
		}
	},

	/**
	 * display a single location
	 * @param {String} id - id of location
	 */
	showLocation: function(id) {
		$('agency' + id).removeClass('hd');
	},

	/**
	 * hide a single location
	 * @param {String} id - id of location
	 */
	hideLocation: function(id) {
		$('agency' + id).addClass('hd');
	},

	/**
	 * add click event to linklist 
	 */
	addLinkEvents: function() {
		$$('#agencyList a').addEvent('click', function(e) {
			new Event(e).stop();
			var target = e.target || e.srcElement;
			var id = target.getProperty('rel');

			$$('#agencyList a').removeClass('selected');
			target.addClass('selected');

			bm.agencysearch.switchLocation(id);
		});
	},

	/**
	 * switch the location on the map and display address details accordingly
	 * @param {String} listId - id of selected agency in agency list 
	 */
	switchLocation: function(listId) {
		for (var i = 0; i < this.locations.length; ++i) {
			if (this.locations[i].id == listId) {
				if ((typeof bm.google != 'undefined') && (typeof bm.google.map != 'undefined')) {
					bm.google.map.setCenter(this.locations[i].point);
					bm.google.displayInfoWindow([this.locations[i]])();
				}
				bm.agencysearch.showLocation(this.locations[i].id);
			} else {
				bm.agencysearch.hideLocation(this.locations[i].id);
			}
		}
	}
}

/**
 * component: medical search
 * @description: adds the functionality to toggle the visibility of the extended search
 */

// add component to domready event list
window.addEvent('domready', function() {
	bm.medicalsearch.init();
});

bm.medicalsearch = {

	/**
	 * fieldset with search filters 
	 */
	searchResultFilter: null,

	/**
	 * initialize the component
	 */
	init: function() {
		if (this.searchResultFilter = $('medicalSearchResultFilter')) {
			this.hideSearchFilter();
			this.generateSearchOption();
		}
	},

	/**
	 * generate search option links
	 */
	generateSearchOption: function() {

		var text = bmConfig.getProperty('medicalsearch', 'app.label.fieldset.refineSearchResult');

		var button = new Element('p', {
			'class': 'button',
			'id': 'medicalSearchResultOption'
		});
		var span = new Element('span', {
			'class': 'but'
		}).injectInside(button);
		var link = new Element('a', {
			'class': 'ic',
			'href': '#',
			'title': text
		}).setText(text).injectInside(span);
		button.injectBefore(this.searchResultFilter);

		$('medicalSearchResultOption').addEvent('click', function(e) {
			new Event(e).stop();
			bm.medicalsearch.searchResultFilter.toggleClass('hd');
			$E('#medicalSearchResultOption a').toggleClass('minus');
		});
	},
	
	/**
	 * hide search filter
	 */
	hideSearchFilter: function() {
		this.searchResultFilter.addClass('hd');
	}
}


/**
 * component: google map
 * @description: object for google maps in barmer context
 */

bm.google = {

	/**
	 * language properties
	 */
	lang: {
		multipleResults: " Ergebnisse in ",
		route: {
			calculate: "Route berechnen",
			find: "Finde Route",
			print: "Route drucken",
			from: "Startadresse (Stra\u00DFe Nr., PLZ Ort)",
			to: "Zieladresse",
			headline: "Route nach/zu ",
			error: {
				generic: "Leider ist ein technischer Fehler aufgetreten. Bitte versuchen Sie es in wenigen Minuten erneut.",
				undetermined: "Leider war die angegebene Startadresse nicht eindeutig. Die am besten passende Adresse wurde f\u00FCr die Suche verwendet. Bitte korrigieren Sie evtl. die Startadresse.",
				notfound: "Leider konnte die angegebene Startadresse nicht gefunden werden. Bitte erg\u00E4nzen Sie evtl. die Hausnummer bzw. die Stadt oder \u00FCberpr\u00FCfen Sie die Schreibweise."
			}
		},
		backToList: "zur\u00FCck zur Liste",
		closeWindow: "Fenster schlie\u00DFen",
		travelMode: {
			type: 'Routentyp',
			driving: "Mit dem Auto",
			walking: "Fu\u00DFweg"
		}
	},
	
	/**
	 * google map object
	 */
	map: null,
	
	/**
	 * google map geocoder object
	 */
	geocoder: null,
	
	/**
	 * google map point state
	 */
	mapIsUptodate: false,
	
	/**
	 * initialize the component
	 */
	init: function() {
		if (bmConfig.testComponent('google')) {
			if (typeof google != 'undefined' && GBrowserIsCompatible() && $E('.google_maps')) {
				this.initIcons();
				this.initializeMap();
			}
		}
	},

	/**
	 * initialize the icons for various types of medical institutions
	 */
	initIcons: function() {
		this.locationIcons = {
			barmer: this.createMapIcon("Barmer_Map.png"),
			arzt: this.createMapIcon("Arzt_Map.png"),
			aerzte: this.createMapIcon("Aerzte_Map.png"),
			apotheke: this.createMapIcon("Apotheke_Map.png"),
			krankenhaus: this.createMapIcon("Krankenhaus_Map.png"),
			zahnarzt: this.createMapIcon("Zahnarzt_Map.png"),
			zahnaerzte: this.createMapIcon("Zahnaerzte_Map.png"),
			hilfsmittelberater: this.createMapIcon("Hilfsmittelberater_Map.png"),
			integrierteversorgung: this.createMapIcon("IntegrierteVersorgung_Map.png")
		}
	},

	/**
	 * create a customized google map icon
	 * @param {String} name of icon
	 */
	createMapIcon: function(name) {
	  	var path = assetPath + "img/gmaps/";

	  	var baseIcon = new GIcon(G_DEFAULT_ICON);
	  	baseIcon.shadow = path + "Barmer_Map_shadow.png";
	  	baseIcon.iconSize = new GSize(25, 33);
	  	baseIcon.shadowSize = new GSize(37, 34);
	  	baseIcon.iconAnchor = new GPoint(9, 34);
	  	baseIcon.infoWindowAnchor = new GPoint(9, 2);
	  	baseIcon.image = path + name;

	  	return baseIcon;
	},
	
	/**
	 * initialize the google map
	 */
	initializeMap: function() {
		$E(".google_maps").addClass('js');
		this.map = new GMap2($E(".google_maps"));
	    this.map.setCenter(new GLatLng(51.2608322, 7.1462908), 13);
		// set default UI like on maps.google.com
	    this.map.setUIToDefault();
		// reset scroll wheel zoom to default (disabled)
		this.map.disableScrollWheelZoom();
	    this.geocoder = new GClientGeocoder();
		if (bmConfig.google.locations){
			// get all Lat and Lng
			for (var i = 0; i < bmConfig.google.locations.length; ++i) {
				var callbackHandler = bm.google.addPointCallbackHandler(bmConfig.google.locations[i].id);			
				this.geocoder.getLatLng(bm.google.getAddressFromLocation(bmConfig.google.locations[i]), callbackHandler);		
			}
		}
	},

	/**
	 * implement a closure as a callback handler for the geocoder getLatLng method 
	 * @param {String} id - id of point
	 */
	addPointCallbackHandler: function(id) {
		return (function(point) {
			var allInformationAvailable = true;
	
			for (var i = 0; i < bmConfig.google.locations.length; ++i) {
				// update all addresses with Lat and Lng information
				if (bmConfig.google.locations[i].id == id ){
					bmConfig.google.locations[i].pointUpdated = true;
					if (point) {
						bmConfig.google.locations[i].point = point;
					}
				}
	
				// all Lat and Lng information updated?
				if (!bmConfig.google.locations[i].pointUpdated){
					allInformationAvailable = false;
				}
			}
	
			if (allInformationAvailable && !bm.google.mapIsUptodate) {
				bm.google.mapIsUptodate = true;
				bm.google.writeAllLocationsToMap();
			}
	    });
	},

	/**
	 * return the lat/long search string for a given location object
	 * @param {Object} location
	 */
	getAddressFromLocation: function(location) {
		return location.street + ', ' + location.zipcode + ' ' + location.city;
	},

	/**
	 * add marker for all points to google map
	 */
	writeAllLocationsToMap: function() {
		// create Map with same location and set processed
		var bounds = new GLatLngBounds;

		for (var i = 0; i < bmConfig.google.locations.length; ++i) {
			var addressesWithSameLocation = new Array();
			if (!bmConfig.google.locations[i].processed && bmConfig.google.locations[i].point) {
				addressesWithSameLocation.push(bmConfig.google.locations[i]);
				bmConfig.google.locations[i].processed = true;
				var moreThenOneLocationPerPoint = false;
				// find all with the same point
				for (var ii = 0; ii < bmConfig.google.locations.length; ++ii) {
					if (!bmConfig.google.locations[ii].processed && bmConfig.google.locations[ii].point && bmConfig.google.locations[ii].point.equals(bmConfig.google.locations[i].point)) {
						addressesWithSameLocation.push(bmConfig.google.locations[ii]);
						bmConfig.google.locations[ii].processed = true;
						moreThenOneLocationPerPoint = true;
					}
				}
	
				// write to map
				var markerOptions = {
					icon: bm.google.locationIcons[bmConfig.google.locations[i].icon]
				};
				
				if (moreThenOneLocationPerPoint) {
					if (bmConfig.google.locations[i].icon == 'arzt') {
						markerOptions.icon = bm.google.locationIcons.aerzte;
					} else if (bmConfig.google.locations[i].icon == 'zahnarzt') {
						markerOptions.icon = bm.google.locationIcons.zahnaerzte;
					}
				} 
	
				var marker = new GMarker(addressesWithSameLocation[0].point, markerOptions);
				var displayInfoWindow = bm.google.displayInfoWindow(addressesWithSameLocation);
	
				GEvent.addListener(marker,"click", displayInfoWindow);
	    		bm.google.map.setCenter(addressesWithSameLocation[0].point, 13);
				bounds.extend(bmConfig.google.locations[i].point);
				bm.google.map.addOverlay(marker);
			}
		}
		
		// find best zoom
		if (bmConfig.google.locations.length > 1){
			bm.google.map.setZoom(bm.google.map.getBoundsZoomLevel(bounds));
			var clat = (bounds.getNorthEast().lat() + bounds.getSouthWest().lat()) /2;
			var clng = (bounds.getNorthEast().lng() + bounds.getSouthWest().lng()) /2;
			bm.google.map.setCenter(new GLatLng(clat,clng));	
		}
	},

	/**
	 * create and display the content of the info window (closure)
	 * @param {Object} locationList - array of location points
	 */
	displayInfoWindow: function(locationList){
		return (function(){
			var listview = locationList.length > 1 ? true : false;
			var myHtml = '<div class="mapAddress cl">';
			var hideClass = listview ? ' hd' : ''; 
	
			// create overview
			if (listview){
				myHtml += '<div class="mapAddressList cl">';
				myHtml += '<p>' + locationList.length + bm.google.lang.multipleResults + '<strong>' + locationList[0].street + '</strong></p>';
				myHtml += '<ul>';
				for (var i = 0; i < locationList.length; ++i) {
					myHtml += '<li><h4><a class="ic" href="#" rel="' + locationList[i].id + '">' + locationList[i].name + '</a></h4>';
					myHtml += '<address>';
					if (locationList[i].speciality){
						myHtml += locationList[i].speciality + '<br />';
					}
					myHtml += '</address></li>';
				}
				myHtml += '</ul></div>';
			}
			
			// create detail box for each entry
			for (var i = 0; i < locationList.length; ++i) {
				myHtml += '<div class="mapAddressDetail' + hideClass + '" id="mapAddress' + locationList[i].id + '">';
				myHtml += '<h4>' + locationList[i].name + '</h4>';
				myHtml += '<address>';
				if (locationList[i].speciality){
					myHtml += locationList[i].speciality + '<br />';
				}
				myHtml += locationList[i].street + '<br />';
				myHtml += locationList[i].zipcode + ' ' + locationList[i].city + '<br />';
				if (locationList[i].telephone) {
					myHtml += locationList[i].telephone;
				}
				myHtml += '</address>';
				myHtml += '</div>';
			}
	
			myHtml += '<div class="findRouteBox' + hideClass + '">';
			myHtml += '<p class="calculateRoute"><a class="ic" href="#">' + bm.google.lang.route.calculate + '</a></p>';
			myHtml += '<form class="findRoute hd" action="#"><p>';
			myHtml += '<label for="departure">' + bm.google.lang.route.from + '</label>';
			myHtml += '<input class="text" id="departure" name="departure" type="text" size="30" />';
			myHtml += '<input class="submit" type="submit" value="' + bm.google.lang.route.find + '" />';
			myHtml += '</p></form>';
			myHtml += '</div>';
			
			if (listview){
				myHtml += '<p class="mapAddressBack hd"><span class="previous"><a class="ic" href="#">' + bm.google.lang.backToList + '</a></span></p>';
			}
	
			myHtml += '</div>';

			// add new html to infowindow
			bm.google.map.openInfoWindowHtml(locationList[0].point, myHtml, {
				maxWidth: '320',
				onOpenFn: function() {
					// add events to infowindow
					bm.google.addInfoWindowEvents(locationList);
					
					var content = new GInfoWindowTab('label', $E('.mapAddress'));
					bm.google.map.updateInfoWindow([content], function() {
						// resize infowindow
						bm.google.adjustInfoWindow(locationList);
					});
				}
			});
		});
	},

	/**
	 * adjust the height of the infoWindow
	 * @param {Object} locationList - array of location points
	 */
	adjustInfoWindow: function(locationList) {
		var infoWindow = bm.google.map.getInfoWindow();
		var tabContent = infoWindow.getTabs();
		var infoWindowWidth = tabContent[0].contentElem.scrollWidth > 320 ? 320 : tabContent[0].contentElem.scrollWidth;
		var infoWindowHeight = tabContent[0].contentElem.scrollHeight;

		infoWindow.reset(locationList[0].point, tabContent, new GSize(infoWindowWidth,infoWindowHeight), null, null);
	},

	/**
	 * add events to new infowindow html
	 * @param {Object} locationList - array of location points
	 */
	addInfoWindowEvents: function(locationList) {
		// function to be triggered on submit of find route
		var submitFindRoute = function(e) {
			new Event(e).stop();

			// shadowbox content
			var myRouteBox = new bm.google.RouteShadowbox($E('.mapAddress .findRouteBox form input.text').value, locationList[0]);
			myRouteBox.show();
		};

		/**
		 * show details of a single location
		 */
		$$('.mapAddress .mapAddressList h4 a').addEvent('click', function(e) {
			new Event(e).stop();
			var target = e.target ? e.target : e.srcElement;
			
			while (target.nodeName != 'A') {
				target = target.parentNode;
			}
			var id = target.getProperty('rel');

			$E('.mapAddressList').addClass('hd');
			$('mapAddress'+id).removeClass('hd');
			$E('.findRouteBox').removeClass('hd');
			$E('.calculateRoute').removeClass('hd');
			$E('.findRoute').addClass('hd');
			$E('.mapAddressBack').removeClass('hd');

			// workaround to hide "persistent" focus/hover state in IE
			if (window.ie6 || window.ie7) {
				var tempParent = target.getParent().getParent();
				var tempLink = target.getParent().clone();
				target.getParent().remove();
				tempLink.injectTop(tempParent);
			}

			var content = new GInfoWindowTab('label', $E('.mapAddress'));
			bm.google.map.updateInfoWindow([content], function() {
				// resize infowindow
				bm.google.adjustInfoWindow(locationList);
			});
		});

		/**
		 * show all locations in a list
		 */
		$$('.mapAddress .previous a').addEvent('click', function(e) {
			new Event(e).stop();
			var target = e.target ? e.target : e.srcElement;

			$E('.mapAddressList').removeClass('hd');
			$$('.mapAddressDetail').addClass('hd');
			$E('.findRouteBox').addClass('hd');
			$E('.findRoute').addClass('hd');
			$E('.mapAddressBack').addClass('hd');

			// workaround to hide "persistent" focus/hover state in IE
			if (window.ie6 || window.ie7) {
				var tempLink = target.getParent().clone();
				target.getParent().remove();
				tempLink.injectInside($E('.mapAddressBack'));
			}

			var content = new GInfoWindowTab('label', $E('.mapAddress'));
			bm.google.map.updateInfoWindow([content], function() {
				// resize infowindow
				bm.google.adjustInfoWindow(locationList);
			});
		});

		/**
		 * show the input fields to enter a 'from' location
	 	 * resize the infowindow to fit to new content
		 */
		$E('.mapAddress .findRouteBox .calculateRoute a').addEvent('click', function(e) {
			new Event(e).stop();
			var target = e.target ? e.target : e.srcElement;

			$E('.calculateRoute').addClass('hd');
			$E('.findRoute').removeClass('hd');
			if ($E('.mapAddressBack')) {
				$E('.mapAddressBack').setStyle('float', 'left');

				// workaround to hide "persistent" focus/hover state in IE
				if (window.ie6 || window.ie7) {
					var tempLink = target.getParent().clone();
					target.getParent().remove();
					tempLink.injectTop($E('.findRouteBox'));
				}
			}
			

			var content = new GInfoWindowTab('label', $E('.mapAddress'));
			bm.google.map.updateInfoWindow([content], function() {
				// resize infowindow
				bm.google.adjustInfoWindow(locationList);

				$E('.findRoute input').focus();
			});
		});

		/**
		 * submit the route
		 */
		$E('.mapAddress .findRouteBox form input.submit').addEvent('click', submitFindRoute);

		/**
		 * submit the route
		 */
		$E('.mapAddress .findRouteBox form').addEvent('submit', submitFindRoute);
	},

	/**
	 * Class RouteShadowbox
	 * @param {Object} sourceAddress
	 * @param {Object} targetAddress
	 */
	RouteShadowbox: new Class({
		map : null,
		gdir : null,
		addressSuggestion :null,
		addressSuggestionIndex :0,

		initialize: function(sourceAddress, address){
			this.sourceAddress = sourceAddress;
			this.targetAddress = bm.google.getAddressFromLocation(address);
			this.targetName = address.name;
		},

		/**
		 * show content of shadowbox
		 */
		show: function(){
			// wrapper div
			var shadowboxContentWrapper = new Element('div');
			var shadowboxContent = new Element('div', {
				'class': 'google_maps_route'
			}).injectInside(shadowboxContentWrapper);
		
			// print link
			var printLinkBox = new Element('p', {
				'class': 'print'
			});
			var printLink = new Element('a', {
				'class': 'ic',
				'href': '#'
			}).setText(bm.google.lang.route.print).injectInside(printLinkBox);
			printLinkBox.injectInside(shadowboxContent);
	
			// close link
			var closeLinkBox = new Element('p', {
				'class': 'close'
			});
			var closeLink = new Element('a', {
				'class': 'ic',
				'href': '#'
			}).setText(bm.google.lang.closeWindow).injectInside(closeLinkBox);
			closeLinkBox.injectInside(shadowboxContent);
	
			// headline
			var headline = new Element('h3').setText(bm.google.lang.route.calculate).injectInside(shadowboxContent);

			// main shadowbox content
			var mainContent = '<div class="routeLeftCol">';
			mainContent += '<form class="routeForm cl" action="#"><p class="routeFrom">';
			mainContent += '<label for="fromAddress">' + bm.google.lang.route.from + '</label>';
			mainContent += '<input type="text" class="text" size="25" id="fromAddress" name="fromAddress" value="' + this.sourceAddress + '" />';
			mainContent += '</p><p class="routeTo">';
			mainContent += '<span class="label">' + bm.google.lang.route.to + '</span> <strong>' + this.targetAddress + '</strong>';
			mainContent += '</p><p class="travelMode">';
			mainContent += '<label for="travelMode">' + bm.google.lang.travelMode.type + '</label>';
			mainContent += '<select id="travelMode" name="travelMode">';
			mainContent += '<option value="DRIVING">' + bm.google.lang.travelMode.driving + '</option>';
			mainContent += '<option value="WALKING">' + bm.google.lang.travelMode.walking + '</option>';
			mainContent += '</select>';
			mainContent += '</p><p class="submitButton">';
			mainContent += '<input type="submit" class="submit" value="' + bm.google.lang.route.calculate + '" title="' + bm.google.lang.route.calculate + '" />';
			mainContent += '</p></form>';
			mainContent += '<h4>' + bm.google.lang.route.headline + this.targetName + '</h4>';
			mainContent += '<div class="routeDirections"></div>';
			mainContent += '</div>';
			mainContent += '<div class="routeMap"></div>';
	
			var mainContentDiv = new Element('div', {
				'class': 'routeWrapper'
			}).setHTML(mainContent).injectInside(shadowboxContent);
	
			// append on finish hook function to shadowbox options
			bm.shadowbox.options.onFinish = this.afterShadowboxLoaded(this);
			
			bm.shadowbox.init();
		
			// open shadowbox
			Shadowbox.open({
				content: shadowboxContentWrapper.innerHTML,
				player: 'html',
				height: 650,
				width: 930
			}, bm.shadowbox.options);
		},
	
		/**
		 * add events to shadowbox content after it is loaded and initialize the map
		 * @param {Object} box - instance of bm.google.RouteShadowbox
		 */
		afterShadowboxLoaded: function(box) {
			return function() {
				var travel = G_TRAVEL_MODE_DRIVING;
				var removeMessages = true;
				
				// function to be triggered on form submit
				var submitForm = function(e) {
					new Event(e).stop();
					box.sourceAddress = $('fromAddress').value;
					travel = $('travelMode').value=="WALKING" ? G_TRAVEL_MODE_WALKING : G_TRAVEL_MODE_DRIVING;

					// load new directions
					box.loadGDir(box, travel);
				}
				
				// event: print
				$E('#shadowbox .google_maps_route .print a').addEvent('click', function(e) {
					new Event(e).stop();
					window.print();
				});

				// event: close
				$E('#shadowbox .google_maps_route .close a').addEvent('click', function(e) {
					new Event(e).stop();
					Shadowbox.close();
				});

				// event: form submit
				$E('#shadowbox .google_maps_route .routeForm .submit').addEvent('click', submitForm);

				// event: form focus (enter key handling)
				$E('#shadowbox .google_maps_route .routeForm').addEvent('submit', submitForm);				

				//init maps
		    	box.map = new GMap2($E('.routeMap'));
		    	box.map.setCenter(new GLatLng(51.2608322, 7.1462908), 13);
		    	box.map.setUIToDefault();
				box.gdir = new GDirections(box.map, $E('.routeDirections'));
				// load new directions
				box.loadGDir(box, travel);
				
				// event listener for directions
				GEvent.addListener(box.gdir, "load", function(){
					// remove previous errors
					if (removeMessages) {
						box.removeErrorMessage();
					} else {
						removeMessages = true;
					}
				});

				GEvent.addListener(box.gdir, "addoverlay", function(){
					// styling for copyright notice
					var copyright = $$('#shadowbox .routeDirections .googledir div').getLast();
					copyright.setStyles({
						'color': '#565656',
						'font-size': '.833em',
						'text-align': 'right'
					});
				});

				GEvent.addListener(box.gdir, "error", function(){
					// get error code
					var status = box.gdir.getStatus();

					box.removeErrorMessage();

					if (status.code == G_GEO_UNKNOWN_ADDRESS){
						// try to find best suitable address
						if (box.addressSuggestion){
							box.addressSuggestionIndex++;
							if (box.addressSuggestion.Placemark.length > box.addressSuggestionIndex){
								// test next address
								$('fromAddress').value = box.addressSuggestion.Placemark[box.addressSuggestionIndex].address;
								box.sourceAddress = box.addressSuggestion.Placemark[box.addressSuggestionIndex].address;
								// load new directions
								box.loadGDir(box, travel);
							} else {
									box.createErrorMessage(box, G_GEO_UNKNOWN_ADDRESS);
							}
						} else {
							bm.google.geocoder.getLatLng(box.sourceAddress, function(point){
								if (!point){
									box.createErrorMessage(box, status.code);
								} else {
									removeMessages = false;
									box.createErrorMessage(box, 10000); // barmer specific code range > 10000
	
									bm.google.geocoder.getLocations(point, function(response) {
										box.addressSuggestion = response;
										$('fromAddress').value = response.Placemark[0].address;
										box.sourceAddress = response.Placemark[0].address;
										// load new directions
										box.loadGDir(box, travel);
									})
								}
							});
						}
					} else {
						// create new error message
						box.createErrorMessage(box, status.code);
					}
				});

				// set focus on first input field
				$E('#shadowbox .google_maps_route input.text').focus();
			}
		},

		/**
		 * prepare google direction string
		 * @param {String} source - source address
		 * @param {String} target - target address
		 */
		getGDir: function(source, target) {
			return 'from: ' + source + ' to: ' + target;
		},

		/**
		 * prepare google direction string
		 * @param {Object} box - instance of bm.google.RouteShadowbox
		 * @param {String} travel - travel mode
		 */
		loadGDir: function(box, travel) {
			box.gdir.load(box.getGDir(box.sourceAddress, box.targetAddress+', Deutschland'), {
				'locale': 'de',
				travelMode: travel
			});
		},

		/**
		 * map google error code to barmer specific error messages
		 * @param {String} code - error code
		 */
		mapError: function(code) {
			switch (code) {
				case G_GEO_UNKNOWN_ADDRESS:
					code = 'notfound';
					break;
				case 10000:
					code = 'undetermined';
					break;
				default:
					code = 'generic';
			}

			return bm.google.lang.route.error[code];
		},

		/**
		 * create an error message
		 * @param {Object} box - instance of bm.google.RouteShadowbox
		 * @param {String} code - error code
		 */
		createErrorMessage: function(box, code) {
			// create new text and add to DOM
			var text = new Element('p', {
				'class': 'error'
			}).setText(box.mapError(code)).injectBefore($E('.routeDirections'));
		},

		/**
		 * remove previous error messages
		 */
		removeErrorMessage: function() {
			var errors = $$('#shadowbox .google_maps_route .error');
			for (var i=0; i<errors.length; i++) {
				errors[i].remove();
			}
		}
	})
}


// add component to domready event list
window.addEvent('domready', function() {
	bm.google.init();
});




