$(function(){ //Page ready
	base.initCufon();
	base.initPopups();
	base.initSearch();
	base.addLinkIcons();
	forms.initPlaceholders();

	$.ajaxSetup({ //Ajax is used mainly for search and in the jobapplication
		cache: false //Caching is the source of many problems in IE
	});
});

var base =
{
	//Init Cufon text
	initCufon:function() {
		//https://github.com/sorccu/cufon/wiki/API
		var preTrim = function(text, textNode, element, options) { return $.trim(text); };
		//Går kanske att använda trim?
		Cufon.set('modifyText', preTrim);
		Cufon.replace('.main-nav li a, .quick-apply .row a', { fontFamily: 'ITCFGothicStd-Demi', hover: true, modifyText: preTrim });
		Cufon.replace('section h1, body.start section h2, section li h2, section > h2, .text-block h2, .details-box .heading h2, .aside > h1, .details-box .heading .number, #footer h3, #main .contact-description h4, .news-archive h2, .contact-box h2, section.available-jobs li h2', { fontFamily: 'ITCFGothicStd-Demi', modifyText: preTrim });
		Cufon.replace('.visual .visual-section .button span', { fontFamily: 'ITCFGothicStd-Heavy', textShadow: '#000 0 1px', modifyText: preTrim });
		Cufon.replace('.vacancy-number', { fontFamily: 'ITCFGothicStd-Heavy', modifyText: preTrim });
		Cufon.replace('.more-box .more, .column li a, #main .headline, .ingress, .description span.upper-case', { fontFamily: 'ITCFGothicStd-Book', hover: true, modifyText: preTrim });
		Cufon.replace('h2.message-read', { fontFamily: 'ITCFGothicStd-Book', modifyText: preTrim });
		Cufon.replace('.visual .visual-section h1', { fontFamily: 'ITCheavyital', hover: true, modifyText: preTrim });
		Cufon.replace('.visual .visual-section h1', { textShadow: '#919b8e 0 2px', modifyText: preTrim });
		//Cufon.replace('.note-small .apply, .text-block .apply a, .notethis', {fontFamily: 'NoteThis'});
	},

	//Init popups
	initPopups:function() {
		//Login
		$('.login span a').click(function() {
			$('.popup-login').fadeToggle();
			return false;
		});
		$('.popup-login .btn-login').click(function(e) { ipClient.loginClick(this, e, true); });

		$('a.close').click(function()
		{
			$(this).closest('.popup-err, .popup, .popup-big').fadeOut();
			return false;
		});
	},

	//Init search
	initSearch:function() {
		var focusClass = 'parent-focus',
			form = "#search-form",
			content = form + ' div.content',
			$form = $(form),
			$row = $(form + ' div.row');
			$drop = $(form + ' div.drop'),
			$text = $(form + ' input.text');

		//Focus
		var focus = function() {
			$row.addClass(focusClass);
			if ($(content).children().size() > 0)
				$drop.fadeIn('fast');
		};

		//Blur
		var blur = function() {
			//Delay blur
			clearTimeout($.data(this, 'blurtimer'));
			var wait = setTimeout(dropfade, 20);
			$(this).data('blurtimer', wait);

			function dropfade() {
				if (!$text.is(':focus'))
				{
					$row.removeClass(focusClass);
					$drop.fadeOut('fast');
				}
			}
		};

		//Ajax search
		var search = function() {
			//Delay search somewhat
			clearTimeout($.data(this, 'searchtimer'));
			var wait = setTimeout(search, 350);
			$(this).data('searchtimer', wait);

			function search() {
				if ($text.val().length > 1)
					$form.ajaxSubmit({
						target: content,
						success: function() {
							if ($row.hasClass(focusClass))
								$drop.fadeIn('fast');
						},
						beforeSerialize: function($form) {
							$url = $form.find('input[name="RP"]');
							$url.val('/sok/ajax');
						}
					});
			}
		}

		//Bind
		$text.keyup(search).focus(focus).blur(blur).blur();
		$drop.focus(function() {
			$text.focus();
		}).blur(blur);
		$form.submit(function(e) {
			if ($text.val().length < 2)
				e.preventDefault();
			else
				$url.val('/sok');
		});
	},

	showStartBubble:function() {
		$('.visual .box').delay(2000).fadeIn(1000);
		$('#slick-hide').click(function() {
			$('.visual .box').fadeOut('slow');
			return false;
		});
	},

	initFaq:function() {
		//Shorten questions
		/*$('section li div.faq-answer p').each(function() {
			var t = $.trim($(this).text()),
				more = "Läs mer",
				length = 180;
			if (t.length > length)
			{
				$(this).html(t.substr(0, length - 3) + '<ins>...</ins><ins style="display: none;">' + t.substr(length - 3) + '</ins> <a href="#" class="linkicon">' + more + '</a>');
				$(this).children('a').click(function() {
					$(this).siblings('ins').toggle();
					$(this).text($(this).text() == more ? "Dölj" : more);
					return false;
				});
			}
		});*/
		$('.faq-answer p').expander(
			{
				slicePoint: 180,
				expandText: "Läs mer",
				userCollapseText: "Dölj",
				moreClass:"read-more-linkicon",
				lessClass:"read-less-linkicon"
			}
		);
	},

	addLinkIcons:function() {
		var linkify = function ($col/*lection*/, allowPrevSibling)
		{
			$col.each(function ()
			{
				if (allowPrevSibling || //Either a previous sibling is allowed
					$(this.previousSibling).text().trim() == '') //Or there is no pre text content
					$(this).addClass('linkicon');
			});
		}

		linkify($('ul.available-jobs > li > a:only-child, div + a, br + a, p > a:first-child, div > a:first-child, p > span:first-child > a:first-child').filter(':not(li > p > a, .button a, #slickbox a, .apply a, .details-box a, .popup-login a, .logo a, .albumrow a, .image-detail a, .quick-apply a, a:has(img), a[href^="mailto:"], [class]), .more'));
	}
}

var jobApp =
{
	//Represents each step in job application (1-5)
	data: [{pass: null}, {"list": []}, {"list": []}, null, null],

	//Used to determine if step 0 should load job app or do a quick apply
	step0QuickApply: true,

	//Used to change appearance of app when only updating CV
	cvUpdateOnly: false,

	init:function(cvUpdateOnly)
	{
		//Adjust z-index for popup-holders in descending order
		var z = 30;
		$('.popup-holder').each(function() {
			$(this).css('zIndex', z--);
		});

		//Init popups
		$('a.more').click(function(element)
		{
			var $popup = $(this).next('.popup, .popup-big'), //Current popup
				$popups = $('.popup, .popup-big').not($popup); //All popups but current

			$popups.find('a.close').click(); //Hide other steps
			$popup.fadeIn(); //Fade in current

			return false;
		});

		//Special handling of popups close
		$('#content .inner > a.close').click(function() {
			if ($(this).closest('section.details-box.passed').size() > 0)
				$(this).parent().find('.btn-save, .btn-step').click();
		});

		//Quick apply & update existing profile (step 0 or 1)
		$('section.info-box .popup.quick-apply .btn-send').click(jobApp.quickApply);
		$('section.info-box a.more').click(function () { if (job_occupation_id == 0) jobApp.determineQuickApplyType(); }); //If not applying for specific job, then quick-apply implies updating existing profile
		$('.btn-info, .btn-enter, .btn-update-profile').click(jobApp.determineQuickApplyType);

		//CV update
		if (cvUpdateOnly)
		{
			jobApp.cvUpdateInitial(true);
			jobApp.cvUpdateOnly = true; //For access from other functions
		}

		//Get job app
		$('#btn-get-app').click(function () { jobApp.loadApp(this, false); });

		//Init step 2 & 3 season checkbox (enable/disable)
		$('#ongoing-employment, #ongoing-education').click(function() {
			var $input = $(this).parent().prev().find('input:last');
			if($input.enabled())
				$input.disable();
			else
				$input.enable();
		});

		//Init step 5
		$('.experience h3').click(function() { //Accordions
			$(this).next('.experience-group').toggle(400);
			$(this).toggleClass("active");
			return false;
		});
		$('#gradeSchoolLang, #highScoolLang').click(function() { //Other/special languages
			$(this).parent().prev().prop("checked", true);
		}).blur(function() {
			$check = $(this).parent().prev();
			var val = $(this).val();
			if (val.length > 0 && val != $(this).attr('placeholder'))
				$check.prop("checked", true);
			else
				$check.prop("checked", false);
		});

		//Tick and disable checkbox with job occupation id in step 5
		if (job_occupation_id > 0)
			$('#check-' + job_occupation_id).check().disable();

		//Adding to step list (multi sub step - 2 & 3)
		$('.details-box .content .row a:not(.close):not([target])').click(jobApp.saveStep);

		//Save steps
		$('.details-box .btn-save, .details-box .btn-step').click(jobApp.saveStep);

		//Submit application
		$('.btn-application').click(jobApp.submitApplication);
	},

	//Used to change appearance of app when only updating CV
	cvUpdateInitial:function(initial)
	{
		$cvFade = $('.cv-update-fade');
		$dboxFrames = $('section.details-box .details-frame');
		$appSubmit = $('.btn-application');
		$infoMore = $('section.info-box a.more');

		if (initial) //Fade bulk of app
		{
			$cvFade.show();
			$dboxFrames.find('> p, > .more-box').hide();
			$appSubmit.hide();
			$infoMore.click();
		}
		else //Show app
		{
			$cvFade.hide();
			$dboxFrames.find('> p, > .more-box').show();
			$appSubmit.show();
			$infoMore.fadeOut();
		}
	},

	submitApplication:function(event) //Called by final form submit
	{
		//Does not work in IE8
		/*var $dboxes = $('.details-box:not(:last)'); //Last box is not mandatory
		if ($dboxes.size() > $dboxes.filter('.passed').size())
		{
			alert('Var vänlig fyll i steg 1-4 innan du skickar in ansökan!');
			return false;
		}*/

		var passed = true;
		for (i = 0; i < 4; i++)
			if (!jobApp.getDetailsBox(i).is('.passed'))
			{
				passed = false;
				break;
			}

		if (passed)
			$('#json').val(JSON.stringify(jobApp.data));
		else
		{
			alert('Var vänlig fyll i steg 1-4 innan du skickar in ansökan!');
			return false;
		}
	},

	getDetailsBox:function(step)
	{
		return $('section.details-box:eq(' + step + ')');
	},

	getFirstContent:function($dbox)
	{
		return $dbox.find('.content:first');
	},

	setListSummary:function($scope, html)
	{
		$cb = $scope.find('.courses-box');
		if (html)
			$cb.show().html(html);
		else
			$cb.hide().html('');
	},

	determineQuickApplyType:function()
	{
		var $qabox = $('section.info-box div.quick-apply'),
			$p = $qabox.find('form > p'),
			$submit = $qabox.find('.btn-send[name=quick-apply]');

		if ($(this).is('.btn-info')) //Quick apply
		{
			$(this).closest('.popup').fadeOut();
			$qabox.fadeIn().find('#q-email').val($('#r-email').val()); //Show popup and prepopulate e-mail field

			jobApp.step0QuickApply = true;
			$p.attr('style', '');
			$submit.removeClass('btn-get');
		}
		else //Update existing profile
		{
			$(this).closest('.popup').fadeOut().next('.popup').fadeIn();

			jobApp.step0QuickApply = false;
			$p.attr('style', 'margin-bottom: -10px; visibility: hidden;');
			$submit.addClass('btn-get');
		}
	},

	quickApply:function(e)
	{
		if (jobApp.step0QuickApply)
			ipClient.loginClick(this, e, false);
		else
		{
			jobApp.loadApp(this, true);
			e.preventDefault();
		}
	},

	loadApp:function(submitbutton, loadStep1/*Means this was called from "quick-apply"*/)
	{
		var $inputs = forms.getInputs($(submitbutton).closest('.popup-holder')), //Find inputs
			errors = forms.validateAll($inputs); //Validate

		if (errors.length > 0) //Display errors
			forms.displayErrors(errors, submitbutton);
		else
		{
			forms.hideErrors(submitbutton); //Fade out errors

			var object = forms.inputsToObject($inputs);
			ipClient.getJobApp(object.email, object.pass, function(jobapp) {
				if (jobapp)
				{
					//If CV update, reset to normal appearance
					if (jobApp.cvUpdateOnly)
						jobApp.cvUpdateInitial(false);

					//Load steps
					for (var step = 0; step < 5; step++)
					{
						if (loadStep1 || step > 0) //All steps (but 1, depending on var)
						{
							jobApp.data[step] = jobapp[step]; //Assign downloaded data

							var $inputs = forms.getInputs(jobApp.getFirstContent(jobApp.getDetailsBox(step))); //Get input fields
							forms.objectToInputs(jobApp.data[step], $inputs); //Assign object values to input fields

							if (step == 1 || step == 2) //List steps (2 & 3)
							{
								jobApp.sortDateArray(jobApp.data[step]["list"]); //Sort
								jobApp.showSummary(step, true); //Must always update summary in popup, to enable list operations
							}
							else if (step == 4) //Step 5
								$('#gradeSchoolLang, #highScoolLang').blur(); //Run blur event (checks boxes if inputs are set)
						}

						//Verify (approximately) that applicant has provided information in step (old applicants may not have done this), before finishing step and showing summary
						if (step == 0 || //Step 1
							(step < 3 && jobapp[step]['list'].length > 0) || //List steps (2 & 3)
							(step == 3 && jobapp[step]['reason'].length > 0) || //Step 4
							(step == 4 && !(jobapp[step] instanceof Array)/*Is only array when empty because of how PHP json_encode works*/)) //Step 5
							jobApp.finishAndCloseStep(step);
					}

					//Store password for registration (in hidden field)
					$('#pass').val(object.pass);

					//Click step 1 submit (to store pass & jobGUID as JSON - in jobApp.data)
					jobApp.getFirstContent(jobApp.getDetailsBox(0)).find('.btn-save:first').click();

					if (loadStep1)
						$(submitbutton).closest('.popup').fadeOut(); //Close "quick-apply" popup

					//Cannot change e-mail
					$('#r-email').disable();
				}
				else
					forms.displayErrors(loadStep1 ? 'Felaktiga inloggningsuppgifter, kontrollera e-postadress och lösenord.' : 'Felaktigt lösenord.', submitbutton);
			});
		}
		return false;
	},

	finishAndCloseStep:function(step) { //Method for finishing step and closing popup
		jobApp.getDetailsBox(step).addClass('passed').find('.popup, .popup-big').fadeOut();
		jobApp.showSummary(step); //Show summary in details box
	},

	saveStep:function() //Triggered by submit button or anchor
	{
		var $dboxes = $('section.details-box'), //Details boxes
			$dbox = $(this).closest('section.details-box'), //Details box for this step
			$content = $(this).closest('.content'), //Popup content
			step = $.inArray($dbox[0], $dboxes), //Step number (zero-based)
			popup = $.inArray($content[0], $dbox.find('.content')), //Popup number (in step) (zero-based)
			isListStep = step == 1 || step == 2, //Step 2 or 3
			anchorClick = $(this).is('a'), //Adding more to list (anchor click in step 2 or 3)
			singleFieldName, //Name of non-list field in step 2 and 3
			inputsAreDefault, //True if inputs are default values
			$inputs = forms.getInputs($content), //Find inputs
			$listInputs;

		if (isListStep)
		{
			//Init list step vars
			singleFieldName = step == 1 ? "prev_exp" : "teacher_qualification";
			$listInputs = $inputs.not("[name=" + singleFieldName + "]");
			inputsAreDefault = forms.areDefault($listInputs);

			//Filter inputs in list step
			if (anchorClick)
				$inputs = $listInputs;
			else if (jobApp.data[step]["list"].length > 0 && inputsAreDefault) //If list contains items and inputs are default
				$inputs = $inputs.filter("[name=" + singleFieldName + "]");
		}

		var errors = forms.validateAll($inputs); //Validate

		if (errors.length > 0) //Display errors
		{
			forms.displayErrors(errors, this, anchorClick);
			$dbox.removeClass('passed');
			jobApp.insertSummary(step); //Display original description/summary
		}
		else //No errors - compile data
		{
			forms.hideErrors(this); //Fade out errors

			var object = forms.inputsToObject($inputs); //Get data

			if (!isListStep)
			{
				//Special handling in step 1; if user already exists (and application has not been loaded) -> load application
				if (step == 0 && $('#pass').val().length == 0 && !jobApp.cvUpdateOnly)
				{
					jobApp.data[step] = object; //Store data

					ipClient.loginEnabled(object.email, function(enabled) {
						if (enabled)
						{
							$loginEnabledPopup = $content.closest('.popup').fadeOut().next('.popup');
							$loginEnabledPopup.find('strong').text('E-postadressen ' + object.email + ' finns redan registrerad.');
							$loginEnabledPopup.fadeIn();
						}
						else
							jobApp.finishAndCloseStep(step);
					});
				}
				else
				{
					if (step == 4) //In step 5, do not store non set values
						for (prop in object)
							if (!object[prop])
								delete object[prop];

					jobApp.data[step] = object; //Store data
					jobApp.finishAndCloseStep(step);
				}
			}
			else
			{
				if (!anchorClick) //If submitting step
					jobApp.data[step][singleFieldName] = object[singleFieldName]; //Field not to be stored in list (the first field in popup 2 and 3)

				if (!inputsAreDefault) //List data in form
				{
					delete object[singleFieldName]; //Should not be stored in list
					jobApp.data[step]["list"].push(object); //Store list data
					jobApp.sortDateArray(jobApp.data[step]["list"]); //Sort
					forms.resetInputs($listInputs); //Reset list inputs
					jobApp.showSummary(step, true); //Must always update summary in popup, to enable list operations
				}

				if (!anchorClick) //If submitting step
					jobApp.finishAndCloseStep(step);
			}
		}

		return false;
	},

	sortDateArray:function(arr)
	{
		arr.sort(function (a, b) { //Sort by from-dates
			return a.from.localeCompare(b.from);
		});
	},

	//Is used to display new or original summary
	insertSummary:function(step, html/*display original summary if not set*/)
	{
		var $dbox = jobApp.getDetailsBox(step),
			$p = $dbox.find('> div > div > p'),
			$hidden = $p.filter(':hidden'),
			$visible = $p.filter(':visible'),
			isDefault = $p.filter(':hidden').size() == 0;

		if (isDefault)
			$visible.hide();
		else
			$visible.remove();

		if (html)
			$dbox.find('.more-box').before(html);
		else
			$p.show();
	},

	showSummary:function(step, inPopup)
	{
		var d = jobApp.data[step];
		var listoperations = '<span class="listoperations"><a href="#" title="Ändra" class="listoperation-edit"></a><a href="#" title="Ta bort" class="listoperation-delete"></a></span>';
		var html;
		switch(step)
		{
			case 0:
				html = "<p><b>" + d["firstname"] + " " + d["surname"] + "</b> är född <b>" + d["ssn"].substring(0, 6) + "</b> och nås på <b>" + d["email"] + "</b> eller via telefon <b>" + d["telephone"] + "</b>. Postadress är <b>" + d["street"] + ", " + d["zipcode"] + " " + d["city"] + "</b>.</p>";
				break;
			case 1:
				l = d["list"];
				if (l.length > 0)
				{
					html = inPopup ? '<strong class="title">Tillagda arbetsgivare:</strong>' : "";
					for (var i = 0; i < l.length; i++)
					{
						d = l[i];
						html += "<p>" + (inPopup ? listoperations : "") + d["service"] + " på " + d["employer"] + " från " + d["from"] + " " + (d["ongoing"] ? "och framåt" : "till " + d["to"]) + ".</p>";
					}
				}
				break;
			case 2:
				l = d["list"];
				if (l.length > 0)
				{
					html = inPopup ? '<strong class="title">Tillagda utbildningar:</strong>' : "";
					for (var i = 0; i < l.length; i++)
					{
						d = l[i];
						var schooltype = jobApp.getDetailsBox(step).find("select[name='level'] option[value='" + d["level"] + "']").text();
						html += "<p>" + (inPopup ? listoperations : "") + d["school"] + " (" + schooltype + ") från " + d["from"] + " " + (d["ongoing"] ? "och framåt" : "till " + d["to"]) + ".</p>";
					}
				}
				break;
			case 3:
				var days = jobApp.getDetailsBox(step).find("input[type='radio'][name='days'][value='" + d["days"] + "']").next('label').text();
				html = "<p><em>\"" + d["reason"] + "\"</em></p><p>Jag kan arbeta <b>" + days + "</b> dag" + (days > 1 ? "ar" : "") + " i veckan.</p>";
				break;
			default:
				html = "<p>Jag har angett intresse för ytterligare arbetsmöjligheter.</p>";
				break;
		}

		//Insert summary
		var $dbox = jobApp.getDetailsBox(step),
			$content = jobApp.getFirstContent($dbox);
		if (inPopup)
		{
			jobApp.setListSummary($content, html);
			jobApp.bindListoperations(step); //Bind click events for list operations
		}
		else
			jobApp.insertSummary(step, html);
	},

	bindListoperations:function(step)
	{
		jobApp.getFirstContent(jobApp.getDetailsBox(step)).find('span.listoperations').each(function(i) {
			$(this).find('a').each(function() {
				$(this).click(function() {
					if ($(this).is('.listoperation-edit'))
						forms.objectToInputs(jobApp.data[step]["list"][i], forms.getInputs(jobApp.getFirstContent(jobApp.getDetailsBox(step))));
					jobApp.data[step]["list"].remove(i);
					jobApp.showSummary(step, true);

					return false;
				});
			});
		});
	}
}

var ipClient =
{
	getJobApp:function(email, pass, success)
	{
		$.getJSON('/jobb/json_get_jobapp', { email: email, pass: pass }, success);
	},

	loginEnabled:function(email, success)
	{
		$.getJSON('/jobb/json_login_enabled', { email: email }, success);
	},

	login:function(email, pass, intranet, success)
	{
		$.getJSON('/intranat/json_login', { email: email, pass: pass, intranet: intranet ? 'true' : '' }, success);
	},

	loginClick:function(submitbutton, event, intranet)
	{
		var $form = $(submitbutton).closest('form'),
			$inputs = forms.getInputs($form), //Find inputs
			errors = forms.validateAll($inputs); //Validate

		if (errors.length > 0) //Display errors
			forms.displayErrors(errors, submitbutton);
		else
		{
			forms.hideErrors(submitbutton); //Fade out errors

			var object = forms.inputsToObject($inputs);
			ipClient.login(object.email, object.pass, intranet, function(result) {
				if (result == 'success')
				{
					if (intranet)
						window.location.href = $form.attr('action');
					else
						$form.submit();
				}
				else
					forms.displayErrors(result == 'not_employed' ?
						'Du måste vara anställd hos Lärarförmedlarna för att kunna logga in.' :
						'Felaktiga inloggningsuppgifter, kontrollera e-postadress och lösenord.',
						submitbutton);
			});
		}
		event.preventDefault();
	}
}

var forms =
{
	initPlaceholders:function()
	{
		var attribute = "placeholder",
			defaultClass = "placeholder",
			$items = $("[" + attribute + "]");

		$items.each(function () {
			var $i = $(this);

			$i.blur(function () {
				$i.val($i.val().trim());
				if (!$i.val())
					$i.val($i.attr(attribute));
				if ($i.val() == $i.attr(attribute))
					$i.addClass(defaultClass);
			});

			$i.focus(function () {
				if ($i.val() == $i.attr(attribute)) {
					$i.val("")
					  .removeClass(defaultClass);
				}
			});

			$i.blur();
		});
    },

	areDefault:function($inputs)
	{
		var areDefault = true;
		$inputs.each(function () {
			if ($(this).is('select'))
			{
				if ($(this)[0].selectedIndex > 0)
				{
					areDefault = false;
					return;
				}
			}
			else if ($(this).is(':checkbox'))
			{
				if ($(this).checked())
				{
					areDefault = false;
					return;
				}
			}
			else
			{
				var ph = $(this).attr('placeholder');
				var val = $(this).val();
				if((ph && ph != val) || (!ph && "" != val))
				{
					areDefault = false;
					return;
				}
			}
		});
		return areDefault;
	},

	inputsToObject:function($inputs)
	{
		var data = {};
		$inputs.each(function()
		{
			/*if (!$(this).is(':disabled:')) //Step 5 prepopulated job occupation id is disabled
			{*/
				//Get name or id
				var name = $(this).attr('name');
				if (!name)
					name = $(this).attr('id');

				//Store value
				if ($(this).is(':radio')) //If radio, get group value
					data[name] = $('input[name=' + $(this).attr("name") + ']:radio:checked').val();
				else if ($(this).is(':checkbox'))
					data[name] = $(this).checked() ? $(this).val() : false;
				else //Else get value (if not default)
					if ($(this).val() != $(this).attr('placeholder'))
						data[name] = $(this).val();
			//}
		});
		return data;
	},

	objectToInputs:function(object, $inputs)
	{
		$.each(object, function(i, el) {
			//Find input
			var $input = $inputs.filter('#' + i + ', [name=' + i + ']');

			//Assign value
			if ($input.is(':radio'))
				$input.filter('[value=' + el + ']').attr('checked', true);
			else if ($input.is(':checkbox'))
			{
				if (el)
					$input.check();
				else
					$input.uncheck();
			}
			else
				$input.val(el);
		});
	},

	getInputs:function($scope)
	{
		return $scope.find('input:not([type=submit]), select, textarea');
	},

	validateAll:function($inputs)
	{
		var errors = [];
		$inputs.each(function()
		{
			//If input should be validated
			if ($(this).attr('data-validate'))
			{
				$(this).val($(this).val().trim()); //Trim value

				var $errorHolder = $(this).closest('.text, .textarea-box, .check-box, select, .radio-box');
				if (!forms.validate($(this)))
				{
					$errorHolder.addClass('error');
					errors.push(forms.extractLabel($errorHolder));
				}
				else
					$errorHolder.removeClass('error');
			}
		});
		return errors;
	},

	displayErrors:function(errors, trigger, anchorClick)
	{
		if (errors instanceof Array)
		{
			errors.unshift('Var vänlig kontrollera / fyll i följande fält:');
			errors = '<p>' + errors.distinct().join('</p><p>') + '</p>';
		}
		else
			errors = '<p>' + errors + '<p>';
		var $errPop = $(trigger);
		if (anchorClick)
			$errPop = $errPop.parent();
		$errPop = $errPop.next('div.popup-err');
		$errPop.fadeIn().find('.content').html(errors); //Show error
		$('div.popup-err').not($errPop).fadeOut(); //Fade out other errors
	},

	hideErrors:function(trigger)
	{
		$(trigger).closest('.content').find('div.popup-err').fadeOut();
	},

	resetInputs:function($inputs)
	{
		$inputs.each(function()
		{
			if ($(this).is('select'))
				$(this)[0].selectedIndex = 0;
			else if ($(this).is(':checkbox, :radio'))
				$(this).uncheck();
			else
				$(this).val('')/*.enable()*/;
			$(this).blur(); //Reset placeholders
		});
	},

	extractLabel:function($holder) { //Find and extract input holder's label text
		$label = $holder.prev('label, p');
		if ($label.size() == 0)
			$label = $holder.closest('.row, .season-row, .row-radio, .area-box, .area-box1, .content').children(":first");
		var remove = /[0-9\.\*]|\(.*?\)/ig; //Remove numbers, dots, stars and anything between (including) parentheses
		var text = $label.text().replace(remove, '');
		if (text.length > 21)
			text = text.substring(0, 18) + "...";
		return text;
	},

	validate:function($input) //Provides validation for (enabled) data-validate elements
	{
		if ($input.is(':disabled'))
			return true;

		var value;
		if ($input.is(':radio')) //If radio
			value = $('input[name=' + $input.attr("name") + ']:radio:checked').size() > 0; //Get if radio group is checked
		else
			value = $input.val(); //Else get value

		//Validation types
		var validate_types = $input.attr('data-validate').split('|');

		var i,type,compare_val;

		for(i = 0; i < validate_types.length; i++)
		{
			type = validate_types[i];

			if (type.indexOf('min[') != -1)
			{
				compare_val = type.match(/\d+/)[0];

				type = 'min';
			}
			if (type.indexOf('max[') != -1)
			{
				compare_val = type.match(/\d+/)[0];

				type = 'max';
			}
			else if (type.indexOf('match[') != -1)
			{
				compare_field_name = type.replace('match[','');
				compare_field_name = compare_field_name.replace(']','');

				compare_val = $('input[name="' + compare_field_name + '"]').val();

				type = 'match';
			}

			switch(type)
			{
				case 'not-empty':
					if (value == '')
						return false;
				break;
				case 'email':
					pattern = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/;
					return pattern.test(value);
				break;
				case 'min':
					if (value.length < compare_val)
						return false;
				break;
				case 'max':
					if (value.length > compare_val)
						return false;
				break;
				case 'match':
					if (value != compare_val)
						return false;
				break;
				case 'year-month':
					pattern = /^(19|20)\d\d-(0[1-9]|1[012])$/;
					return pattern.test(value);
				break;
				case 'pers_no':
					pattern = /^[0-9]{6}-[0-9]{4}$/;
					return pattern.test(value);
				break;
				case 'phone':
					pattern = /^[0-9+-]{6,20}$/;
					return pattern.test(value);
				break;
				case 'zipcode':
					pattern = /^\d{3}[ ]?\d{2}$/;
					return pattern.test(value);
				break;
			}
		}

		return true;
	}
}
