/**
 * FBTO Keuzehulp Wonen
 * V3.0 - 22 maart 2010
 */
(function($){
	
	window.KeuzeHulpWonen = {
		initialize:function() {
			
			var url = $('head link[rel=questions]').attr('href');

			this.questionManager = new QuestionManager({
				container: '#keuzehulp-wonen',
				intro: '.keuzehulp-intro',
				introContent: '.keuzehulp-introduction',
				questions: '.keuzehulp-questions',
				answers: '.keuzehulp-answers',
				selected: '.keuzehulp-selected',
				advice: '.keuzehulp-advice',
				tooltip: '.keuzehulp-tooltip',
				tipcontent: '.tooltip-content',
				tiparrow: '.tooltip-arrow',
				buttons: '.keuzehulp-buttons',
				pages: '.keuzehulp-steps',
				message: '.keuzehulp-error',
				directory: url,
				index: 'index.xml'
			});
		},
			
		getCampaign:function() {
			return this.questionManager.getCampaign();
		},

		getButtons:function() {
			return this.questionManager.view.$buttons;
		},

		getIntro:function() {
			return this.questionManager.view.$intro;
		},

		getAdvice:function() {
			return this.questionManager.advice;
		}
	};

	var REG_CHOICE = /qm-choose/i;
	var REG_CONTENT = /[a-z]/;
	
	/**
	 * Question manager
	 */
	function QuestionManager(settings) {
		this.root = $(settings.container);
		this.container = $(settings.questions);
		this.answers = $(settings.answers);
		this.advice = $(settings.advice);
		this.directory = settings.directory;
		this.$selected = $(settings.selected);
		this.$tooltip = $(settings.tooltip);
		this.$tipcontent = $(settings.tipcontent);
		this.$tiparrow = $(settings.tiparrow);
		
		this.form = $('form', settings.container);
		
		this.validator = new Validator(settings);
		this.validationMsg = $(settings.message);
		this.view = new QuestionView(settings);
		
		this.inputData = new LBi.HashMap();
		this.adviceData = new LBi.HashMap();
		this.selected = new LBi.HashMap();
		
		this.relations = new LBi.LinkRelations();
		this.relations.subscribe(/qm-/, this.handleClick.bind(this));

		LBi.Dispatcher.subscribe('click:input', this.handleInputClick.bind(this));

		this.initTooltip();

		var questions = this.directory;
		this.indexXML = settings.index;
		
		if(/\.xml$/.test(this.directory)) {
			this.directory = this.directory.replace(/[^\/]+$/, '');
		} else {
			questions += settings.index;
		}

		this.questionHome = questions;
	//	this.loadQuestions(questions);

		if(/msie\s?6/i.test(navigator.userAgent)) {
			this.ieFrame = $('<iframe src="about:blank" frameborder="0"></iframe>');
			this.ieFrame.css({position:'absolute', opacity:0, left:-1000, top:0 });
			this.root.before(this.ieFrame);
		}

	//	this.loadIndex();
	}

	QuestionManager.prototype = {
		constructor: QuestionManager,

		loadQuestions:function(url) {
			$.get(url, this.parseQuestions.bind(this), 'xml');
		},

		loadIndex:function() {
			this.loadQuestions(this.questionHome);
		},

		forwardTo:function(url) {
			this.loadQuestions(this.directory + url);
		},

		parseQuestions:function(response) {
			var $xml = $(response);
			var config = $xml.find('config');
			var intro = config.find('introduction');
			var questions = $xml.find('step');
			var l = questions.length;

			this.questions = [];
			this.index = -1;
			for(var i=0; i<l; i++) {
				this.questions.push(
					new Question(questions[i])
				);
			}

			this.applySettings(config);
			this.renderIntro(intro);
			this.renderQuestions();
			this.reset();
		},

		applySettings:function(config) {
			this.remoteURL = config.attr('action');
			this.remoteMethod = config.attr('method');
			this.description = config.find('description').text();
			this.groups = config.find('groups').text();

			if(this.currentTheme) {
				this.root.removeClass(this.currentTheme);
			}

			var theme = config.find('theme').text();
			if(theme) {
				this.root.addClass(theme);
				this.currentTheme = theme;
				this.currentCampaign = theme.replace('theme', 'keuzehulpwonen');
			}
			
			var params = config.find('param');
			var l = params.length;
			this.parameters = {};
			for(var i=0; i<l; i++) {
				var param = params[i];
				this.parameters[param.getAttribute('name')] = 
					param.getAttribute('value');
			}			
		},

		getCampaign:function() {
			return this.currentCampaign || 'keuzehulpwonen';
		},


		handleClick:function(e) {
			var link = e.target;
			var rel = link.rel;
			var type = /qm-([^ ]+)/.exec(rel)[1];

			switch (type) {
				case 'next': this.tryNext(); break;
				case 'previous': this.previous(); break;
				
				case 'answer':
					if(this.validate()) {
						this.answerQuestion();
						this.validationMsg.hide();
					} else {
						this.validationMsg.fadeIn();
					}
				break;
				case 'advice':
					if(this.validate()) {
						this.advise();
						this.validationMsg.hide();
					} else {
						this.validationMsg.fadeIn();
					}
				break;
				case 'choose':
					this.chooseAnswer(link);
				break;
				
				case 'reset':	this.loadIndex(); break;
				case 'start':	this.start(); break;
				case 'submit':	this.submit(); break;

				case 'description':
					this.toggleTooltip(true, link, this.description);
				break;
				
				case 'open':
					// this.reset();
					this.loadIndex();
					this.toggle(true);
				break;
				case 'close':
					this.toggle(false);
				break;
			}

			e.preventDefault();
		},


		handleInputClick:function(e) {
			var input = e.target;
			var name = input.name;
			var uid = input.id;
			if(!uid) {
				var itemUID = $(input).closest('li.qm-answer').attr('rel');
				if(!itemUID) {
					return;
				}
				uid = itemUID;
			}

			var advice = this.view.getAdvice(uid);
			if (advice == null) {
				return;
			}
			if(advice.length > 1) {
				advice = this.filterAdvice(advice);
			}

			var value = advice.attr('value');
			if(value) {
				input.value = value;
			}

			this.inputData.put(name, input.value);

			var question = this.currentQuestion.id;
			
			try {
				Statistics.handleChoice(
					this.getCampaign(),
					$('h1', this.currentQuestion).text(), 
					input.getAttribute('alt')
				);
			} catch (e) {
			}

			this.adviceData.put(question, {
				content: advice.text(),
				forward: advice.attr('forward'),
				start: advice.attr('start'),
				mode: advice.attr('mode')
			});

			if(/checkbox/i.test(input.type)) {
				var opt = $(input).closest('li.qm-answer');
				opt.siblings('li').find('input:text').removeClass('qm-error').val('').attr('disabled', input.checked);
			}
		},

		initTooltip:function() {
			this.root.bind('mouseover', this.handleTooltip.bind(this));
			this.$tooltip.hover(
				this.tooltipOver.bind(this),
				this.tooltipOut.bind(this)
			);
		},
		
		handleTooltip:function(e) {
			var link = $(e.target).closest('a');
			var button = link[0];
			if(button) {
				var rel = button.rel;
				if(REG_CHOICE.test(rel)) {
					var id = /#(.*)$/.exec(button.href)[1];
					var advice = this.view.getAdvice(id);
					if(advice.length > 1) {
						advice = this.filterAdvice(advice);
					}

					var mode = advice.attr('mode');
					var text = advice.text();
					if(/tooltip/.test(mode) && REG_CONTENT.test(text)) {
						this.delayedTooltip(true, button, text);
					} else {
						this.toggleTooltip(false);
					}
				}
			} else {
				this.delayedTooltip(false);
			}
		},

		delayedTooltip:function(toggle, button, html) {
			clearTimeout(this.tooltipTimer);
			if(this.tooltipHover) {
				return;
			}

			var self = this;
			if(toggle) {
				this.tooltipTimer = setTimeout(function(){
					self.toggleTooltip(toggle, button, html);
				}, 100);
			} else {
				this.tooltipTimer = setTimeout(function(){
					self.toggleTooltip(false);
				}, 300);
			}
		},
			tooltipOver:function () {
				this.tooltipHover = true;
				clearTimeout(this.tooltipTimer);
			},

			tooltipOut:function () {
				this.tooltipHover = false;
				this.delayedTooltip(false);
			},

		toggleTooltip:function(toggle, button, html){
			if(toggle) {
				var off = this.root.offset();
				var top = off.top;
				var left = off.left;

				var b = $(button).offset();
				this.$tipcontent.html(html);
				this.$tooltip.css({top: (b.top - top + 70)});
				this.$tiparrow.css({
					left: (b.left - left) + (button.offsetWidth/2) - 55 
				});
				this.$tooltip.hide();
				this.$tooltip.fadeIn(100);
			} else {
				this.$tooltip.fadeOut(100);
			}
		},

		filterAdvice:function(adviceList) {
			var l = adviceList.length;
			for(var i=0; i<l; i++) {
				var advice = adviceList[i];
				var target = advice.getAttribute('for');
				var exclude = advice.getAttribute('not');
				
				if(this.matchesInputFor(target, exclude)) {
					return adviceList.eq(i);
				}
			}
		},

		matchesInputFor:function(values, exclude) {
			var includers = values.split(',');
			var excluders = (exclude || '').split(',');

			function filter(requirements, data) {
				for(var j=0; j<requirements.length; j++) {
					var pair = requirements[j].split('=');
					var value = data.get(pair[0]);
					if(value && value === pair[1]) {
						return true;
					}
				}
				return false;
			}
			
			var data = this.inputData;
			var valid = filter(includers, data) & !filter(excluders, data);

			return valid;
		},

		validate:function(){
			return LBi.Dispatcher.fire('validate', this.currentQuestion);
		},

		renderIntro:function(intro) {
			var html = intro.text();
			if(html) {
				this.view.renderIntro(html);
			}
		},

		renderQuestions:function() {
			var questions = this.view.renderQuestions(this.questions);
			LBi.DOM.write(this.container, $(questions));
			this.$questions = $('.qm-question', this.container);
		},

		answerQuestion:function() {
			var question = this.currentQuestion.id;
			var advice = this.adviceData.get(question);

			var showAdvicePage = !(/tooltip|none/i.test(advice.mode)) && REG_CONTENT.test(advice.content);
			
			this.requestedForward = advice.forward;
			this.requestedStart = advice.start || 0;
			var pages = this.$questions.length;

			this.answers.html(advice.content);
			this.view.setPercentage((this.index+1)/pages);
			var title = this.answers.find('h2:first').clone();
			if(title.length && !title.hasClass('informative')) {
				this.selected.put(question, title);	
			}

			this.view.displaySummary(this.selected);
			
			if(showAdvicePage) {
				this.view.setState('answer');
				if(/none/i.test(advice.forward)) {
					this.view.setButtonState('none');
				}
				this.toggleIEFrame(true);
			} else {
				this.tryNext();
			}
		},

		chooseAnswer:function(link) {
			var id = /#(.*)$/.exec(link.href)[1];
			var input = document.getElementById(id);
			input.checked = true;
			LBi.Dispatcher.fire('click', input);

			this.answerQuestion();
		},

		next:function() {
			var last = this.questions.length -1;
			if(++this.index > last ) { 
				this.index = last;
				return false;
			}

			var question = this.questions[this.index];
			var filter = question.filter;
			var exclude = question.exclude;
			if(filter && !this.matchesInputFor(filter, exclude)) {
				return this.next();
			}

			this.setQuestion(this.index);
			return true;
		},

		tryNext:function() {
			if(this.requestedForward) {
				this.forwardTo(this.requestedForward);
				return;
			}

			if(!this.next()) {
				this.advise();
			}

			this.toggleIEFrame(true);
		},

		previous:function() {
			if(this.currentQuestion) {
				var question = this.currentQuestion.id;
				this.selected.remove(question);
				this.view.displaySummary(this.selected);
			}

			if(--this.index < 0) {
				this.index = 0; 
			}

			var question = this.questions[this.index];
			var filter = question.filter;
			var exclude = question.exclude;
			if(filter && !this.matchesInputFor(filter, exclude)) {
				this.previous();
				return;
			}

			this.setQuestion(this.index, true);
		},

		setQuestion:function(index, reset) {
			this.toggleTooltip(false);

			var $question = this.$questions.eq(index);
			var question = this.questions[this.index];
			var questionMode = question.mode;

			if(reset) {
				var inputs = $(this.currentQuestion).find('input:radio, input:checkbox');
				inputs.attr('checked', false);
			}
			
			this.$questions.hide();
			this.currentQuestion = $question[0];
			$question.show();

			var group = parseInt(question.group, 10);
			var total = parseInt(this.groups, 10);
			
			this.view.setPage(group, total);
			this.view.setState(questionMode);
			this.toggleIEFrame(true);
		},

		advise:function(){
			var pages = parseInt(this.groups, 10);
			this.view.setPage(pages + 1, pages);
			this.view.setState('advice');
			
			try {
				Statistics.handleAdvice(
					this.getCampaign(),
					'Bereken je premie'
				);
			} catch (e) {
			}
		},

		submit:function() {
			var params = this.parameters;
			for(var i in params) {
				if(typeof i == 'string') {
					this.form.append(
						'<input type="hidden" name="'+i+'" value="'+params[i]+'" />'	
					)
				}
			}
			this.parameters = {};
			this.form.submit();
		},

		reset:function() {
			this.index = -1;
			this.next();
			this.form[0].reset();
			this.inputData.clear();
			this.adviceData.clear();
			this.selected.clear();
			this.view.reset();
			this.view.displaySummary(this.selected);

			Statistics.handleIntro(
				this.getCampaign(),
				'start'
			);
		},

		start:function() {
			this.reset();
			var start = parseInt(this.requestedStart || 0, 10);
			this.index = start -1;
			this.next();
			this.setQuestion(start);
		},

		toggle:function(toggle) {
			var callback = (function(){
				this.toggleIEFrame(toggle);
			}).bind(this);

			this.root[toggle? 'fadeIn' : 'fadeOut'](callback);
		},

		toggleIEFrame:function(toggle) {
			if(!this.ieFrame) return;
			var node = this.root[0];

			if(toggle) {
				var offset = this.root.offset();
				this.ieFrame.css({
					left: offset.left + 'px',
					top: offset.top + 'px',
					width: node.offsetWidth + 'px',
					height: node.offsetHeight + 'px'
				});
			} else {
				this.ieFrame.css({
					left: -9999 + 'px',
					top: -9999 + 'px'
				});
			}
		
		}
	};

	QuestionManager.getUID = function() {
		if(!this._uid) { this._uid = 1; }
		return 'fbto-uid-' + (this._uid ++);
	};

	/**
	 * Question
	 */
	function Question(node) {
		this.answers = [];
		this.parseQuestion(node);
		this.uid = QuestionManager.getUID();
	}

	Question.prototype = {
		parseQuestion:function(node) {
			var $node = $(node);
			var $options = $node.find('option');
			var l = $options.length;
			
			this.filter = $node.attr('for');
			this.exclude = $node.attr('not');
			this.group = $node.attr('group');
			this.mode = $node.attr('mode') || 'question';
			this.label = $node.find('question');
			
			for(var i=0; i<l; i++) {
				this.answers.push(
					new Answer($options[i])	
				);
			}
		},

		getLabel:function() {
			return this.label;
		},

		getAnswers:function() {
			return this.answers;
		},
		
		getUID:function() {
			return this.uid;
		}
	};

	/**
	 * Answer
	 */
	function Answer(node) {
		this.parseAnswer(node);
		this.uid = QuestionManager.getUID();
	}

	Answer.prototype = {
		parseAnswer:function(node) {
			var $node = $(node);
			this.label = $node.find('answer');
			this.advice = $node.find('advice');
		},

		getLabel:function() {
			return this.label;
		},

		getAdvice:function() {
			return this.advice;
		},
		
		getUID:function() {
			return this.uid;
		}
	};

	
	/**
	 * Question view
	 */
	function QuestionView(settings) {
		this.$container = $(settings.container);
		this.$buttons = $(settings.buttons);
		this.$pages = $(settings.pages);

		this.$intro = $(settings.intro);
		this.$introContent = $(settings.introContent);
		this.$questions = $(settings.questions);
		this.$answers = $(settings.answers);
		this.$selected = $(settings.selected);
		this.$advice = $(settings.advice);

		this.tips = new LBi.HashMap();
	}

	QuestionView.prototype = {
		renderIntro:function(intro) {
			this.$introContent.html(intro);
		},

		renderQuestions:function(questions) {
			var html = [];
			var l = questions.length;
			for(var i=0; i<l; i++) {
				html.push(this.renderQuestion(questions[i]));
			}

			return html.join('');
		},


		renderQuestion:function(question) {
			var label = question.getLabel();
			var uid = question.getUID();
			var html = [
				'<div class="qm-question" id="', uid, '">', 
					label.text(), 
					'<ul class="qm-options">'
			];
			
			var answers = question.getAnswers();
			var l = answers.length;
			for (var i=0; i<l; i++) {
				html.push(this.renderAnswer(answers[i], question));
			}

			html.push(
					'</ul>',
				'</div>'
			);

			return html.join('');
		},

		renderAnswer:function(answer, question) {
			var mode = question.mode;
			var title = question.getLabel();
			var label = answer.getLabel();
			var type = label.attr('type');
			var name = label.attr('name');
			var value = label.attr('value');
			var cls = label.attr('class');
			var text = label.text();
			var uid = answer.getUID();

			
			this.tips.put(uid, answer.getAdvice());

			var answerHTML = [];
			
			if(/html/i.test(type)) {
				answerHTML.push(text);
			} else {
				var answerText = text.replace(/<[^>]+>/mg, '');
				answerHTML.push(
					'<input type="', type, '" name="', name, '" value="', value, '" id="', uid, '" alt="', answerText, '" /> '
				);
				
				switch (mode) {
					case 'triggered':
						var questionTitle = '';
						var campaign = KeuzeHulpWonen.getCampaign();
						try {
							var questionHtml = title.text().replace(/\s+/gm, ' ');
							questionTitle = />([^<]+)/.exec(questionHtml)[1];
						} catch (e) {
						}
						
						answerHTML.push(
							'<a href="#', uid, '" class="',cls,'" rel="qm-choose" ', 
								Statistics.getAttributes(campaign, questionTitle, answerText),
							'>', 
								text, 
							'</a>'
						);
					break;
					case 'question':
					default:
						answerHTML.push('<label for="', uid, '" class="',cls,'">', text, '</label>');
					break;
				}
			}			

			return [
				'<li class="qm-answer ', mode, '" rel="'+uid+'">',
					answerHTML.join(''),					
				'</li>'
			].join('');
		},

		renderAdvice:function(advice) {
			return [
				'<div class="qm-advice">', 
					advice.text(), 
				'</div>'
			].join('');
		},

		displaySummary:function(data) {
			var keys = data.getKeys();
			var html = [];

			if(keys.length == 0) {
				html.push('<p>Nog geen tips beschikbaar.</p>');
			} else {
				html.push(
					'<h2>Dit zijn de verzekeringen die passen bij jouw situatie:</h2><ul class="checks">'
				);

				var titles = [];

				for(var i=0; i<keys.length; i++) {
					var key = keys[i];
					var header = data.get(key); 
					var title = header.text();

					if(title in titles) {
						continue;
					}

					titles[title] = true;

					if(title) {
						html.push('<li class="'+ header[0].className +'">', title, '</li>');
					}
				}

				html.push('</ul>');
			}

			this.$selected.html(html.join(''));
		},

		setButtonState:function(state) {
			if(this.currentButtonState) {
				this.$buttons.removeClass(this.currentButtonState);
			}
			this.$buttons.addClass(state);
			this.currentButtonState = state;
		},

		setState:function(state) {
			if(this.currentState) {
				this.$container.removeClass(this.currentState);
			}

			this.$container.addClass(state);
			this.currentState = state;

			var buttonState = state;
			var page = this.currentPage;
			var pages = this.totalPages;
			
			this.$questions.hide();
			this.$answers.hide();
			this.$advice.hide();
			this.$intro.hide();

			this.$buttons.show();
			this.$selected.show();

			switch (state) {
				case 'question':
				case 'triggered':
					this.$questions.show();
					if(page == 1) {
						buttonState = 'first';
					}
				break;
				case 'answer':
					this.$answers.show();
				/*	if(page == pages) {
						buttonState += ' last';
					}
				*/
				break;
				case 'intro':
					this.$buttons.hide();
					this.$selected.hide();
					this.$intro.show();
					buttonState = 'intro';
				break;
				case 'advice':
					this.$advice.show();
				break;
			}
			
			this.setButtonState(buttonState);
		},

		setPage:function(page, total) {
			this.currentPage = page;
			this.totalPages = total;
			
			if(this.lastPage) {
				this.$pages.removeClass(this.lastPage);
			}

			this.lastPage = 'page-'+page;
			this.$pages.addClass(this.lastPage);

			this.$pages.find('span.state').html(
				'Vraag ' + Math.min(page, total) + ' van ' + total	
			);

			this.setPercentage((page-1)/total);
		},

		setPercentage:function(percentage) {
			this.percentage = percentage; //Math.round(percentage * 10)/10;
			var width = this.percentage * 471;
			this.$pages.find('span.result span.bar').css({
				width: width + 'px'
			});
			this.$pages.find('span.result span.arrow').css({
				left: width + 'px'
			});

			this.$pages.find('span.result span.value').html(
				parseInt(this.percentage * 100, 10) + '%'
			);
		},

		getAdvice:function(uid) {
			return this.tips.get(uid);
		},

		reset:function() {
			this.$selected.empty();
			this.setState('intro');
		}
	};


	/**
	 * Validator
	 */
	function Validator() {
		LBi.Dispatcher.subscribe('validate', this.check.bind(this));
	}

	Validator.prototype = {
		check:function(e){
			var hasValue = false;
			var $inputs = $(e.target).find('input');
			if($inputs.length == 0) {
				return true;
			}
			
			$inputs.removeClass('qm-error');
			$inputs.each(function(){
				switch(this.type) {
					case 'radio': 
					case 'checkbox':
						hasValue |= this.checked;
					break;
					default:
						hasValue |= this.value? true : false;
				}
			});
			
			var $text = $inputs.filter(':text');
			if($text.length && !this.checkDate($text)) {
				$text.addClass('qm-error');
				e.preventDefault();
			}

			if(!hasValue) {
				e.preventDefault();
			}
		},

		checkDate:function(inputs) {
			var day = 0, month = 0, year = 0;
			var l = inputs.length;
			for(var i=0; i<l; i++) {
				var input = inputs[i];
				if(!input.value) {
					continue;
				}

				if(/dag/i.test(input.name)) {
					day = parseInt(input.value, 10);
				} else if(/maand/i.test(input.name)) {
					month = parseInt(input.value, 10) -1;
				} else if(/jaar/i.test(input.name)) {
					year = parseInt(input.value, 10);
				}
			}

			if(isNaN(day + month + year)) {
				return false;
			}

			if(year || day || month) {
				var now = new Date();
				date = new Date(year, month, day);
				if(date.getMonth() != month || date < now || isNaN(date.getTime())) {
					return false;
				}
			}

			return true;
		}
	};


	/**
	 * Statistics hook
	 */
	var Statistics = {
		decorate:function(button, c, q, a) {
			button.
				attr('id', c).
				attr('name', q).
				attr('alt', a);
		},

		handleIntro:function(c, q) {
			var $intro = KeuzeHulpWonen.getIntro();
			var $continue = $intro.find('a.start');
			this.decorate($continue, c, q, '');
		},

		handleChoice:function(c, q, a) {
			var $buttons = KeuzeHulpWonen.getButtons();
			var $next = $buttons.find('a.answer');
			this.decorate($next, c, q, a);
		},

		handleAdvice:function(c,q) {
			var $advice = KeuzeHulpWonen.getAdvice();
			var $submit = $advice.find('a.submit');
			this.decorate($submit, c, q, '');
		},

		getAttributes:function(c, q, a) {
			return 'id="' + c + '" name="' + q + '" alt="' + a + '"';
		}
	};	

	/**
	 * init
	 */
	$(function(){
		KeuzeHulpWonen.initialize();
		if(typeof KeuzeHulpStartupVEH != "undefined") { // check of variabele bestaat
			if (KeuzeHulpStartupVEH != null){
				if (KeuzeHulpStartupVEH){ 
					KeuzeHulpWonen.questionManager.loadIndex();
					KeuzeHulpWonen.questionManager.toggle(true);
				}
			}
		}
	});

})(jQuery);