// constants
var checkStatusInterval = 60000; // Intervallzeit für den Statuscheck
var showLoadingDuration = 700; // Mindestanzeigedauer der Ladeanzeige in ms

// global vars
var $wd_content, $topnav, $loading, $load_msg, $load_msg_status, $error_msg, $error_msg_status, kundeAfterBackend = 0;

// for status request
var executeCheckStatus = true; // Flag für Ausführung von Status Request (siehe Status.js)
var setExecuteCheckStatus = function(execute) {
	if(execute) {
		executeCheckStatus = true;
		document.cookie = 'status-request=on';
	}
	else {
		executeCheckStatus = false;
		document.cookie = 'status-request=off';
	}
};

// requests
var requests = new Array();
requests.abort = function() {
	while(this.length > 0){
		var req = this.pop();
		if(req){
			console.info('aborting request: ', req);
			req.abort();
			console.groupEnd();
		}
	}
};
requests.remove = function(req) {
	var idx = -1;
	for (var i=0; i<this.length; i++) {
		if (req == this[i]) {
			idx = i;
			break;
		}
	}
	if (idx != -1)
		this.splice(idx,1);
};

var scrollToAnchor = function(hash)
{
	// substr() statt replace() (wie oben), weil einige anchors
	// das #-zeichen drin im hash haben (z.b. bei Lieferanten)
	var aname = hash.substr(1),
		$anchor = $("a[name='" + aname + "']"),
		offset=0;
	console.log('scrollToAnchor() anchor name='+aname+', target=',$anchor);

	// hack for IE because of layout
	if ($.browser.msie) {
		var borderTopWidthCss = $wd_content.css('border-top-width');
		if (borderTopWidthCss) {
			offset = -parseInt(borderTopWidthCss.match(/\d+/))
		}
	}
	// scroll wd-content container to anchor
	$wd_content.scrollTo($anchor, {axis:'y', duration:1500, queue:false, offset:offset});
};

// Ladeanzeige
var loadingStart = function() {
	//console.log('loadingStart()...'+ $loading.is(':visible'));
	if (!$loading.is(':visible')) {
		$loading.show();
	}
	$error_msg.hide();
	$load_msg.show();
	$loading.data("tstart", new Date().getTime())
	.stop(true)
	.animate({ opacity: 0 }, { duration: 50 }) // wait
	.animate({ opacity: 1 }, { duration: 0 });
};
var loadingStop = function() {
	//console.log('loadingStop()...'+ $loading.is(':visible'));
	var wait = $error_msg.is(':visible') ? 5000 : 0,
		tstart = $loading.data("tstart");
	if (wait == 0 && tstart) { // success
		wait = Math.max(showLoadingDuration - (new Date().getTime() - tstart) - 200, 0);
	}
	$loading.stop(true)
	.animate({ opacity: 1 }, { duration: wait }) // wait
	.animate({ opacity: 0 }, 1 , function(){	// chrome opacity bug workaround
		if($loading.css('opacity')!=0){	
			$(this).hide();
		}
	});
	
//	.hide();
};
var loadingError = function(req, status) {
	$error_msg_status.text(status);
	$load_msg.hide();
	$error_msg.show();
};

var navigation = function($nav)
{
	// constants
	var cssActive='selected'; // <li/> and <a/> css

	// inner functions
	var activate = function(href) {
		console.log('activate ' + href);
		href = href || '';

		// reset navi1 listitem
		$nav2.parent().css('position','');

		// reset navi2, navi3
		$nav2.add($nav3).css({ 'z-index':'0', 'left':'' }).hide()
			.find('li.' + cssActive).removeClass(cssActive).css('position','')
			.children('a.' + cssActive).removeClass(cssActive)
			.find('li:visible').hide();

		if (href.length == 0) {
			return;
		}

		// show active links and its lists
		$nav.find("a[href$=" + href + "]:last").addClass(cssActive) // <a/>
			.parent().addClass(cssActive) // show active <li/>
			.siblings().andSelf().show().end() // show <li/>'s siblings
			.parents('li').addClass(cssActive).show() // parent <li>'s
			.children('a').addClass(cssActive).end().end()// parent <li>'s <a>'s
			.parents('ul').css('z-index','1').show(); // parent <ul/>'s

		reposition();
	};
	// sums up the width of the inner children
	var getInnerWidth = function($elem) {
		for (var w=0,$children=$elem.children(),i=0; i<$children.length; i++) {
			w += $($children[i]).innerWidth();
		}
		return w;
	};

	// reposition 2nd and 3rd navigation on window event or click
	var reposition = function(ev){
		// initialize navi3 offset and width after activate() click
		// (no window resize event object present)
		if (!ev) {
			$nav3Visible = $nav3.filter(':visible');
			if ($nav3Visible.size() == 0) return;

			if (typeof $nav3Visible.data('leftRelative') == 'undefined') {
				// save left offset and width for reuse
				$nav3Visible.data('leftRelative', $nav3Visible.offset().left - leftLinkPadding)
				.data('width', getInnerWidth($nav3Visible));
			}
		}
		if (!$nav3Visible || $nav3Visible.size() == 0) return // window resized during load?

		// wd_content width = outer width - right IE-border - 10px for scrollbar
		var wdContentWidth = $wd_content.outerWidth()
				- (parseInt($wd_content.css('border-right-width').match(/\d+/)) || 0) - 10,
			n2LeftStatic = 0,
			n3LeftStatic = 0;

		// resize navi3 if (navi3 is static OR (navi3 is relative AND naviWidth > wdContentWidth))
		var resizeNav3 = $nav3Visible.parent().css('position') == 'static'
			|| ($nav3Visible.data('leftRelative') + $nav3Visible.data('width') > wdContentWidth); // navi3 > wd_content?

		// resize navi2 if (navi3 is resized OR navi2 is static OR (navi2 is relative AND naviWidth > wdContentWidth))
		var resizeNav2 = resizeNav3
			|| $nav2.parent().css('position') == 'static'
			|| ($nav2.data('leftRelative') + $nav2.data('width') > wdContentWidth); // navi2 > wd_content?

		if (resizeNav2) {
			n2LeftStatic = Math.min(
					Math.max(wdContentWidth - $nav2.data('width'), 0),
					$nav2.data('leftRelative'));
		}
		if (resizeNav3) {
			n3LeftStatic = Math.min(
					Math.max(wdContentWidth - $nav3Visible.data('width'), 0),
					$nav3Visible.data('leftRelative'));
		}

		// set new offsets
		if (resizeNav2 || resizeNav3) {
			var d = n3LeftStatic - n2LeftStatic;
			if (d < 0) { // if navi3 > navi2, then the offset of navi3 would be negative.
						 // to prevent navi3 being "more left" than navi2, navi2 is also shifted left
				n2LeftStatic = Math.max(n2LeftStatic + d, 0);
			}
			$nav2.css('left', n2LeftStatic).parent().css('position','static');

			if (resizeNav3) {
				$nav3Visible.css('left', Math.max(d, 0)).parent().css('position','static');
			}
		}
	};

	// bind backendLoader to links in navi2 and navi3
	$nav.find('ul a[backend]').click(function(){
		backendLoader($(this).attr('backend'));
		return false; // prevent click
	});

	var $nav2 = $nav.find('ul#navi2'), // navi2 (one list)
		$nav3 = null, // navi3 (more than one list)
		$nav3Visible = null, // visible navi3
		leftLinkPadding = null; // left link padding, used to correct the left offset when switched from relative -> static

	if ($nav2.size() == 1) {
		$nav3 = $nav2.find('ul');

		leftLinkPadding = parseInt($nav.find('a:first').css('padding-left').match(/\d+/)) || 5;

		$nav2.data('leftRelative', $nav2.offset().left - leftLinkPadding)
		.data('width', getInnerWidth($nav2));

		// bind window resize event to resize function using a timer to
		// prevent too many calculations on IE
		// @see http://groups.google.com/group/jquery-en/browse_thread/thread/4a00d513c63f5c00
		var resizeTimer = null;
		$(window).resize(function() {
		    if (resizeTimer) clearTimeout(resizeTimer);
		    resizeTimer = setTimeout(reposition, 200);
		});
	}
	return {
		activate: activate,
		elem : $nav
	}
};

// creates request object from the given arguments.
// get($container)         - loads html into container
// post(data, $container)  - posts data and loads html into container
// jsonBackendLoad([data]) - GETs JSON and loads html from mapping url into container
var ajaxRequest = function(url, callback)
{
	var TIMEOUT_MAX_RETRIES = 15;
	var _request = function(url, type, dataType, data, $container, callback, reqType, retries) {
		retries = retries || 0;
		var tempData = null; // stores result in success() we could need in complete()
		var dataIn = data;
		//console.groupCollapsed('starting ajaxRequest:', url);
		console.group('starting ajaxRequest:', url);
		console.log(reqType + ' ' + type + ' ' + dataType + ' request: url=', url
					,', data=', dataIn, ', container=', $container
					,', callback=', callback, ', retries=', retries);

		return $.ajax({
			url: url,
			type: type,
			dataType: dataType,
			data: data,
			beforeSend: function(req){
				console.log('beforeSend()...');
				if (requests.length == 0) {
					loadingStart();
				}
				// requests from the hashLoader are abortable
				if(reqType == "jsonBackendLoad" || reqType == "htmlBackendLoad"){
					requests.push(req);
				}
			},
			complete: function(req, status) {
				console.log('complete()...');
				// 'remove' completed request from requests-Array
				requests.remove(req);

				if (callback) { // always callback - on success or error
					callback(status, tempData); // Note: tempData could be invalid!
				}
				if (requests.length == 0) {
					loadingStop();
				}
				console.groupEnd();
			},
			success: function(data, status) {
				//console.log('success: data' + (dataType == 'html' ? ' length=' + data.length : '=' + data)
				//		 + ', status=' + status + ', reqType=' + reqType);
				tempData = data;
				if (reqType == "jsonBackendLoad") {
					// links with http:// will be opend in a new window
					try {
						if(piwikSiteId != "") {
							console.log('piwik siteid:' + piwikSiteId + ' dataIn.path:' + dataIn.path);
							// setze eigene URL, wenn Daten hinter hash #
							if(dataIn.path != "") {
								piwikTracker.setCustomUrl(dataIn.path);
							}
							piwikTracker.trackPageView();
							piwikTracker.enableLinkTracking();
						}
					} catch( err ) { }
					
					if(data[0].indexOf('http://')!=-1){
						window.open(data[0]);
						history.back();
					}
					else{
						// load result data into container
						ajaxRequest(data[0], function(status){ // urlFromMapping callback
							if (status == "success") {
								$topnav.activate(data[1]); // highlight navi
								//deaktivierte GeoDaten
								//loadAdressMaps(data);
							}
						}).get($container, "htmlBackendLoad");
					}
				}
				else if (dataType == "html") {
					if ($container) { // insert html and do postLoad actions...
						// schneller fix für kaputtes css in kdinfo nach aktualisierung von kdinfo
						if(url=="backend/getKundenInformation.html"){
							ajaxformSubmit($container.html(data).attr("timestamp", new Date().getTime()));
						}
						else{
							ajaxformSubmit($container.html('<div class="wd-inner-content">' + data + '</div>').attr("timestamp", new Date().getTime()));
						}
						// 1. backendLoad and 2. refreshKd synchronized (if kundeAfterBackend set in $('a').live('click', ...)
						if(kundeAfterBackend>0){	 
							console.log('refreshKunde READY: ', reloadKdInfo());
							kundeAfterBackend--;
						}
					}
				}
				//else { }// "json"
			},
			error: function(req, status, ex) { // status "timeout", "error", "notmodified" and "parsererror"
				console.log('error: req=', req, ', status=' + status + ', exception=',ex, ', retries=' + retries);
				if (status == "timeout" && retries < TIMEOUT_MAX_RETRIES ) { // try again
					// breche Request ab
					req.abort();
					//setTimeout(function() {
					//	return _request(url, type, dataType, data, $container, callback, reqType, retries+1);
					//}, 2000);
				}
				loadingError(req, status);
				// handle error...
			}
		});
	};
	return {
		jsonBackendLoad: function(data, $container) {
			return _request(url, "GET", "json", data, $container, callback, "jsonBackendLoad");
		},
		json: function($container) {
			return _request(url, "GET", "json", null, $container, callback);
		},
		get: function($container, reqType) {
			return _request(url, "GET", "html", null, $container, callback, reqType);
		},
		post:function(data, $container) {
			return _request(url, "POST", "html", data, $container, callback);
		}
	};
};

var ajaxformSubmit = function($container)
{
	console.log('ajaxformSubmit(....) container=' + $container);
	if (! ($container || $($container).attr('id'))) return;

	// find input field that should have focus
	// and whose focus index is greater
	var maxFocusIndex = -1;
	$container.find('input[type="text"]').filter(function() {
		var $this = $(this);
		var hasFocus = $this.attr('hasfocus');
		if(hasFocus == undefined || hasFocus == "yes") {
			var focusIndex = $this.attr('focusindex');
			focusIndex = (focusIndex != undefined) ? parseInt(focusIndex) : 0;
			if(focusIndex > maxFocusIndex) {
				maxFocusIndex = focusIndex;
				return true;
			}
		}
		return false;
	}).filter(':last').focus().select();

	// for all forms...
	$container.find('form').each(function(){
		var $form = $(this);
		bindSubmit($form); // submit bei Klick auf Elemente mit class="submit-button"

		// binde ajaxSubmit an Formular
		$form.submit(function() {
			var action = $form.attr('action') || null,
				presubmitcheck = $form.attr("presubmitcheck") || null;

			if (! (action && funcCheck(presubmitcheck))) {
				console.log("sorry nope! presubmitcheck=" + presubmitcheck + ', action=' + action);
				return false;
			}
			var refresh = $form.attr('refresh');

			ajaxRequest(action, function(status, result){ // callback
				if (status == "success") {
					if ($form.attr('refreshKunde')){
						reloadKdInfo();
					}
					if($form.attr("redirect")){
						$.historyLoad($form.attr("redirect").replace(/^.*#/, ''));
					}
					if($form.attr("triggerOnSuccess")){
						funcCheck($form.attr("triggerOnSuccess"));
					}
				}
			}).post(
					// serialize form fields and filter checkboxes and radiobuttons that are not checked
					$form.find(':input').filter(
					function(){
						var $this = $(this);
						return !($this.is(':checkbox:not(:checked)') || $this.is(':radio:not(:checked)'));
					}).serialize(),
					(refresh && refresh === "false" ? null : $container)
			);
			return false;
		});
	});
};

var funcCheck = function(func) {
	var isIENativeFunction = function(f) {
		return !!f && typeof f.toString === "undefined" && /^\s*\bfunction\b/.test(f);
	};

	if (!func) { // kein Funktionsname gefunden
		return true;
	}
	// TODO: schneller hack. könnte sauberer sein... funzt aber.
	var fun = eval(func.split("(")[0]);
	if (! $.isFunction(fun)) { // kein Fun
		if(!isIENativeFunction(fun)){
			return false;
		}
	}
	return eval(func);
};

// trigger $form.submit() bei Elementen mit class="submit-button"
var bindSubmit = function($form){
	$form.find('a.submit-button','img.submit-button','input.submit-button').unbind('click').click(function(){
		$form.trigger('submit');
	});
};

var hashLoader = function()
{
	var hash = (arguments[0] || '#').replace(/^.*#/, ''), // get part after '#'
		$container = $(arguments[1] || $wd_content); // default container

	console.log('hashLoader() hash=', hash, ', container=',$container);
	requests.abort();

	// getUrlFromMapping.php returns JSON: result = ['urlForContainer','naviHighlightPath']
	ajaxRequest("backend/getUrlFromMapping.php").jsonBackendLoad({ path : hash }, $container);
	return false;
};

var backendLoader = function()
{
	var href = arguments[0] || '',
		$container = $(arguments[1] || $wd_content); // default container

	console.log('backendLoader: '+href);
	// anstelle von ajaxRequest sollte hier nur das backend ausgeführt aber nicht angezeigt werden !
	ajaxRequest(href, function(status){ // html callback
		if (status == "success") {
			console.log('backend loaded....');
		}
	}).get($container);
	return false;
};

// die folgende Funktion sollte in backendLoader integriert werden (am besten, wenn kein container übergeben wird, dann nicht rendern)
// dazu müssten aber ALLE expliziten backendaufrufe überprüft werden
var backendLoaderWithoutRendering = function()
{
	var href = arguments[0] || '';
	console.log('backendLoader: '+href);

	// anstelle von ajaxRequest sollte hier nur das backend ausgeführt aber nicht angezeigt werden !
	ajaxRequest(href, function(status){ // html callback
		if (status == "success") {
			console.log('backend loaded without rendering....');
		}
	}).get();
	return false;
};

// helper to refresh wd-kunde container
var reloadKdInfo = function()
{
	backendLoader('backend/getKundenInformation.html', '#wd-kunde');
	return false;
};

// helper to Load AdresseMaps
var loadAdressMaps = function(data){
	var findStr = "E-Shop.html#Verwaltung/Adressen";
	//console.log("data[0] - " + data[0]);
	//console.log("data[1] - " + data[1]);
	if(data[1] == findStr){

		console.log("E-Shop.html#Verwaltung/Adressen -> loadGoogle[Start]...");
		
		console.log("GoogleMap[Start]...");
		$.getScript("http://maps.google.com/maps?file=api&v=2&async=2&key=ABQIAAAAN6Mbf7k-ko1aduUWWIGt6RTydKb-MTdjFgWbTEEOvP9KxSAMrRQdugXzocjqSS3YZdz2_hdF71s2jg",
				function(d, s){
					console.log("...GoogleMap[End]");
					console.log("markermanager[Start]...");
					$.getScript("http://gmaps-utility-library.googlecode.com/svn/trunk/markermanager/release/src/markermanager.js",
							function(da, st){
								console.log("...markermanager[End]");
								console.log("js/googleMaps.js[Start]...");
								$.getScript("js/googleMaps.js",
										function(dat, sta){
											if(typeof StartGoogleMaps == 'function'){
												StartAdressMaps(data[0]);
											}
										}
								);
								console.log("...js/googleMaps.js[End]");
							}
					);
				}
		);
		console.log("...loadGoogle[Ende]");		
	}
}
//helper to Start AdresseMaps
var StartAdressMaps = function(data){
	if(typeof StartGoogleMaps == 'function'){
		var lnr = 0;
		var findStr = 'backend/getAdressen.html';
		if(data.substring(0, findStr.length) == findStr){
			if(data.length > findStr.length){
				lnr = parseInt(data.replace(findStr + "?lnr=" , ""));
			}
			console.log("js/StartAdressMaps.js[Start]...");
			$.getScript("js/StartAdressMaps.js?lnr=" + lnr,
					function(d, s){
						console.log("...js/StartAdressMaps.js[End]");
				}
			);
		}
	}
}
// onload
$(function()
{
	//
	// fill global vars
	//
	$wd_content=$('#wd-content');

	// ladeanzeige
	$loading=$('#loading');
	$load_msg = $loading.find('#load-msg');
	$load_msg_status = $load_msg.find('#load-msg-status');
	$error_msg =  $loading.find('#error-msg');
	$error_msg_status = $error_msg.find('#error-msg-status');
	loadingStop();

	// init global $topnav (hashLoader needs it)
	$topnav = navigation($('#wd-topnavi ul.navi'));
	navigation($('#wd-bottomnavi ul.navi'));

	// ajax setup for all requests
	$.ajaxSetup({
		cache: false,
		timeout: 90000 // in Millisekunden
	});
	
	$(this).ajaxStop(function(){
		kundeAfterBackend = 0;
	});
	// start checkStatus (siehe Status.js)
	setExecuteCheckStatus(true);
	setInterval(checkStatus, checkStatusInterval);

	// NOTE: die Funktion im Plugin ist bisschen angepasst ;-)
	// @see Kommentar am Ende der jquery.history.js#historyInit() Funktion
	// !!! Deswegen bitte beim Aktualisieren des Plugins aufpassen !!!
	$.historyInit(hashLoader, "E-Shop.html");

	$('a').live('click', function() {
		//console.groupCollapsed('click on', this);
		console.group('click on', this);
		var $this = $(this),
			preclickcheck = $this.attr('preclickcheck'),
			confirm = funcCheck(preclickcheck);

		if((preclickcheck!=undefined && confirm) || preclickcheck==undefined){
			console.log('post-action preclickcheck: ', preclickcheck);

			// use backend but do not render return
			var get_ajax = $this.attr('get_ajax');
			if(get_ajax!=undefined){
				console.log('post-action backendWithoutRenderingString: ', get_ajax);
				console.log('backendWithoutRendering READY: ', backendLoaderWithoutRendering(get_ajax));
			}
			var backend = $this.attr('backend');
			var refresh = $this.attr('refreshKunde');
			// synchronize backendLoad and kundeRefresh
			if(refresh!=undefined && backend!=undefined){
				console.log('refreshKunde After backendload');
				kundeAfterBackend++;
			}
			// use backend and render return (if synchronized with refreshKd: refreshKd after backendLoad success)
			if(backend!=undefined){
				console.log('post-action backendString: ', backend);
				console.log('backend READY: ', backendLoader(backend));
			}
			// refresh KundenInfo
			if(refresh!=undefined && backend==undefined){	// only if not coupled with backendload (does that ever happen?)
				console.log('post-action refreshKunde: ', refresh);
				console.log('refreshKunde READY: ', reloadKdInfo());
			}

			var href = $this.attr('href');

			// NOTE: IE setzt die ganze Browser URL vor dem # Zeichen,
			// deswegen kein ^ am Anfang der RegEx fuer IE
			var regShopUrl = /^(E-Shop\.html)?#\/?[\w-]+(\/[\w-]*)*$/;
			var regShopUrlIE = /E-Shop\.html#\/?[\w-]+(\/[\w-]*)*$/;

			var regHashSign = /^#$/;  // fuer Links mit href="#"
			var regHashSignIE = /E-Shop\.html#$/;  // fuer Links mit href="#" in IE
			
			if($this.hasClass('anchor-link'))
			{
				scrollToAnchor($this.attr('hash'));
				console.groupEnd();
				return false;
			}
			else if(regShopUrl.test(href) || regShopUrlIE.test(href))
			{
				$.historyLoad(href.replace(/^.*#/, ''));
				console.groupEnd();
				return true;
			}
			//else if(href != '#')
			else if(!regHashSign.test(href) && !regHashSignIE.test(href))
			{
				console.groupEnd();
				return true;
			}
			//href == '#'
		}
		else{
			// do nothing
			console.log('post-action preclickcheck false!', confirm);
		}
		console.groupEnd();
		return false;
	});
//	$(window).unload(function(){
//		requests.abort(); // clean up, needed?
//	});
});