﻿if (parent.length) {
	window.open(location.href, "_top");
}

// library configuration properties

var config = {
	edge: "199310309999" // edge egn for 18 turners at elections day
};

// utility functions

function isLeapYear(year) {
	return year % 4 == 0 && year % 100 != 0 || year % 400 == 0;
}

function hide(o) {
	o.style.display = "none";
}

function show(o) {
	o.style.display = "";
}

var Egn = {
	Ok: 0,
	BadLength: 1,
	BadMonth: 2,
	BadDay: 3,
	BadChecksum: 4,
	BadGregory: 42
};

function getEgnYear(egn) {
	var digits = [];

	for (var i = 0; i < egn.length; i++) {
		digits[i] = parseInt(egn.charAt(i), 10);
	}

	var dd = digits[4] * 10 + digits[5],
		mm = digits[2] * 10 + digits[3],
		yy = digits[0] * 10 + digits[1],
		yyyy = null;

	if (mm >= 1 && mm <= 12) {
		yyyy = 1900 + yy;
	} else if (mm >= 21 && mm <= 32) {
		mm -= 20;
		yyyy = 1800 + yy;
	} else if (mm >= 41 && mm <= 52) {
		mm -= 40;
		yyyy = 2000 + yy;
	}

	return yyyy;
}

function checkEgn(egn) {
	var digits = [],
		coeffs = [2, 4, 8, 5, 10, 9, 7, 3, 6],
		days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];

	// validate egn length (10 digits)

	for (var i = 0; i < egn.length; i++) {
		var digit = parseInt(egn.charAt(i), 10);

		if (isNaN(digit)) {
			break;
		}

		digits[i] = digit;
	}

	if (digits.length != 10) {
		return Egn.BadLength;
	}

	// validate egn month

	var dd = digits[4] * 10 + digits[5],
		mm = digits[2] * 10 + digits[3],
		yy = digits[0] * 10 + digits[1],
		yyyy = null;

	if (mm >= 1 && mm <= 12) {
		yyyy = 1900 + yy;
	} else if (mm >= 21 && mm <= 32) {
		mm -= 20;
		yyyy = 1800 + yy;
	} else if (mm >= 41 && mm <= 52) {
		mm -= 40;
		yyyy = 2000 + yy;
	} else {
		return Egn.BadMonth;
	}

	// validate egn day

	days[1] += isLeapYear(yyyy) ? 1 : 0;

	if (dd < 1 || dd > days[mm - 1]) {
		return Egn.BadDay;
	}

	// Gregorian calendar adoption. 31 Mar 1916 was followed by 14 Apr 1916.
	if (yyyy == 1916 && mm == 4 && (dd >= 1 && dd < 14)) {
		return Egn.BadGregory;
	}

	// validate egn checksum

	var checksum = 0;

	for (var i = 0; i < coeffs.length; i++) {
		checksum += digits[i] * coeffs[i];
	}

	checksum %= 11;

	if (10 == checksum) {
		checksum = 0;
	}

	if (digits[9] != checksum) {
		return Egn.BadChecksum;
	}

	// egn is ok

	return Egn.Ok;
}

// tab group class - internal sections and links to them
// are grouped to form property sheet like interface

function TabGroup(id, linkElement, hx) {

	// internals

	var _tabscontainer = null,
		_tabs = null,
		_active = null,
		_hx = hx;

	function getPageId(href) {
		return href.substr(href.indexOf("#") + 1);
	}

	function initTab(a, group, index) {
		a.group = group;
		a.index = index;
		a.page = document.getElementById(getPageId(a.href));
		a.onclick = function () {
			this.group.activatePage(this.index);
			this.blur();
			return false;
		};
	}

	function hidePage(tab) {
		tab.page.style.display = "none";
		tab.className = "";
	}

	function showPage(tab) {
		tab.page.style.display = "";
		tab.className = "Current";
	}

	function hideHeadings(tab) {
		var hs = tab.page.getElementsByTagName(_hx);

		for (var i = 0; i < hs.length; i++) {
			var h = hs[i];

			h.style.display = "none";
		}
	}

	function showHeadings(tab) {
		var hs = tab.page.getElementsByTagName(_hx);

		for (var i = 0; i < hs.length; i++) {
			var h = hs[i];

			h.style.display = "";
		}
	}

	// interface

	this.activatePage = function (index) {
		var tab = _tabs[index];

		if (_active) { hidePage(_active); }
		showPage(tab);
		_active = tab;
	};

	// construction

	_tabscontainer = document.getElementById(id);
	_tabs = _tabscontainer.getElementsByTagName(linkElement);

	for (var i = 0; i < _tabs.length; i++) {
		var tab = _tabs[i];

		initTab(tab, this, i);
		if (_hx) { hideHeadings(tab); }
		hidePage(tab);
	}
}

// egn checker class - checks egn for correctness and
// shows detailed error information

function EgnChecker() {

	// internals

	var _controls = document.getElementById("egncheckercontrols"),
		_text = document.getElementById("egncheckertext"),
		_check = document.getElementById("egncheckercheck"),
		_reset = document.getElementById("egncheckerreset"),
		_result = document.getElementById("egncheckerresult");

	function clear() {
		_text.value = "";
		_result.value = "";
		_result.className = "";
	}

	function writeResultOk(msg) {
		_result.value = msg;
		_result.className = "EgnCheckerResultOk";
	}

	function writeResultError(msg) {
		_result.value = msg;
		_result.className = "EgnCheckerResultError";
	}

	// interface

	// construction

	_check.onclick = function () {
		switch (checkEgn(_text.value)) {
			case Egn.BadLength:
				writeResultError("Моля, въведете 10 ЦИФРИ.");
				break;
			case Egn.BadMonth:
				writeResultError("Некоректен месец. Позиции 3 и 4.");
				break;
			case Egn.BadDay:
				writeResultError("Некоректен ден. Позиции 5 и 6.");
				break;
			case Egn.BadChecksum:
				writeResultError("Грешна контролна цифра на въведеният ЕГН. Позиция 10.");
				break;
			case Egn.BadGregory:
				writeResultError("Грешна дата (от 01.04.1916 г. до 13.04.1916 г. - Григориански календар).");
				break;
			default:
				writeResultOk("Въведеният ЕГН е верен.");
		}

		_text.focus();
	};

	_reset.onclick = function () { clear(); };

	clear();
}

// class to enhance egn search form

function EgnSearchForm() {
	//private
	var _form = document.getElementById("frm"),
		_egn = document.getElementById("egn"),
			_egnerrDigits = document.getElementById("egnli"),
			_egnerrMonth = document.getElementById("month"),
			_egnerrDay = document.getElementById("day"),
			_egnerrChecksum = document.getElementById("count"),
			_egnerrAge = document.getElementById("noage"),
			_egnerrInvalid = document.getElementById("InvalidEgn"),
		_fname = document.getElementById("fname"),
			_fnameerrMissing = document.getElementById("imes"),
			_fnameerrLength = document.getElementById("imeslen"),
			_fnameerrCyrillic = document.getElementById("checkfname"),
		_secode = document.getElementById("secode"),
			_secodeerrInvalid = document.getElementById("InvalidCode"),
			_secodeerrMissing = document.getElementById("secodemissing"),
		_submit = document.getElementById("submit"),
		_reset = document.getElementById("reset");

	function hideErrors() {
		hide(_egnerrDigits);
		hide(_egnerrMonth);
		hide(_egnerrDay);
		hide(_egnerrChecksum);
		hide(_egnerrAge);
		hide(_egnerrInvalid);

		hide(_fnameerrMissing);
		hide(_fnameerrLength);
		hide(_fnameerrCyrillic);

		hide(_secodeerrInvalid);
		hide(_secodeerrMissing);
	}

	function validateEgn() {
		switch (checkEgn(_egn.value)) {
			case Egn.BadLength:
				show(_egnerrDigits);
				return false;
			case Egn.BadMonth:
				show(_egnerrMonth);
				return false;
			case Egn.BadDay:
				show(_egnerrDay);
				return false;
			case Egn.BadChecksum:
				show(_egnerrChecksum);
				return false;
			default:
				var test = getEgnYear(_egn.value) + _egn.value.substring(2);

				if (config.edge < test) {
					show(_egnerrAge);
					return false;
				}
		}

		return true;
	}

	function validateFname() {
		var characters = [];

		for (var i = 0; i < _fname.value.length; i++) {
			var character = _fname.value.charAt(i).toUpperCase();
			if ((character < "А" || character > "Я") && (character != '\'' && character != '-' && character != ' ')) { break; }
			characters[i] = character;
		}

		if (_fname.value.length != characters.length) { show(_fnameerrCyrillic); return false; }
		if (3 > characters.length) { show(_fnameerrLength); return false; }

		return true;
	}

	function validateSecode() {
		//var digits = [];

		//for (var i = 0; i < _secode.value.length; i++) {
		//	var digit = parseInt(_secode.value.charAt(i), 10);

		//	if (isNaN(digit)) { break; }
		//	digits[i] = digit;
		//}

		//if (5 != digits.length) { show(_secodeerrMissing); return false; }

		if (_secode.value.length == 0) { show(_secodeerrMissing); return false; }

		return true;
	}

	//public

	//construction
	_form.onsubmit = function () {
		var errors = 0;
		hideErrors();
		if (!validateEgn()) { if (0 == errors) { _egn.focus(); } errors++; }
		if (!validateFname()) { if (0 == errors) { _fname.focus(); } errors++; }
		if (!validateSecode()) { if (0 == errors) { _secode.focus(); } errors++; }
		return (0 == errors) ? true : false;
	};

	_form.onreset = function () {
		return false;
	};

	_submit.onclick = function () {
		return true;
	};

	_reset.onclick = function () {
		hideErrors();
		_egn.value = "";
		_fname.value = "";
		_secode.value = "";
		_egn.focus();
	};

	_egn.focus();
}

// class to enhance egn search form (limited access)

function EgnSearchFormWork() {
	//private
	var _form = document.getElementById("frm"),
		_egn = document.getElementById("egn"),
			_egnerrDigits = document.getElementById("egnli"),
			_egnerrMonth = document.getElementById("month"),
			_egnerrDay = document.getElementById("day"),
			_egnerrChecksum = document.getElementById("count"),
			_egnerrAge = document.getElementById("noage"),
			_egnerrVoterInfo = document.getElementById("voterinfo"),
		_submit = document.getElementById("submit"),
		_reset = document.getElementById("reset");

	function hideErrors() {
		hide(_egnerrDigits);
		hide(_egnerrMonth);
		hide(_egnerrDay);
		hide(_egnerrChecksum);
		hide(_egnerrAge);
		hide(_egnerrVoterInfo);
	}

	function validateEgn() {
		switch (checkEgn(_egn.value)) {
			case Egn.BadLength:
				show(_egnerrDigits);
				return false;
			case Egn.BadMonth:
				show(_egnerrMonth);
				return false;
			case Egn.BadDay:
				show(_egnerrDay);
				return false;
			case Egn.BadChecksum:
				show(_egnerrChecksum);
				return false;
			default:
				var test = getEgnYear(_egn.value) + _egn.value.substring(2);

				if (config.edge < test) {
					show(_egnerrAge);
					return false;
				}
		}

		return true;
	}

	//public

	//construction
	_form.onsubmit = function () {
		var errors = 0;
		hideErrors();
		if (!validateEgn()) { if (0 == errors) { _egn.focus(); } errors++; }
		return (0 == errors) ? true : false;
	};

	_form.onreset = function () {
		return false;
	};

	_submit.onclick = function () {
		return true;
	};

	_reset.onclick = function () {
		hideErrors();
		_egn.value = "";
		_egn.focus();
	};

	_egn.focus();
}

// classes to enhance address search forms

function NewCAddrForm() {
	//private
	var _form = document.getElementById("certForm"),
		_addrdate = document.getElementById("addrdate"),
			_dateerrLength = document.getElementById("datelen"),
			_dateerrInvalid = document.getElementById("invaliddate"),
			_dateerrFuture = document.getElementById("futuredate"),
			_dateerrPast = document.getElementById("pastdate"),
		_submit = document.getElementById("lnkconfirm"),
		_msgconfirm = document.getElementById("msgconfirm");

	function hideErrors() {
		hide(_dateerrLength);
		hide(_dateerrInvalid);
		hide(_dateerrFuture);
		hide(_dateerrPast);
	}

	function checkAddrDate() {
		if (_addrdate.value.length != 8 || isNaN(_addrdate.value)) { show(_dateerrLength); return false; }

		var days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
			yyyy = 1 * _addrdate.value.substr(0, 4),
			mm = 1 * _addrdate.value.substr(4, 2),
			dd = 1 * _addrdate.value.substr(6, 2);

		days[1] += isLeapYear(yyyy) ? 1 : 0;

		if (!(dd >= 1 && dd <= days[mm - 1])) { show(_dateerrInvalid); return false; }

		return true;
	}

	function validate() {
		var errors = 0;
		hideErrors();
		if (!checkAddrDate()) { if (0 == errors) { _addrdate.focus(); } errors++; }
		var msg = new String(_msgconfirm.innerHTML);
		msg = msg.replace(/\n/g, ''); // assume no markup
		if (0 == errors && !confirm(msg.replace(/\$/g, '\n'))) { _addrdate.focus(); errors++; }
		return (0 == errors);
	}

	//public

	//construction
	_form.onsubmit = function () {
		return validate();
	};

	_form.onreset = function () {
		hideErrors();
		_addrdate.value = "";
		_addrdate.focus();
		return false;
	};

	_submit.onclick = function () {
		if (validate()) { _form.submit(); }
		return false;
	};

	_addrdate.focus();
}

function VotingCertForm(doReg) {
	//private
	var _form = document.getElementById("certForm"),
		_certnum = document.getElementById("certnumber"),
	    _numerrLength = document.getElementById("numberlen"),
	    _numerrInvalid = document.getElementById("numberinvalid"),
		_certdate = document.getElementById("certdate"),
			_dateerrLength = document.getElementById("datelen"),
			_dateerrInvalid = document.getElementById("invaliddate"),
			_dateerrFuture = document.getElementById("futuredate"),
			_dateerrPast = document.getElementById("pastdate"),
		_submit = document.getElementById("register"),
		_msgconfirm = document.getElementById("msgconfirm")
	;

	function hideErrors() {
		hide(_numerrLength);
		hide(_numerrInvalid);
		hide(_dateerrLength);
		hide(_dateerrInvalid);
		hide(_dateerrFuture);
		hide(_dateerrPast);
	}

	function checkCertNum() {
		if (_certnum.value.length == 0) {
			show(_numerrLength);
			return false;
		}

		if (isNaN(_certnum.value)
			|| parseInt(_certnum.value, 10) < 1
			|| parseInt(_certnum.value, 10) > 999999
		) {
			show(_numerrInvalid);
			return false;
		}

		return true;
	}

	function checkCertDate() {
		var 
			parts = _certdate.value.split('.'),
			day = parts[0],
			month = parts[1],
			year = parts[2],
			test = new Date(year, month - 1, day)
		;

		if (
			test.getDate() != day || 
			test.getMonth() != month - 1 || 
			test.getFullYear() != year
		) {
			show(_dateerrInvalid);
			
			return false;
		}

		if (test < new Date(2011, 0, 1)) {
			show(_dateerrPast);

			return false;
		}

		if (test > new Date()) {
			show(_dateerrFuture);

			return false;
		}
		
		return true;
	}

	function validate() {
		var errors = 0;
		hideErrors();
		if (!checkCertNum()) {
			if (0 == errors) {
				_certnum.focus();
			}
			errors++;
		}
		if (!checkCertDate()) {
			if (0 == errors) {
				_certdate.focus();
			}
			errors++;
		}
		var msg = new String(_msgconfirm.innerHTML);
		msg = msg.replace(/\n/g, ''); // assume no markup
		if (0 == errors && !confirm(msg.replace(/\$/g, '\n'))) {
			_certnum.focus();
			errors++;
		}
		return (0 == errors);
	}

	//public

	//construction
	//_form.onsubmit = function () {
	//	return validate();
	//};

	_form.onreset = function () {
		hideErrors();
		_certnum.value = "";
		_certdate.value = "";
		_certnum.focus();
		return false;
	};

	_submit.onclick = function () {
		if (validate()) {
			//_form.submit();
			doReg();
		}
		return false;
	};

	this.clearErrors = function () {
		hideErrors();
	};

	hideErrors();

	_certnum.focus();
}

var
	VK_TAB = 9,
	VK_ENTER = 13,
	VK_ESCAPE = 27,
	VK_UP = 38,
	VK_DOWN = 40,
	
	// keys to ignore
	VK_SHIFT = 16,
	VK_CTRL = 17,
	VK_ALT = 18,
	VK_CAPSLOCK = 20,
	VK_HOME = 36,
	VK_LEFTARROW = 37,
	VK_INSERT = 45
;

function AutoComplete(
	inputId, loadingId, acId, hiddenId,
	acUrl, paramId,
	textKey, valueKey,
	onValueChanged
) {
	var
		j = jQuery,
		jinput = j('#' + inputId),
		jloading = j('#' + loadingId),
		jac = j('#' + acId),
		jhidden = j('#' + hiddenId),
		jparam = j('#' + paramId)
	;

	function getInputText() {
		return jinput.val();
	}

	function setInputText(text) {
		jinput.val(text);
	}

	jinput.data('value', '');

	function getInputValue() {
		return jinput.data('value');
	}

	function setInputValue(value) {
		jinput.data('value', value);
		jhidden.val(value);

		if (onValueChanged) {
			onValueChanged(value);
		}
	}

	function clearInput() {
		setInputText('');
		setInputValue('');
	}

	function markInputError() {
		jinput.addClass('Error');
	}

	function markInputOk() {
		jinput.removeClass('Error');
	}

	function getSearchString() {
		var text = getInputText();

		return (
			text.toUpperCase().
				substring(text.indexOf('.') + 1). // strip leading xxx.
				replace(/^\s+/, ''). // strip leading whitespace
				replace(/\s+$/, ''). // strip trailing whitespace
				replace('"', '') // remove quotation marks
		);
	}

	function isACNavKey(code) {
		return (
			code == VK_TAB ||
			code == VK_ENTER ||
			code == VK_ESCAPE ||
			code == VK_UP ||
			code == VK_DOWN ||
		
			code == VK_SHIFT ||
			code == VK_CTRL ||
			code == VK_ALT ||
			code == VK_CAPSLOCK ||
			code == VK_HOME ||
			code == VK_LEFTARROW ||
			code == VK_INSERT
		);
	}

	jinput.keydown(function (e) {
		var current = getACCurrentItem();

		if ( !(isACNavKey(e.keyCode) && current) ) {
			return true;
		}

		switch (e.keyCode) {
		case VK_TAB:
			hideAC();
			
			break; // allow field change
		case VK_ENTER:
			finishAC(current);
			
			return false; // prevent form submit
		case VK_ESCAPE:
			hideAC();

			return false; // prevent input clear
		case VK_UP:
			setACCurrentItem(getACPrevItem(current));

			break;
		case VK_DOWN:
			setACCurrentItem(getACNextItem(current));

			break;
		}

		return true;
	});

	jinput.keyup(function (e) {
		if (isACNavKey(e.keyCode)) {
			return true;
		}

		var search = getSearchString();

		if (search.length < 3) {
			setInputValue('');
			markInputOk();
			clearAC(); // TODO: clear only if search string actually changed
		} else if (search.length == 3) {
			showLoading();
			setInputValue('');

			if (search.indexOf('<') != -1 || search.indexOf('>') != -1) {
				hideLoading();
				markInputError();
				clearAC();
			} else {
				j.ajax(acUrl + '/' + getParamValue() + '/' + encodeURIComponent(search), {
					async: true,
					dataType: 'json',
					success: function (json) {
						hideLoading();

						if (json.length == 0) {
							markInputError();
							clearAC();
						} else {
							markInputOk();
							loadAC(json);

							doAC();
						}
					},
					error: function (jxhr, status, error) {
						hideLoading();
						markInputError();
						clearAC();
					}
				});
			}
		} else {
			doAC();
		}
	});

	function showLoading() {
		jloading.css({visibility: 'visible'});
	}

	function hideLoading() {
		jloading.css({visibility: 'hidden'});
	}

	jac.data('current', null);

	function showAC() {
		var first = jac.children().first();

		while (true) {
			if (first.css('display') == 'block') {
				break;
			}

			first = jac.children().eq(getACItemNextIndex(first));
		}

		setACCurrentItem(first);
		
		jac.css({display: 'none'}); // looks bad otherwise
		jac.css({display: 'block'});
	}

	function hideAC() {
		clearACCurrentItem();
		jac.css({display: 'none'});
	}

	function clearAC() {
		hideAC();
		jac.empty();
	}

	function loadAC(json) {
		clearAC();

		j.each(json, function (i, v) {
			var aciid = jac.attr('id') + '_' + i;

			jac.append('<div class="AutoCompleteItem" id=\"' + aciid + '\">' + v[textKey] + '</div>');

			j('#' + aciid).
				data('value', v[valueKey]).
				data('index', i).

				hover(function () {
					setACCurrentItem(j(this));
				}, function () {
					//clearACCurrentItem();
				}).

				click(function () {
					finishAC(j(this));
				});
		});
	}

	function doAC() {
		var
			search = getSearchString(),
			matches = 0,
			lastMatch = null
		;

		j.each(jac.children(), function (i, child) {
			var
				jchild = j(child),
				text = getACItemText(jchild),
				value = getACItemValue(jchild)
			;

			// matches
			if (text.indexOf(search) != -1) {
				matches += 1;
				lastMatch = jchild;
				jchild.css({display: 'block'});
			// doesn't match
			} else {
				jchild.css({display: 'none'});
			}

			// last child
			if (getACItemCount() - 1 == i) {
				if (0 == matches) {
					setInputValue('');
					markInputError();
					hideAC();
				} else if (1 == matches) {
					markInputOk();
					
					if (getInputValue().length == 0) {
						finishAC(lastMatch);
					} else {
						showAC();
					}
				} else {
					markInputOk();
					showAC();
				}
			}
		});
	}

	function finishAC(item) {
		setInputText(getACItemText(item));
		setInputValue(getACItemValue(item));
		hideAC();
	}

	function getACItemCount() {
		return jac.children().length;
	}

	function getACCurrentItem() {
		return jac.data('current');
	}

	function setACCurrentItem(item) {
		var current = getACCurrentItem();

		if (current) {
			current.removeClass('AutoCompleteItemHover');
		}

		item.addClass('AutoCompleteItemHover');
		jac.data('current', item);
	}

	function clearACCurrentItem() {
		var current = getACCurrentItem();

		if (current) {
			current.removeClass('AutoCompleteItemHover');
		}

		jac.data('current', null);
	}

	function getACNextItem(item) {
		var next = jac.children().eq(getACItemNextIndex(item));

		while (true) {
			if (next.css('display') == 'block') {
				return next;
			}

			next = jac.children().eq(getACItemNextIndex(next));
		}
	}

	function getACPrevItem(item) {
		var prev = jac.children().eq(getACItemPrevIndex(item));

		while (true) {
			if (prev.css('display') == 'block') {
				return prev;
			}

			prev = jac.children().eq(getACItemPrevIndex(prev));
		}
	}

	function getACItemText(item) {
		return item.html();
	}

	function getACItemValue(item) {
		return item.data('value');
	}

	function getACItemIndex(item) {
		return item.data('index');
	}

	function getACItemNextIndex(item) {
		var
			i = getACItemIndex(item),
			count = getACItemCount()
		;

		return (i < count - 1) ? i + 1 : 0;
	}

	function getACItemPrevIndex(item) {
		var
			i = getACItemIndex(item),
			count = getACItemCount()
		;

		return (i > 0) ? i - 1 : count - 1;
	}

	function getParamValue() {
		return jparam.data('value');
	}

	this.getInput = function () {
		return jinput;
	};

	this.clear = function () {
		clearInput();
		clearAC();
	};

	j('html').click(function () {
		hideAC();
			
		return true;
	});
}

