/**
 * NS global components
 * Contains components that are used throughout the NS site by various other objects.
 * 
 * @version   1.00.090814
 * @author    LBI Lost Boys
 */
NS(function($){

	/**
	 * SimpleMenu component
	 */
	var STATE_COLD = 1;
	var STATE_HOT  = 2;

	NS.SimpleMenu = function(element, settings){
		$.extend(this, NS.SimpleMenu.Defaults, settings);
		this.root = element;
		this.state = STATE_COLD;
		this.stateChange = null;
		
		var jNode = $(this.root);
		jNode.bind('mouseover', this.mouseover.bind(this));
		jNode.bind('mouseout', this.mouseout.bind(this));

		if(this.keyEnabled) {
			var focusable = $(this.focusType, this.root);
			focusable.bind('focus', this.mouseover.bind(this));
			focusable.bind('blur', this.mouseout.bind(this));
		}
		
		//iframe for covering up select boxes in IE
		this.ieFrame = NS.Interface.createIEFrame();
	};

	NS.SimpleMenu.prototype = {
		toggleMenu:function(item, toggle) {
			$(item)[toggle? 'addClass' : 'removeClass'](this.activeClass);
			
			var menu = $(this.menuType, item).eq( 0);
			this.toggleIEFrame(toggle,menu);
		},
		
		toggleItem:function(item, toggle) {
			$(item)[toggle? 'addClass' : 'removeClass'](this.hoverClass);
		},

		mouseover: function(e) {
			var item = $(e.target).closest(this.itemType);
			if(item && item != this.item) {
				this.setCurrent(item);
				clearTimeout(this.stateChange);
				var self = this, toggle = function(){ self.toggle(item); };

				switch(this.state) {
					case STATE_COLD:
						this.stateChange = setTimeout(toggle, this.openDelay);
					break;
					case STATE_HOT: 
						this.stateChange = setTimeout(toggle, this.switchDelay);
					break;
				}
			}
		},

		mouseout: function(e) {
			var node = e.relatedTarget;
			while(node) {
				if(node == this.root) { 
					return;
				}
				node = node.parentNode;
			}

			this.setCurrent(null);
			clearTimeout(this.stateChange);

			var self = this;
				
			switch(this.state) {
				case STATE_COLD: break;
				case STATE_HOT:
					this.stateChange = setTimeout(function(){ 
						self.toggle(false);
					}, this.closeDelay);
				break;
			}
		},

		toggle: function(item) {
			var tree = item? item.parentNode : this.root;
			var lists = $(tree).find(this.menuType);
			var list;

			for(var i=0; (list=lists[i++]);) {
				if(list.parentNode != item) {
					this.toggleMenu(list.parentNode, false);
				}
			}

			if(item) {
				list = $(item).find(this.menuType)[0];
				if(list) {
					this.toggleMenu(list.parentNode, true);
				}
			}
			
			this.state = item? STATE_HOT : STATE_COLD;
		},

		setCurrent:function(item) {
			if(this.item) {
				this.toggleItem(this.item, false);
			}
			if(item) {
				this.item = item;
				this.toggleItem(item, true);
			}
		},
		
		toggleIEFrame:function(toggle, menu) {
			if(this.ieFrame){
				if(toggle) {
					var offset = menu.offset();
					this.ieFrame.css({
						left: offset.left + 'px',
						top: offset.top + 'px',
						width: (menu[0].offsetWidth) + 'px',
						height: (menu[0].offsetHeight) + 'px'
					});
				} else {
					this.ieFrame.css({
						left: -9999 + 'px',
						top: -9999 + 'px'
					});
				}
			}
		}
	};

	NS.SimpleMenu.Defaults = {
		openDelay:   500,
		switchDelay: 200,
		closeDelay:  1000,
		hoverClass:  'hover',
		activeClass: 'active',
		itemType:    'li',
		menuType:    'ul',
		keyEnabled:  true,
		focusType:   'a'
	};

	/**
	 * Calendar component
	 */
	NS.Calendar = function(node, settings) {
		this.container = node;
		this.allowPast = settings.allowPast;
		this.table = $('table', node);
		this.body = $('tbody', node);
		this.selects = $("select", node);
		this.setAction(function(){});
		
		this.table.bind('mouseup', this.getDate.bind(this));
		this.table.bind('mousemove', this.hoverDate.bind(this));
		this.selects.bind('change', this.upDate.bind(this));

		var now = new Date();
		this.now = new Date(now.getFullYear(), now.getMonth(), now.getDate());
		this.chooseDate(this.selects[0]);
	};

	NS.Calendar.prototype = {
		setAction:function(action) { this.action = action; },
		upDate:function(e) {
			var target = $(e.target).closest('select')[0];
			if(target) {
				this.chooseDate(target);
			}
		},

		getDateFromSelect:function(target) { 
			var year, month;
			if(/year|month/i.test(target.className)) {
				year = parseInt(this.selects[0].value, 10);
				month = parseInt(this.selects[1].value, 10) -1;
			} else {
				var date = target.value.split('/');
				year = parseInt(date[0], 10);
				month = parseInt(date[1] || 1, 10) -1;
			}

			return new Date(year, month, 1);
		},

		chooseDate:function(target) {
			var date = this.getDateFromSelect(target);
			this.setDate(date);
		},

		setSelects:function(date) {
			var selectable = true;
			var selectValue = function(select, value) {
				for (var i=0; i<select.options.length; i++) {
					if(select.options[i].value == value) {
						select.selectedIndex = i;
						return;
					}
				}
			
				selectable = false;
				select.selectedIndex = 0;
			};

			if(this.allowPast) {
				selectValue(this.selects[0], date.getFullYear());
				selectValue(this.selects[1], date.getMonth()+1);
			} else {
				var s = date.getFullYear() + '/' + (/[0-9]{2}$/).exec('0'+ (date.getMonth()+1))[0] + '/01';
				selectValue(this.selects[0], s);
			}
			
			return selectable? date : this.getDateFromSelect(this.selects[0]);
		},

		setDate:function(date, options) {
			if(options) { 
				this.startDate = options.startDate;
				this.endDate = options.endDate;
			}
	
			var selected = this.setSelects(date || this.selectedDate);
			this.selectedDate = new Date(selected.getTime());			
			
			this.createTable();
		},

		hoverDate:function(e) {
			var target = e.target;
			var day = target.innerHTML;
			if(this.currentCell && (target === this.currentCell[0])) {
				return;
			}

			if(this.currentCell) {
				this.currentCell.removeClass('current');
			}

			if(/td/i.test(target.nodeName) && /^[0-9]+$/.test(day) && !/past/.test(target.className)) {
				this.currentCell = $(target).addClass('current');
			}
		},

		getDate:function(e){
			var target = e.target;
			var day = target.innerHTML;
			if(/td/i.test(target.nodeName) && /^[0-9]+$/.test(day) && !/past/.test(target.className)) {
				var date = this.selectedDate;
				this.action(new Date(date.getFullYear(), date.getMonth(), day));
			}
		},

		createTable:function() {
			var date = new Date(this.selectedDate.getTime()); 
			date.setDate(1);

			var day, row, cell, endmode = false; 
			var month = date.getMonth(); 
			var first = date.getDay(); 
			var days = first + 42;
			
			this.currentCell = null;
			this.body.remove();
			this.body = $('<tbody />');
			this.table.append(this.body);

			for(var i=0; i<days; i++) {
				day = i+1 - first;
				date.setMonth(month);
				if(day < 1) {
					day = ' ';
				} else {
					date.setDate(day);
					if(date.getMonth() != month) {
						day = ' '; endmode = true;
					}
				}

				if(i%7 === 0) {
					if(endmode) {
						break;
					}
					row = this.body[0].insertRow(i/7);
				}	
				
				cell = row.insertCell(i%7);
				cell.innerHTML = day;
				
				if((date < this.now && !this.allowPast) ||
				  (this.startDate && date < this.startDate) ||
				  (this.endDate && date > this.endDate)) {
					cell.className = 'past';
				}
				
				if(day > 1 && Math.abs(this.selectedDate - date) < 86400000) {
					cell.className += ' today';
				}
				
				if(i%7 === 0 || i%7 === 6) {
					cell.className += ' weekend';
				}
			}
		}
	};

	/**
	 * Animator
	 */
	NS.Animator = function(callBack, callEnd, easing, tick) {
		this.callBack = callBack;
		this.callEnd = callEnd;
		this.easing = easing || NS.Animator.EASEINOUT;
		this.timer = null;
		this.tick = tick || 30;
	};

	NS.Animator.prototype = {
		run:function(from, to, duration) {
			this.stop();
			this.from = from;
			this.to = to;
			this.step = 0;
			this.increment = this.tick/duration;
			this.timer = setInterval(this.animate.bind(this), this.tick);
		},
		
		animate:function() {
			if(this.paused) { return; }
			var factor = Math.min(this.easing(this.step), 1);
			var value = this.from + ((this.to - this.from) * factor);
			this.callBack(value);
			if(this.step >= 1) {
				this.stop();
				if(this.callEnd) {
					this.callEnd();
				}
			}
			this.step += this.increment;
		},

		pause:function(toggle) { 
			this.paused = toggle; 
		},

		stop:function() {
			clearInterval(this.timer);
		}
	};

	NS.Animator.LINEAR = function(n){ return n; };
	NS.Animator.EASEIN = function(n){ return 1- Math.cos(n * Math.PI/2); };
	NS.Animator.EASEOUT = function(n){ return Math.sin(n * Math.PI/2); };
	NS.Animator.EASEINOUT = function(n){ return 1- (Math.cos(n * Math.PI)/2 + 0.5); };

	/**
	 * Static XMLHttp object
	 */
	NS.XMLHttp = {
		load:function(url, func, scope){ 
			return this.sendAndLoad(null, url, func, 'get');
		},

		sendAndLoad:function(doc, url, func, type){
			var xhr = this.getXMLHttp(); 
			var async = func? true:false; 
			var method = type || 'post'; 
			var request = url;
			
			if(!/post/i.test(method) && doc) {
				request += '?' + doc;
			}

			xhr.open(method, request, async);
			if(async) {
				xhr.onreadystatechange = function() {
					if(xhr.readyState == 4) {
						func(xhr.responseXML, xhr.status);
					}
				};
			}
			
			xhr.setRequestHeader('Accept', 'text/xml,application/xml');
			xhr.setRequestHeader('Referer', document.location.href);
			xhr.setRequestHeader('User-Agent', navigator.userAgent);
			xhr.setRequestHeader('Connection', 'close');
			if(/post/i.test(method)) {
				xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
			}

			xhr.send(/post/i.test(method)? doc : null);
			return async? xhr : xhr.responseXML;
		},
		
		abort:function(xhr) {
			try {
				xhr.onreadystatechange = null;
				xhr.abort();
			} catch (fail) {}
		},

		getXMLHttp:function() {
			if(window.XMLHttpRequest) {
				return new XMLHttpRequest();
			} else if(window.ActiveXObject) {
				var xhr, http = ['Microsoft.XMLHTTP', 'Msxml2.XMLHTTP'], l = http.length;
				while(l--) {
					try {
						xhr = new ActiveXObject(http[l]);
						return xhr;
					} catch (e) {}
				}
			} else {
				return false;
			}
		}
	};

	/**
	 * Simple password strength meter
	 */
	NS.PasswordStrength = function(options){
		this.settings = $.extend({}, NS.PasswordStrength.Defaults, options);
	};

	NS.PasswordStrength.prototype = {
		getStrength:function(pass) {
			var s = this.settings;
			var strength = 0;

			if(s.regLower.test(pass)) { strength ++; }
			if(s.regUpper.test(pass)) { strength ++; }
			if(s.regNumber.test(pass)) { strength ++; }
			if(s.regOther.test(pass)) { strength ++; }
			if(s.regLength.test(pass)) { strength ++; }
			
			return strength;
		},

		getVerdict:function(pass) {
			var s = this.settings;
			var strength = this.getStrength(pass);
			
			return s.prefix + s.labels[strength];
		},
		
		setLabels:function(labels) {
			this.settings.labels = labels;
		}
	};

	NS.PasswordStrength.Defaults = {
		prefix: 'sterkte: ',
		labels: ['zeer zwak','zwak','matig','redelijk','goed','zeer goed'],
		regLower: /[a-z]/,
		regUpper: /[A-Z]/,
		regNumber: /[0-9]/,
		regOther: /[^a-z0-9]/i,
		regLength: /^.{8,}$/
	};

});