/**
 * FBTO Internetstraat
 */
(function($){
	
	window.KeuzeHulp = {
		initialize:function() {
			
			var url = $('link[rel=questions]').attr('href');

			this.questionManager = new QuestionManager({
				container: '#keuzehulp',
				intro: '#fbto-intro',
				questions: '#fbto-questions',
				answers: '#fbto-answers',
				selected: '#fbto-selected',
				advice: '#fbto-advice',
				buttons: '#buttons',
				pages: '.header',
				data: url
			});			
		}		
	};
	
	/**
	 * Question manager
	 */
	function QuestionManager(settings) {
		this.root = $(settings.container);
		this.container = $(settings.questions);
		this.answers = $(settings.answers);
		this.advice = $(settings.advice);
		this.$selected = $(settings.selected);
		
		this.form = $('form', settings.container);
		this.questions = [];
		this.index = -1;

		this.validator = new Validator(settings);
		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.loadQuestions(settings.data);
	}

	QuestionManager.prototype = {
		constructor: QuestionManager,

		loadQuestions:function(url) {
			$.get(url, this.parseQuestions.bind(this), 'xml');
		},

		parseQuestions:function(response) {
			var $xml = $(response);
			var config = $xml.find('config');
			var questions = $xml.find('step');
			var l = questions.length;
			
			for(var i=0; i<l; i++) {
				this.questions.push(
					new Question(questions[i])
				);
			}

			this.applySettings(config);
			this.renderQuestions();
			this.next();
		},

		applySettings:function(config) {
			this.remoteURL = config.attr('action');
			this.remoteMethod = config.attr('method');
		},

		handleClick:function(e) {
			var link = e.target;
			var rel = link.rel;
			var type = /qm-([^ ]+)/.exec(rel)[1];

			switch (type) {
				case 'next': this.next(); break;
				case 'previous': this.previous(); break;
				
				case 'answer':
					if(this.validate()) {
						this.answerQuestion();
					}
				break;
				case 'advice':
					if(this.validate()) {
						this.advise();
					}
				break;
				
				case 'reset':	this.reset(); break;
				case 'start':	this.start(); break;
				case 'submit':	this.submit(); break;
				
				case 'open':
					this.reset();
					window.scrollTo(0,0); // naar boven scrollen bij openen keuzehulp
					this.root.fadeIn();
				break;
				case 'close':
					this.root.fadeOut();
				break;
			}

			e.preventDefault();
		},


		handleInputClick:function(e) {
			var input = e.target;
			var name = input.name;
			var uid = input.id;

			var advice = this.view.getAdvice(uid);
			
			if (advice){ // temporary fix ivm reageren op alle inputfields (ESI:22-12-2009)
				if(advice.length > 1) {
					advice = this.filterAdvice(advice);
				}
				
				var value = advice[0].getAttribute('value');
				if(value) {
					input.value = value;
				}
	
				this.inputData.put(name, input.value);
	
				var question = this.currentQuestion.id;
				this.adviceData.put(question, advice.text());
			}
		},

		filterAdvice:function(adviceList) {
			var l = adviceList.length;
			for(var i=0; i<l; i++) {
				var advice = adviceList[i];
				var target = advice.getAttribute('for');
				
				if(this.matchesInputFor(target)) {
					return adviceList.eq(i);
				}
			}
		},

		matchesInputFor:function(values) {
			var requirements = values.split(',');
				
			for(var j=0; j<requirements.length; j++) {
				var pair = requirements[j].split('=');
				var value = this.inputData.get(pair[0]);
				if(value == pair[1]) {
					return true
				}
			}

			return false;
		},

		validate:function(){
			return LBi.Dispatcher.fire('validate', this.currentQuestion);
		},

		renderQuestions:function() {
			var questions = this.view.renderQuestions(this.questions);
			LBi.DOM.append(this.container, $(questions));
			this.$questions = $('.qm-question', this.container);
		},

		answerQuestion:function() {
			var question = this.currentQuestion.id;
			var advice = this.adviceData.get(question);
			var pages = this.$questions.length;

			this.answers.html(advice);
			this.view.setPercentage((this.index+1)/pages);
			this.view.setState('answer');

			var title = this.answers.find('h2').clone();
			this.selected.put(question, title);

			this.view.displaySummary(this.selected);
		},

		next:function() {
			var last = this.questions.length -1;
			if(++this.index > last ) { 
				this.index = last; 
			}

			var question = this.questions[this.index];
			var filter = question.filter;
			if(filter && !this.matchesInputFor(filter)) {
				this.next();
				return;
			}
			
			this.setQuestion(this.index);
		},

		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;
			if(filter && !this.matchesInputFor(filter)) {
				this.previous();
				return;
			}

			this.setQuestion(this.index, true);
		},

		setQuestion:function(index, reset) {
			var pages = this.$questions.length;
			var $question = this.$questions.eq(index);

			if(reset) {
				var inputs = $(this.currentQuestion).find('input:radio, input:checkbox');
				inputs.attr('checked', false);
			}
			
			this.$questions.hide();
			this.currentQuestion = $question[0];
			$question.show();
			
			this.view.setPage(index + 1, pages);
			this.view.setState('question');
		},

		advise:function(){
			var pages = this.$questions.length;
			this.view.setPage(pages + 1, pages);
			this.view.setState('advice');
		},

		submit:function() {
			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);
		},

		start:function() {
			this.reset();
			this.index = -1;
			this.next();
			this.view.setState('question');
		}
	};

	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.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.$questions = $(settings.questions);
		this.$answers = $(settings.answers);
		this.$selected = $(settings.selected);
		this.$advice = $(settings.advice);

		this.tips = new LBi.HashMap();
	}

	QuestionView.prototype = {
		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(), '<div class="qm-options">'
			];
			
			var answers = question.getAnswers();
			var l = answers.length;
			for (var i=0; i<l; i++) {
				html.push(this.renderAnswer(answers[i]));
			}

			html.push(
					'</div>',
				'</div>'
			);

			return html.join('');
		},

		renderAnswer:function(answer) {
			var label = answer.getLabel();
			var type = label.attr('type');
			var name = label.attr('name');
			var value = label.attr('value');
			var text = label.text();
			var uid = answer.getUID();

			this.tips.put(uid, answer.getAdvice());

			return [
				'<div class="qm-answer">',
					'<input type="', type, '" name="', name, '" value="', value, '" id="', uid, '" /> ',
					'<label for="', uid, '">', text, '</label>',
				'</div>'
			].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>Voor jou geselecteerd:</h2>',
					'<h3>Basisdekking:</h3><ul>'
				);

				var ext = false;

				for(var i=0; i<keys.length; i++) {
					var key = keys[i];
					var header = data.get(key); 
					var title = header.text();

					if((i >= 1) && title && !ext) {
						ext = true;
						html.push('</ul><h3>Uitbreidingen:</h3><ul>')
					}

					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':
					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;
			this.$pages.find('span.state').html(
				'Vraag ' + Math.min(page, total) + ' van ' + total	
			);

			this.setPercentage((page-1)/total);
		},

		setPercentage:function(percentage) {
			this.percentage = percentage;
			var width = percentage * 200;
			this.$pages.find('span.result span.bar').css({
				width: width + 'px'
			});

			this.$pages.find('span.result span.value').html(
				parseInt(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 $radios = $(e.target).find('input:radio, input:checkbox');
			if($radios.length == 0) {
				return true;
			}

			var $checked = $radios.filter(':checked');
			if($checked.length == 0) {
				e.preventDefault();
			}
		}
	};

	/**
	 * init
	 */
	$(function(){
		KeuzeHulp.initialize();
	});

})(jQuery);
