/* common */
if ( !window.pc3 ) window.pc3 = {};
var pc3 = window.pc3;

pc3.Browser = (function(){
	var ua = navigator.userAgent;
	var isOpera = Object.prototype.toString.call(window.opera) == '[object Opera]';
	
	var browser = {
		'features':{},
		'IE':             !!window.attachEvent && !isOpera,
		'Opera':          isOpera,
		'WebKit':         ua.indexOf('AppleWebKit/') > -1,
		'Gecko':          ua.indexOf('Gecko') > -1 && ua.indexOf('KHTML') === -1,
		'MobileSafari':   /Apple.*Mobile/.test(ua)
	};
	
	var ffVersion = browser.Gecko?parseInt(ua.substring(ua.indexOf("Firefox")+8)):0;
	var ieVersion = browser.IE?parseInt(ua.substring(ua.indexOf("MSIE")+5)):0;
	
	browser.FF4 = ffVersion == 4;
	browser.FF5 = ffVersion == 5;
	browser.IE6 = ieVersion == 6;
	browser.IE7 = ieVersion == 7;
	browser.IE8 = ieVersion == 8;
	browser.IE9 = ieVersion == 9;
	browser.Safari = ( browser.WebKit && ua.indexOf("Safari") > 1 && ua.indexOf("Chrome") < 1 );
	
	return browser;
})();

function cp(event){
	if ( window.Event && window.Event.extend ) {
		event = Event.extend(event?event:window.event);
		event.stop();
	} else if ( event ) {
		if ( document.all ) window.event.cancelBubble=true;
		else event.stopPropagation();
	}
}

function addScrollPosition(link) {
	var windowScrollPositions = getWindowScrollPositions();
	
	link.href +=
		(link.href.search(/\?/) > 0?'&':'?')
		+ 'pc3Scroll='
		+ windowScrollPositions['left']
		+ 'x'
		+ windowScrollPositions['top']
	;
}

function applyScrollPosition(){
	var key;
	var match = document.location.search.match('pc3Scroll=([0-9]+)x([0-9]+)');
	if ( !match ) return;
	
	setWindowScrollPositions(match[1], match[2]);
}

/**
 * set the scrollposition of the window
 * 
 * @author acn
 * @param {int} left position from left of the top-left corner of the window
 * @param {int} top position from top of the top-left corner of the window
 */
function setWindowScrollPositions(left, top) {
	if ( typeof window.pageXOffset != 'undefined' && typeof window.pageYOffset != 'undefined' ) {
		window.scrollTo(left, top);
	}
	else if ( typeof document.compatMode != 'undefined' && document.compatMode != 'BackCompat' ) {
		document.documentElement.scrollLeft = left;
		document.documentElement.scrollTop = top;
	}
	else if ( typeof document.body != 'undefined' ) {
		document.body.scrollLeft = left;
		document.body.scrollTop = top;
	}
}

/**
 * get the scrollposition of the window
 * 
 * @author acn
 * @return {array} windowScrollPositions['left'] and windowScrollPositions['top']
 */
function getWindowScrollPositions() {
	var windowScrollPositions = {};
		windowScrollPositions['left'] = 0;
		windowScrollPositions['top']  = 0;
	
	if (  typeof window.pageXOffset != 'undefined' && typeof window.pageYOffset != 'undefined' ) {
		windowScrollPositions['left'] = window.pageXOffset;
		windowScrollPositions['top'] = window.pageYOffset;
	}
	else if ( typeof document.compatMode != 'undefined' && document.compatMode != 'BackCompat' ) {
		windowScrollPositions['left'] = document.documentElement.scrollLeft;
		windowScrollPositions['top'] = document.documentElement.scrollTop;
	}
	else if ( typeof document.body != 'undefined' ) {
		windowScrollPositions['left'] = document.body.scrollLeft;
		windowScrollPositions['top'] = document.body.scrollTop;
	}
	
	return windowScrollPositions;
}

/**
 * Get the GET parameters from the URL.<br>
 * <ul><li>If no filter is defined, all URL parameters are returned.</li><li>If a filter is defined (array with parameter keys), only these parameters are returned.</li></ul>
 * Note: parameter names and parameter values are case sensitive.<br>
 * 
 * @author acn
 * @param {Array} filter : If the paramter filter isn't defined, all URL paramters are collected and returned. If you are looking for specific parameters, you can define the filter with an array.
 * @return {Object} urlParams : The parameter name is used as the name of the object member variable, the according value is the parameter value. Note that if no parameter is found, an empty object is returned. 
 */
function getUrlParam(filter) {
	var urlParamNames = null;
	var href = window.location.href;
	
	if (!href) return;
	var urlParamNames = new Array();
	var regExp = /[\?&]([^=]+)=/g;
	
	while ((results = regExp.exec(href)) != null) urlParamNames.push(results[1]);
	
	if (!urlParamNames || urlParamNames.length < 1) return;
	
	var urlParams = new Object();
	var uPs = new Object();
	var name, regExpS, regExp, result;
	
	for (var i = 0; i < urlParamNames.length; i++) {
		name = urlParamNames[i].replace(/[\[]/, '\\\[').replace(/[\]]/, '\\\]'); // escape square brackets for regExpS (PHP-style)
		
		regExpS = '[\\?&]'+ name +'=([^&#]*)';
		regExp = new RegExp(regExpS);
		result = regExp.exec(href);
		
		name = name.replace(/[\\]/g, ''); // re-escape square brackets
		uPs[name] = result[1];
	}
	
	var behaviour = arguments.length; // 0 : no filter; all url params asked, 1 : filter; array with asked param names
	switch (behaviour) {
		case 1 :
			for (var idx in filter) {
				key = filter[idx];
				if (uPs[key]) urlParams[key] = uPs[key];
			}
			break;

		case 0 :
		default:
			urlParams = uPs;
	}
	
	return urlParams;
}

/**
 * @author cri
 */
function getCookieParam(paramName) {
	var params = document.cookie;
	if (params == '') return;
	
	var cookieParams = new Object;
	var cPs = new Object;
	
	//-- get all url params (for internal use)
	cookies = params.split('; '); // array with 'key=value'
	for (var i = 0; i < cookies.length; ++i) {
		var keyAndValue = cookies[i];
		keyAndValue = keyAndValue.split('='); // array with 0 = 'key' and 1 = 'value'
		
		var key = null;
		var value = null;
		
		key = keyAndValue[0];
		if (keyAndValue[1]) value = keyAndValue[1];
		cPs[key] = value;
	}
	//--
	
	//-- filter params when wanted
	var behaviour = arguments.length; // 0 : no filter; all url params asked, 1 : filter; array with asked param names
	switch (behaviour) {
		case 1 : // array given, loop over all and collect only wanted for return
			for (var idx in paramName) {
				key = paramName[idx];
				if (cPs[key]) cookieParams[key] = cPs[key];
			}
			break;
		
		case 0 :
		default:
			cookieParams = cPs;
	}
	//--
	
	return cookieParams;
}

/**
 * Set GET parameters on a link object (link.href).<br>
 * Keeps (or overwrites) existing parameters and adds nonexisting ones.<br>
 * 
 * @author acn
 * @param {Object} HTML link object (DOM)
 * @param {Object} params containing member variables are used as key, values as value
 * @return void
 */
function setUrlParam(link, params) {
	if (!link.href) return;
	if (!params || typeof params == 'undefined' || typeof params != 'object' || isEmpty(params)) return;
	
	var urlParams = new Object();
	var doEscape = false;
	
	var before = '';
	var href = new String(link.href); // get url from link object, may contain "garbage code" like "javascript void; window.open(..." and my be 'pc3-like' encoded
	var after = '';
	
	var regExpHref = /(.*window\.open\((?:%22))([^,]*)((?:%22)(?:,|).*)/i; // get url from window.open() command
	if ((results = href.match(regExpHref))) {
		doEscape = true;
		
		before = results[1];
		href = results[2];
		after = results[3];
	}
	
	decHref = unescape(href).replace(/\\/g, ''); // decode 'pc3-like' encoding
	
	var results = '';
	var regExpGets = /[\?&]([^=]+)=([^&#]*)/gi; // get all existing get params
	while ((results = regExpGets.exec(decHref)) != null) urlParams[results[1]] = results[2];
	
	for (var key in params) urlParams[key] = params[key]; // overwrite existing, add new ones
	
	var regExpUrl = /([^?]+)/i; // get url without get params
	var results = decHref.match(regExpUrl);
	var url = results[1];
	
	var gets = '?'; // collect all get params
	for (var key in urlParams) {
		if (doEscape) gets += key +'='+ urlParams[key] +'&';
		else gets += escape(key) +'='+ escape(urlParams[key]) +'&';
	}
	gets = gets.substring(0, gets.length - 1); // trim last &
	
	if (doEscape) { // encode 'pc3-like'
		url = escape(url);
		url = url.replace(/\//g, '%5C%2F');
		
		gets = escape(gets); // nothing escaped until now
	}
	
	url = before + url + gets + after; // build new url
	
	link.href = url;
}


/**
 * Check if object is empty (no member variables).
 * 
 * @author acn
 * @param {Object} object
 * @return boolean
 */
function isEmpty(object) {
	for (var prop in object) if (object.hasOwnProperty(prop)) return false;
	
	return true;
}

function pc3CreateElementsByHTML(html,parent,parentTag){
	if ( !html ) return new Array(); //empty html
	
	var nestingLevel = 0;
	var content = document.createElement('div');
	
	parentTag = (parent?parent.nodeName:parentTag);
	
	switch( parentTag ) {
		case 'TR':
			html = '<table><tbody><tr>'+ html +'</tr></tbody></table>';
			nestingLevel = 3;
			break;
			
		case 'TBODY':
			html = '<table><tbody>'+ html +'</tbody></table>';
			nestingLevel = 2;
			break;
			
		case 'TABLE':
			html = '<table>'+ html +'</table>';
			nestingLevel = 1;
			break;
	}
	
	content.innerHTML = html;
	
	if ( !content.firstChild ) {
		// 20081223.acn : BUG #437
		// alert('failed to create: '+ html + ' within '+ parentTag);
		return null;
	}
	
	while ( nestingLevel-- > 0 ) {
		content = content.removeChild(content.firstChild);
	};
	
	var childs = new Array();
	
	while( content.firstChild ) {
		var child = content.removeChild(content.firstChild);
		
		if ( parent ) parent.appendChild(child);
		childs.push(child);
	}
	
	return childs;
}

function pc3GetOuterDimension(element){
	var dimension = {};
	var locations = new Array('Left','Top','Right','Bottom');
	for (var i = 0; i<=3; i++){
		var location = locations[i];
		var styleLocation = location.toLowerCase();
		dimension['offset'+location] = (pc3GetStyle(element, 'border-'+styleLocation+'-style')=='none'?0:parseInt((pc3GetStyle(element, 'border-'+styleLocation+'-width')?pc3GetStyle(element, 'border-'+styleLocation+'-width'):0))) + parseInt((pc3GetStyle(element, 'padding-'+styleLocation)?pc3GetStyle(element, 'padding-'+styleLocation):0));
		dimension['margin'+location] = parseInt((pc3GetStyle(element, 'margin-'+styleLocation)?pc3GetStyle(element, 'margin-'+styleLocation):0));
	}
	dimension.offsetsX = dimension.offsetLeft + dimension.offsetRight;
	dimension.offsetsY = dimension.offsetTop + dimension.offsetBottom;
	dimension.width = (element.offsetWidth<0?0:element.offsetWidth);
	dimension.innerWidth = dimension.width - dimension.offsetsX;
	dimension.width = dimension.width + dimension.marginLeft + dimension.marginRight;
	dimension.height = (element.offsetHeight<0?0:element.offsetHeight);
	dimension.innerHeight = dimension.height - dimension.offsetsY;
	dimension.height = dimension.height + dimension.marginTop + dimension.marginBottom;
	return dimension;
}


function pc3GetStyle(element, property){
	var value = '';
	if ( element.currentStyle ){
		var propertyParts = property.split('-');
		property = propertyParts[0];
		for ( var i=1; i<propertyParts.length;i++){
			property = property + propertyParts[i].charAt(0).toUpperCase() + propertyParts[i].substr(1);
		}
		value = element.currentStyle[property];
	} else if ( window.getComputedStyle ){
		value = window.getComputedStyle(element, null).getPropertyValue(property);
	}
	return value;
}


function dc(code){
	code = Base64.decode(code);
	
	var plain = '';
	
	for(var i=0;i<code.length;i++) {
		plain += String.fromCharCode(code.charCodeAt(i)^xEncryptionKey.charCodeAt(i%xEncryptionKey.length));
	}
	
	return plain;
}

function dcw(code){ document.write(dc(code)); }
function dcm(code){ return 'mailto:'+ dc(code); }

var Base64 = {

    // private property
    _keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",

    // public method for encoding
    encode : function (input) {
        var output = "";
        var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
        var i = 0;

        input = Base64._utf8_encode(input);

        while (i < input.length) {

            chr1 = input.charCodeAt(i++);
            chr2 = input.charCodeAt(i++);
            chr3 = input.charCodeAt(i++);

            enc1 = chr1 >> 2;
            enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
            enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
            enc4 = chr3 & 63;

            if (isNaN(chr2)) {
                enc3 = enc4 = 64;
            } else if (isNaN(chr3)) {
                enc4 = 64;
            }

            output = output +
            this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) +
            this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);

        }

        return output;
    },

    // public method for decoding
    decode : function (input) {
        var output = "";
        var chr1, chr2, chr3;
        var enc1, enc2, enc3, enc4;
        var i = 0;

        input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");

        while (i < input.length) {

            enc1 = this._keyStr.indexOf(input.charAt(i++));
            enc2 = this._keyStr.indexOf(input.charAt(i++));
            enc3 = this._keyStr.indexOf(input.charAt(i++));
            enc4 = this._keyStr.indexOf(input.charAt(i++));

            chr1 = (enc1 << 2) | (enc2 >> 4);
            chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
            chr3 = ((enc3 & 3) << 6) | enc4;

            output = output + String.fromCharCode(chr1);

            if (enc3 != 64) {
                output = output + String.fromCharCode(chr2);
            }
            if (enc4 != 64) {
                output = output + String.fromCharCode(chr3);
            }

        }

        output = Base64._utf8_decode(output);

        return output;

    },

    // private method for UTF-8 encoding
    _utf8_encode : function (string) {
        string = string.replace(/\r\n/g,"\n");
        var utftext = "";

        for (var n = 0; n < string.length; n++) {

            var c = string.charCodeAt(n);

            if (c < 128) {
                utftext += String.fromCharCode(c);
            }
            else if((c > 127) && (c < 2048)) {
                utftext += String.fromCharCode((c >> 6) | 192);
                utftext += String.fromCharCode((c & 63) | 128);
            }
            else {
                utftext += String.fromCharCode((c >> 12) | 224);
                utftext += String.fromCharCode(((c >> 6) & 63) | 128);
                utftext += String.fromCharCode((c & 63) | 128);
            }

        }

        return utftext;
    },

    // private method for UTF-8 decoding
    _utf8_decode : function (utftext) {
        var string = "";
        var i = 0;
        var c = c1 = c2 = 0;

        while ( i < utftext.length ) {

            c = utftext.charCodeAt(i);

            if (c < 128) {
                string += String.fromCharCode(c);
                i++;
            }
            else if((c > 191) && (c < 224)) {
                c2 = utftext.charCodeAt(i+1);
                string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
                i += 2;
            }
            else {
                c2 = utftext.charCodeAt(i+1);
                c3 = utftext.charCodeAt(i+2);
                string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
                i += 3;
            }

        }

        return string;
    }

};

/**
 * catch console.log calls on browsers without console
 * 
 * @author acn
 */ 
if (!window.console) {
	var a = false;
	var uP = getUrlParam(new Array('pc3JSDebug'));
	if (uP && uP.pc3JSDebug == '1') a = true;
	
	window.console = {
		log: function(m){ if(a) alert('console.log\n'+ m); },
		debug: function(m){ if(a) alert('console.debug\n'+ m); },
		info: function(m){ if(a) alert('console.info\n'+ m); },
		warn: function(m){ if(a) alert('console.warn\n'+ m); },
		error: function(m){ if(a) alert('console.error\n'+ m); }
	};
}

/**
 * @author acn
 */
if (!pc3) var pc3 = function(){};

pc3.trackLink = function(tracking) {
	if (!pageTracker) return;
	if (!pageTracker._trackEvent) return;
	
	/*
	 * google
	 * 
	 * @see http://code.google.com/intl/de-DE/apis/analytics/docs/tracking/gaTrackingOverview.html
	 * @see http://code.google.com/intl/de-DE/apis/analytics/docs/tracking/eventTrackerGuide.html
	 */
	pageTracker._trackEvent(tracking.category, tracking.action, tracking.label, tracking.value);
};

/**
 * @author acn
 */
function replaceRssWithXml() {
	if (!/Safari/.test(navigator.userAgent) && !/MSIE (\d+\.\d+);/.test(navigator.userAgent)) return; // ms ie and safari only
	
	var anchors = document.links;
	var regexp = /\.rss(?!\.)/i; // '.rss' allowed, '.rss.' disallowed
	
	for (var i = 0; i < anchors.length; i++) { // loop over each entry
		var href = anchors[i].href;
		if (regexp.test(href)) { // modify only if attribute 'href' do match regexp
			href = href.replace(regexp, '.xml');
			anchors[i].href = href;
		}
	}
}
