/*
http://0xAF.org - js routines [requires jQuery]

vim: set syntax=jquery ts=4 sw=4 ss=4 ff=unix fdm=marker :

License: MIT (http://en.wikipedia.org/wiki/MIT_License)

Copyright (c) 2010 Stanislav Lechev [AngelFire]

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/


var _0xAF_org = "http://0xAF.org/";

var fade_it = false;

var RPC_LOCATION = "rpc/json.pl";
var COOKIE_DOMAIN = /(\w+\.\w+)$/.exec(window.location.hostname);
if (typeof(COOKIE_DOMAIN) == 'object' && COOKIE_DOMAIN!=null) {
	COOKIE_DOMAIN = "."+COOKIE_DOMAIN[1];
}


var srpc;
var rpc_problem = false;
var rpc_retries = 0;
var Debug = {};
var div_debug = false;
var user = new Object;

// emulate dev console if such is missing.
if (typeof(console) == 'undefined') {//{{{
	console = {};
	console.log = function(msg) {
		return false;
	};
	console.dir = function(msg) {
		return false;
	};
}//}}}


// create Debug
Debug.log = function (text) {//{{{
	console.log(text);
	if (!div_debug) return;
	div_debug.html(div_debug.html() + "<p>" + text + "</p>");
	div_debug.scrollTop(div_debug[0].scrollHeight);
}

Debug.dir = function (text) {
	console.dir(text);
	if (!div_debug) return;
	div_debug.html(div_debug.html() + "<p>" + text + "</p>");
	div_debug.scrollTop(div_debug[0].scrollHeight);
}

Debug.toggle = function () {
	if (!div_debug) return;
	div_debug.slideToggle('normal', function() {
		//Debug.log('console shown...');
		div_debug.animate({scrollTop: div_debug[0].scrollHeight});
		div_debug.attr({ scrollTop: div_debug.attr("scrollHeight") });
	});
}
//}}}


function server_problem(x)
{//{{{
	Debug.log("rpc server connection lost...");
	if (!x && rpc_retries < 3) {
		rpc_retries++;
		return 0;
	}
	$('#error-dialog').show();
	return 1;
}//}}}

// here comes the methods
// jQuery functions//{{{
(function($) {
	$.extend($.fn, {

	cookie: function(name, value, options) {//{{{
	/* for function arguments:
	* name		- String		= The name of the cookie.
	* value		- String		= The value of the cookie.
	* options	- Object		= An object literal containing key/value pairs to provide optional cookie attributes.
	*
	* for options object:
	* expires	- Number|Date	= Either an integer specifying the expiration date from now on in days or a Date object.
	*                             If a negative value is specified (e.g. a date in the past), the cookie will be deleted.
	*                             If set to null or omitted, the cookie will be a session cookie and will not be retained
	*                             when the the browser exits.
	* path		- String		= The value of the path atribute of the cookie (default: path of page that created the cookie).
	* domain	- String 		= The value of the domain attribute of the cookie
	*                             (default: domain of page that created the cookie).
	* secure	- Boolean 		= If true, the secure attribute of the cookie will be set and the cookie transmission
	*                             will require a secure protocol (like HTTPS).
	*/

		if (typeof value != 'undefined') { // name and value given, set cookie
			options = options || {};
			// AF: DOMAIN
			options.domain = COOKIE_DOMAIN;
			if (value === null) {
				value = '';
				options.expires = -1;
			}
			var expires = '';
			if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) {
				var date;
				if (typeof options.expires == 'number') {
					date = new Date();
					date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000));
				} else {
					date = options.expires;
				}
				expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE
			}
			var path = options.path ? '; path=' + (options.path) : '';
			var domain = options.domain ? '; domain=' + (options.domain) : '';
			var secure = options.secure ? '; secure' : '';
			document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join('');
		} else { // only name given, get cookie
			var cookieValue = null;
			if (document.cookie && document.cookie != '') {
				var cookies = document.cookie.split(';');
				for (var i = 0; i < cookies.length; i++) {
					var cookie = jQuery.trim(cookies[i]);
					// Does this cookie string begin with the name we want?
					if (cookie.substring(0, name.length + 1) == (name + '=')) {
						cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
						break;
					}
				}
			}
			return cookieValue;
		}
	},//}}}

		outerHTML: function(s) {//{{{
			return (s) ? this.before(s).remove() : $("<p>").append(this.eq(0).clone()).html();
		},//}}}

		addHoverAndClick: function() {//{{{
			return $(this).each(function() {
				$(this).hover(
					function(){
						$(this).data('animate', true);
						if (use_spectrum) {
							$(this).stop().spectrum();
						} else {
							$(this).stop().animate( {
									opacity: 1,
									backgroundColor: '#ff8030'
								}, 500, function() {
								}
							);
						}
					},
					function(){
						$(this).data('animate', false);
						$(this).stop().animate( {
							opacity: 0.65,
							backgroundColor: '#cccccc'
						}, 500, function() {
						}
						);
					}
				).click(function(){ $(this).makeOrder(); });
			});
		},//}}}

		af_load: function(url, cb) {//{{{
			return $(this).each(function() {
				$(this)
					.data('url', url)
					.fadeOut(500,'easeOutQuad', function(){
						$(this).load($(this).data('url'), function(){
							$(this).fadeIn(500,'easeInQuad');
							if (cb) {
								cb();
							}
						})
					});
			});
		},//}}}

		// remove
		listselect: function (options) {//{{{
			var defaults = {
				size: 5,
				listTitle: "All Contacts",
				selectedTitle: "Recipients",
				listClass: "ui-widget-content ui-corner-all",
				selectedClass: "ui-widget-content ui-corner-all"
			}

			var options = $.extend(defaults, options);

			return this.each(function () {
				var listContainer = $("<div style=\"margin-right: 5px; float: left; width: 200px;\"></div>");
				if (options.listTitle && options.listTitle != '')
					listContainer.append("<strong>" + options.listTitle + "</strong>");

				var selectedContainer = $("<div style=\"margin-right: 5px; float: left; width: 200px;\"></div>");
				if (options.selectedTitle && options.selectedTitle != '')
					selectedContainer.append("<strong>" + options.selectedTitle + "</strong>");

				var selected = $(this);
				selected.addClass(options.selectedClass);
				listContainer.insertAfter(selected);
				selectedContainer.insertBefore(listContainer);
				selected.remove();

				var hiddenFieldsContainer = $("<div style=\"clear: both;\"></div>");
				hiddenFieldsContainer.insertAfter(listContainer);

				var list = $("<select></select>");
				list.addClass(options.listClass);
				var selectedValues = null;
				if (selected.attr("selected")) {
					selectedValues = selected.attr("selected").split(",");
				}

				var fieldname = selected.attr('name');
				var fieldID = fieldname.replace("[]" , "");
				selected.attr('name', '');
				selected.attr('id', '');
				selected.css("width", "100%");
				list.css("width", "100%");

				list.html(selected.html());
				selected.html('');

				selected.attr('size', options.size);
				list.attr('size', options.size);

				listContainer.append(list);
				selectedContainer.append(selected);

				list.bind("click", function () {
					var option = $(this).find("option[value='" + $(this).val() + "']");
					if(option.length > 0){
						var hiddenObj = $("<input type=\"checkbox\" style=\"display: none\" checked=\"checked\" name=\"" + fieldname + "\" id=\"listselect_" + fieldID + "_" + $(this).val() + "\" value=\"" + $(this).val() + "\" />");

						option.remove();
						selected.append(option);
						hiddenFieldsContainer.append(hiddenObj);
						selected.val('');
						list.val('');
					}
				});

				selected.bind("click", function () {
					var option = $(this).find("option[value='" + $(this).val() + "']");
					if(option.length > 0){
						var hiddenObj = $("#listselect_" + fieldID + "_" + $(this).val());
						option.remove();
						list.append(option);
						hiddenObj.remove();
						selected.val('');
						list.val('');
					}
				});

				hiddenFieldsContainer.append($("<input type=\"checkbox\" style=\"display: none\" name=\"" + fieldname + "\">"));
				if (selectedValues != null && selectedValues.length > 0) {
					for (var i = 0; i < selectedValues.length; i++) {
						var option = list.find("option[value='" + selectedValues[i] + "']");
						if(option.length > 0) {
							var hiddenObj = $("<input type=\"checkbox\" style=\"display: none\" checked=\"checked\" name=\"" + fieldname + "\" id=\"listselect_" + fieldID + "_" + selectedValues[i] + "\" value=\"" + selectedValues[i] + "\" />");

							option.remove();
							selected.append(option);
							hiddenFieldsContainer.append(hiddenObj);
						}
					}
				}

				selected.val('');
				list.val('');
			});
		},//}}}

		populateOptions: function(a,zeroname,zeroval) {//{{{
			// call this on <select> element
			// a = hash like this { 1: 'option 1', 2: 'option 2' }
			// zeroname = the first option (eg. 'Please Select ...')
			// zeroval = the value for zeroname
			return $(this).each(function() {
				var s = $(this);
				s.empty();
				if (zeroname && zeroname.length) s.append($('<option value="'+zeroval+'">'+zeroname+'</option>'));
				for (var k in a) { $(s).append($('<option value="'+k+'">'+a[k]+'</option>')); }

			});

		},//}}}

		saveCheckbox: function() {//{{{
			var $this = $(this);
			if ($this.is(':checked')) {
				$(document).cookie($this.attr('id'), '1', {expires: 356});
			} else {
				$(document).cookie($this.attr('id'), null);
			}

		}//}}}

	});
})(jQuery);
//}}}

// user stuff
$.extend(user, {//{{{

	abUpdate: function(id,what,val) {//{{{
		if (!user.isLogged()) return;
		var data = { id: id, what: what, value: val };
		var tmp;
		try { tmp = srpc.ab_mod(data); } catch (e) { Debug.log('data:'); Debug.dir(data); Debug.log('res:'); Debug.dir(tmp); server_problem(1); return; };
		if ($(tmp) && $(tmp).length && tmp.success>0) {
			Debug.log('contact updated');
			user.refresh();
		} else {
			Debug.log("problem updating contact");
			Debug.dir(tmp);
		}

		return tmp.failure ? tmp.msg : '';

	},//}}}

	abRemove: function(id) {//{{{
		if (!user.isLogged()) return;
		var data = { id: id };
		var tmp;
		try { tmp = srpc.ab_del(data); } catch (e) { Debug.log('data:'); Debug.dir(data); Debug.log('res:'); Debug.dir(tmp); server_problem(1); return; };
		if ($(tmp) && $(tmp).length && tmp.success>0) {
			Debug.log('contact removed');
			user.refresh();
		} else {
			Debug.log("problem removing contact");
			Debug.dir(tmp);
		}

		return tmp.failure ? tmp.msg : '';

	},//}}}

	abAddNew: function(nn,np,ng) {//{{{
		if (!user.isLogged()) return;
		var data = { name: nn, phone: np, group: ng };
		var tmp;
		try { tmp = srpc.ab_add(data); } catch (e) { Debug.log('data:'); Debug.dir(data); Debug.log('res:'); Debug.dir(tmp); server_problem(1); return; };
		if ($(tmp) && $(tmp).length && tmp.success>0) {
			Debug.log('contact added');
			user.refresh();
		} else {
			Debug.log("problem adding new contact");
			Debug.dir(tmp);
		}

		return tmp.failure ? tmp.msg : '';

	},//}}}

	abGrpAdd: function(name) {//{{{
		if (!user.isLogged()) return;
		var data = { name: name };
		var tmp;
		try { tmp = srpc.ab_group_add(data); } catch (e) { Debug.log('data:'); Debug.dir(data); Debug.log('res:'); Debug.dir(tmp); server_problem(1); return; };
		if ($(tmp) && $(tmp).length && tmp.success>0) {
			Debug.log('grp added');
			user.refresh();
		} else {
			Debug.log("problem adding new group");
			Debug.dir(tmp);
		}

		return tmp.failure ? tmp.msg : '';

	},//}}}

	abGrpRen: function(id, name) {//{{{
		if (!user.isLogged()) return;
		var data = { id: id, name: name };
		var tmp;
		try { tmp = srpc.ab_group_ren(data); } catch (e) { Debug.log('data:'); Debug.dir(data); Debug.log('res:'); Debug.dir(tmp); server_problem(1); return; };
		if ($(tmp) && $(tmp).length && tmp.success>0) {
			Debug.log('grp renamed');
			user.refresh();
		} else {
			Debug.log("problem renaming new group");
			Debug.dir(tmp);
		}

		return tmp.failure ? tmp.msg : '';

	},//}}}

	abGrpDel: function(id) {//{{{
		if (!user.isLogged()) return;
		var data = { id: id };
		var tmp;
		try { tmp = srpc.ab_group_del(data); } catch (e) { Debug.log('data:'); Debug.dir(data); Debug.log('res:'); Debug.dir(tmp); server_problem(1); return; };
		if ($(tmp) && $(tmp).length && tmp.success>0) {
			Debug.log('grp removed');
			user.refresh();
		} else {
			Debug.log("problem removing group");
			Debug.dir(tmp);
		}

		return tmp.failure ? tmp.msg : '';

	},//}}}

	isLogged: function() {//{{{
		return user.data.logged_in > 0;
	},//}}}

	login: function() {//{{{
		var data = {
			email: $('#logindiv').find('#email').val(),
			pass: $.md5($('#logindiv').find('#pass').val())
		};

		$('#logindiv').find('#email').removeClass('ui-state-error');
		$('#logindiv').find('#pass').removeClass('ui-state-error');

		$('#logindiv>#msg').text('Validating Authenticity...');
		var res;
		try { res = srpc.login(data); } catch (e) { server_problem(1); return; };

		if (res && $(res).length && res.success>0) {
			Debug.log('logged in');
			$(document).cookie('email', $('#logindiv').find('#email').val(), {expires: 365});
			user.loginFormHide();
			user.refresh();
			return true;
		} else {
			Debug.log("login incorrect");
			$('#logindiv').find('#email').addClass('ui-state-error');
			$('#logindiv').find('#pass').addClass('ui-state-error');
			$('#logindiv>#msg').css({ color: 'red' }).text('Login Incorrect');
			$('#logindiv').find('#email').focus().select();
			return false;
		}
	},//}}}

	logout: function() {//{{{
		if (!user.isLogged()) return;
		var tmp;
		try { tmp = srpc.logout(); } catch (e) { server_problem(1); return; };
		if (tmp && $(tmp).length && tmp.success>0) {
			Debug.log('logged out');
		}
		$('#main').empty();
		user.refresh();
	},//}}}

	updateData: function() {//{{{
		$('#userbar').find('#username').text(user.data.first?user.data.first+" "+user.data.last:'Guest');
		if (user.isLogged()) {
			$('#inoutbtn').button({label: 'Sign Out'}).click(function(){ user.logout(); });
			$('#menu').show();
		} else {
			$('#inoutbtn').button({label: 'Sign In'}).click(function(){ user.loginFormShow(); });
			$('#menu').hide();
		}
		$('#userbar').animate({opacity: 1}, 200, function(){ });
	},//}}}

	refresh: function () {//{{{
		try { user.data = srpc.user_details(); } catch (e) { server_problem(1); return; };
		$('#userbar').animate({opacity: 0.01}, 200, function(){ user.updateData() });
	},//}}}

	loginFormShow: function () {//{{{
		if (user.isLogged()) return;
		$('html, body').animate({scrollTop:0}, 'slow');
		var email = $(document).cookie('email');

		$('#logindiv').dialog('open');
		$('#logindiv').find('#email').val(email?email:"email@address.com").focus().select();

		$('#logindiv').find('#msg').text('Please Sign In');
		$('#logindiv').find('#email').focus().select();
	},//}}}

	loginFormHide: function() {//{{{
		$('#logindiv').dialog('close');
	},//}}}

	validate: function(el,scope) {// scope should be the div combining all the elements {{{
		var msg = $(scope).find('#msg');
		if (!msg || !msg.length) {
			Debug.log("cannot find div with id 'msg'");
			return false;
		}

		var type = el.attr('rel').split('|');
		if (type[0] != 'validator') {
			Debug.log("nothing to validate");
			return false;
		}

		el.removeClass('error').removeClass('success');
		msg.removeClass('error').text("Моля попълнете формата");;

		if (0) {
		} else if (type[1] == "email") {
			if (! el.val().match(/^[a-z0-9._%+-]{2,}@[a-z0-9.-]{2,}\.[a-z]{2,4}$/i)) {//{{{
				msg.addClass('error').text("Въведете валиден E-Mail адрес");
				el.addClass('error');
				return false;
			}
			el.addClass('success');
			return true;//}}}
		} else if (type[1] == "password") {
			if (type[2] == el.attr('id')) { // this is the first pass field, check for length//{{{
				if (!el.val().match(/^[a-z0-9\._+-]{4,}$/i)) {
					msg.addClass('error').text("Използвайте минимум 4 букви, цифри, '.', '–', '+' и '_'");
					el.addClass('error');
					return false;
				}
				el.addClass('success');
				return true;
			} else if (type[3] == el.attr('id')) { // this is the second pass field, compare them
				if (el.val().length == 0 || el.val() != scope.find("#"+type[2]).val()) {
					msg.addClass('error').text("Паролата не съвпада");
					el.addClass('error');
					return false;
				}
				el.addClass('success');
				return true;
			}//}}}
		} else if (type[1] == "name") {
			if (! el.val().match(/^[абвгдежзийклмнопрстуфхцчшщъьюяАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЮЯ]{2,}$/)) {//{{{
				msg.addClass('error').text("Въведете 2 или повече символа за име на кирилица");
				el.addClass('error');
				return false;
			}
			el.addClass('success');
			return true;//}}}
		} else if (type[1] == "textnum") {
			if (! el.val().match(/^[0-9абвгдежзийклмнопрстуфхцчшщъьюяАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЮЯ ]+$/)) {//{{{
				msg.addClass('error').text("Въведете на кирилица");
				el.addClass('error');
				return false;
			}
			el.addClass('success');
			return true;//}}}
		} else if (type[1] == "text") {
			if (! el.val().match(/^[абвгдежзийклмнопрстуфхцчшщъьюяАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЮЯ ]+$/)) {//{{{
				msg.addClass('error').text("Въведете на кирилица");
				el.addClass('error');
				return false;
			}
			el.addClass('success');
			return true;//}}}
		} else if (type[1] == "adres") {
			if (! el.val().match(/^[абвгдежзийклмнопрстуфхцчшщъьюяАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЮЯ \.,0-9\-\"]{2,}$/)) {//{{{
				msg.addClass('error').text("Въведете 2 или повече символа на кирилица");
				el.addClass('error');
				return false;
			}
			el.addClass('success');
			return true;//}}}
		} else if (type[1] == "egn") {
			if (!user.checkEGN(el.val())) {//{{{
				msg.addClass('error').text("Въведете истински ЕГН ");
				el.addClass('error');
				return false;
			}
			el.addClass('success');
			return true;//}}}
		} else if (type[1] == "phone") {
			if (!el.val().match(/^[\d -\/\(\)]{8,}$/)) {//{{{
				msg.addClass('error').text("Въведете истински телефон ");
				el.addClass('error');
				return false;
			}
			el.addClass('success');
			return true;//}}}
		} else if (type[1] == "date") {
			if (! el.val().match(/^[0-3][0-9]\.[0-1][0-9]\.[1-2][019][8901][0-9]$/)) { // {{{
				msg.addClass('error').text("Въведете дата с формат ДД.ММ.ГГГГ ");
				el.addClass('error');
				return false;
			}
			el.addClass('success');
			return true;//}}}
		} else if (type[1] == "ltextnum") {
			if (! el.val().match(/^[a-zA-Z0-9]+$/i)) {//{{{
				msg.addClass('error').text("Въведете цифри или букви на латиница");
				el.addClass('error');
				return false;
			}
			if (type[2] && parseInt(type[2],10) > 0) {
				if (el.val().length < parseInt(type[2],10)) {
					msg.addClass('error').text("Въведете минимум "+parseInt(type[2],10)+" цифри или букви на латиница");
					el.addClass('error');
					return false;
				}
			}
			el.addClass('success');
			return true;//}}}
		} else if (type[1] == "num") {
			if (!type[2].match(/^\d+$/) || !type[3].match(/^\d+$/) || !type[4].match(/^\d+$/)) { // {{{
				Debug.log("validator|num|MIN|MAX|MLEN - wrong min, max or maxlength");
				return false;
			}
			var min = parseInt(type[2],10);
			var max = parseInt(type[3],10);
			var maxlength = parseInt(type[4],10);

			if (!el.val().match(/^\d+$/)) {
				msg.addClass('error').text("Въведете число");
				el.addClass('error');
				return false;
			}
			var val = parseInt(el.val(),10);
			if (el.val().length < maxlength) {
				msg.addClass('error').text("Въведете минимум "+maxlength+" цифри");
				el.addClass('error');
				return false;
			}
			if (val < min || val > max) {
				msg.addClass('error').text("Въведете число от "+min+" до "+max);
				el.addClass('error');
				return false;
			}
			el.addClass('success');
			return true;//}}}
		} else if (type[1] == "none") {
			return true;
		}

		Debug.log("unknown validator ["+type[1]+"] requested on ["+el.attr('id')+"]");
		return false;

	},//}}}

	init: function() {//{{{
		$('#inoutbtn').button({label: 'Sign In'}).click(function(){ user.loginFormShow(); });
		$('#logindiv').dialog({
			bgiframe: true,
			autoOpen: false,
			height: 300,
			width: 300,
			modal: false,
			closeOnEscape: false,
			open: function(event, ui) { $(".ui-dialog-titlebar-close").hide(); },
			buttons: {
				Login: function() {
					user.login();
				},
				Cancel: function() {
					$(this).dialog('close');
				}
			}
		});

		$('#logindiv').keyup(function(e){if(e.keyCode==27){ user.loginFormHide(); }});
		$('#logindiv').find('#email').keyup(function(e){if(e.keyCode==13){ $('#logindiv').find('#pass').focus().select(); }});
		$('#logindiv').find('#pass').keyup(function(e){if(e.keyCode==13){ user.login(); }});

		user.refresh();
	}//}}}

});//}}}

function engine_start()
{//{{{
	Debug.log("0xAF.org framework.");

	// init rpc
	try {//{{{
		srpc = new rpc.ServiceProxy(RPC_LOCATION, {
			asynchronous: false,  //default: true
			sanitize: true,       //default: true
			methods: null,        //default: null (synchronous introspection populates)
			protocol: 'JSON-RPC' //default: JSON-RPC
		});
	} catch(e) {
		rpc_problem = true;
		Debug.log("RPC client problem: ");
		Debug.log(e);
	}

	// make another try
	if (rpc_problem)
		try {
			srpc = new rpc.ServiceProxy(RPC_LOCATION, {
				asynchronous: false,  //default: true
				sanitize: true,       //default: true
				methods: null,        //default: null (synchronous introspection populates)
				protocol: 'JSON-RPC' //default: JSON-RPC
			});
			rpc_problem = false;
		} catch(e) {
			rpc_problem = true;
			alert(STRING_CAN_NOT_INITIALIZE_RPC);
			Debug.log("RPC client problem: ");
			Debug.log(e);
		}
//}}}

	// That's similiar to what's usually "main()"
	$(document).ready(function() {

		//console.dir(srpc); // XXX: debug

		if ($("#debug").length) {
			div_debug = $("#debug");
		}

		$('#error-dialog').hide();

		if (rpc_problem) {
			server_problem(1);
			return;
		}

		$(window).keyup(function(pEvent) {
			switch(pEvent.keyCode) {
				case 192: // `
					if (pEvent.altKey) Debug.toggle();
					break;
				default:
					//Debug.log('Key #'+ pEvent.keyCode +' was pressed.');
			}
		});

		user.init();

		if (! user.isLogged() ) {
			user.loginFormShow();
		}

		// attach menu links
		$('#menu_sendsms').click(function(e){ $('#main').af_load('?plain=sms', function(){ sms_show(); }); e.preventDefault(); return false; });
		$('#menu_addressbook').click(function(e){ $('#main').af_load('?plain=addressbook', function(){ addressbook_show(); }); e.preventDefault(); return false; });

		Debug.log("ready.");

	});

}//}}}

/* apTextCounter {{{ */

/*
* jQuery.apTextCounter - Textbox/textarea counter tool.
*
* http://www.blog.adampresley.com
*
* This file is part of jQuery.apTextCounter
*
* jQuery.apTextCounter is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* jQuery.apTextCounter is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with jQuery.apTextCounter.  If not, see <http://www.gnu.org/licenses/>.
*
* Callbacks:
* 	- onCharacterCountChecked
* 	- onMaxCharactersReached
* 	- onTrackerUpdated
*
* @author Adam Presley
* @copyright Copyright (c) 2009 Adam Presley
* @param {Object} config
*/
jQuery.fn.apTextCounter = function(config)
{
	function __checkCount(el, e, __c) {
		var count = __c.maxCharacters - $(el).val().length;
		var countDisplay = (__c.direction !== "down") ? (__c.maxCharacters - count) : count;

		if (count <= 0) {
			var k = e.which;
			if ((k > 47 && k < 91) || (k > 95 && k < 112) || (k > 184 && k < 250) || k == 13 || k == 32) {
				e.preventDefault();
				e.stopPropagation();
				/* Fire any callbacks.  */
				if (__c.onMaxCharactersReached !== null) {
					if (__c.scope !== null) {
						__c.onMaxCharactersReached.call(__c.scope, {
							count: countDisplay,
							config: __c
						});
					} else {
						__c.onMaxCharactersReached({
							count: countDisplay,
							config: __c
						});
					}
				}
				return countDisplay;
			}
		}
		/* Fire any callbacks.  */
		if (__c.onCharacterCountChecked !== null) {
			if (__c.scope !== null) {
				__c.onCharacterCountChecked.call(__c.scope, {
					count: countDisplay,
					config: __c
				});
			} else {
				__c.onCharacterCountChecked({
					count: countDisplay,
					config: __c
				});
			}
		}
		return countDisplay;
	}

	function __updateTracker(el, count, __c) {
		var msg = __c.trackerTemplate.replace(/%s/i, count);
		$(__c.tracker).html(msg);

		/* Fire any callbacks.  */
		if (__c.onTrackerUpdated !== null) {
			if (__c.scope !== null) {
				__c.onTrackerUpdated.call(__c.scope, {
					count: count,
					config: __c
				});
			} else {
				__c.onTrackerUpdated({
					count: count,
					config: __c
				});
			}
		}
	}

	return this.each(function() {
		var __this = this;

		/* Store our configuration. */
		this.__c = jQuery.extend({
			maxCharacters: 100,
			direction: "down",
			tracker: "#tracker",
			trackerTemplate: "%s",
			scope: null,
			onCharacterCountChecked: null,
			onMaxCharactersReached: null,
			onTrackerUpdated: null
		}, config);

		/* Perform an initial check and setup the tracker.  */
		__checkCount(this, null, this.__c);
		__updateTracker(this, (this.__c.direction === "down") ? this.__c.maxCharacters : 0, this.__c);

		/* Assign the keydown and keyup handlers.  */
		$(this).keyup(function(e) {
			var count = __checkCount(__this, e, __this.__c);
			__updateTracker(__this, count, __this.__c);
		});

		$(this).keydown(function(e) {
			var count = __checkCount(__this, e, __this.__c);
			__updateTracker(__this, count, __this.__c);
		});
	});
};

/* }}} */

