/* ГАДЖЕТ ЗАПИСНОЙ КНИЖКИ  */
function __Addressbook(id)
{
	this.lang = Locale.Gadgets.Addressbook;
	this.Core = new __StdModuleCore(this, id, 'addressbook', this.lang.title, this.lang.desc);
	
	
	this.exportSources = {'outlookExpress': 'MS OutlookExpress (csv)',
										'firebird': 'Mozzilla Firebird (csv)'
										};
	this.langs = {RU: 'Русский', EN: 'English', DE : 'Deutsch', FR: 'Français'}
	
	this.controls = {};
	
	if(!isEmpty(SProfile.user) && SProfile.user.id)
	{	//пользователь авторизован

	//	this.contactGroups = {work: this.lang.contactGroups.work, friends: this.lang.contactGroups.friends, sidekicks: this.lang.contactGroups.sidekicks, family: this.lang.contactGroups.family};
		this.types = {
			phones: {'mobile': this.lang.types.phones.mobile, 'home': this.lang.types.phones.home, 'work': this.lang.types.phones.work, 'fax': this.lang.types.phones.fax, 'other': this.lang.types.phones.other},
			emails: {'private': this.lang.types.emails.private, 'work': this.lang.types.emails.work, 'other': this.lang.types.emails.other},
			webpagers: {'icq': this.lang.types.webpagers.icq, 'msn': this.lang.types.webpagers.msn, 'yahoo': this.lang.types.webpagers.yahoo, 'aol': this.lang.types.webpagers.aol, 'jabber': this.lang.types.webpagers.jabber, 'mailagent': this.lang.types.webpagers.mailagent, 'skype': this.lang.types.webpagers.skype, 'other': this.lang.types.webpagers.other},
			ownfieldsG: null
		}
		this.phoneLiketypes = {phones: this.lang.phoneLiketypes.phones, emails: this.lang.phoneLiketypes.emails, webpagers: this.lang.phoneLiketypes.webpagers, annivs: this.lang.phoneLiketypes.annivs, ownfields: this.lang.phoneLiketypes.ownfields};
	
		this.ownfieldsGlobal = {};
		this.keywordMinLength = 2;
		this.formContactEdit = {};
		this.dbLite = {};
		this.finput = {};
		this.fpanel = {};
		this.timers = {};
		this.Options.innerHTML = '';

		this.tabIds = {'fios': this.id +'_fio_tab',
								'dates': this.id +'_date_tab',
								'search': this.id +'_search_tab',
								'exports': this.id +'_export_tab',
								'ownfieldsG': this.id +'_ownfields_tab'};

		this.createPanelSettings();
		this.createPanelContent();

		this.anniversaryUpdatePeriod = 900000;
		this.anniversaryRemindTerm = 5;	//сроки напоминания
		this.allRecordsShowed = false;	//флаг вывода всех записей (для обновления при необходимости)
	/*
		Update.request('Addressbook', 'module', 'getAnniversaries', {id: this.id}, {	//запрос на дни рождения и годовщины
			tzOffset: this.today.getTimezoneOffset(),
			dayNum: numOfDay(this.today.getDate(), this.today.getMonth()+1, this.today.getFullYear()),
			term: this.anniversaryRemindTerm
		}, false);
	*/
		Update.request('Addressbook', 'module', 'startup', {id: this.id}, {}, true);	//стартовый запрос
		this.createPanelContacts();
		this.oEmailGadget = null;
	}
	else
	{//неавторизованным юзерам мы показываем пустышку
        this.Content.innerHTML = '<strong>'+ Locale['AuthNeed'] +'</strong><br><div align="center"><img src="/img/tpl/'+Skin+'/toolbar/register.gif" title="'+ Locale['Registration'] +'" class="href" onclick="Startup.DrawRegisterForm()"><img src="/img/tpl/'+Skin+'/toolbar/login.gif" title="'+ Locale['Enter'] +'" class="href" onclick="Startup.DrawLoginForm()" style="margin-left: 20px"></div>';
    }
}

__Addressbook.prototype.Relay = function(data, part)
{
	var self = this;
	switch(data.event.action)
	{
		case 'startup':
			this.dbLite = data.variables.dbLite;
			if(!isEmpty(data.variables.ownfieldsG))
				this.ownfieldsGlobal = data.variables.ownfieldsG;
			else
				this.ownfieldsGlobal = {};
			if(!isEmpty(data.variables.ownfields))
				this.ownfields = data.variables.ownfields;
			else
				this.ownfields = [];
			this.processAnniversaries();
			this.updateOwnfieldsGlobalList();
			this.timers.t2 = window.setInterval(function() {self.processAnniversaries()}, this.anniversaryUpdatePeriod);
			mActionsInspector.execute(this.id);
			break;

		case 'getOwnfields':
			if(!isEmpty(data.variables))
				this.ownfields = data.variables;
			break;

		case 'getOwnfieldsG':	//запрос полного набора собственных полей
			if(!isEmpty(data.variables))
				this.ownfieldsGlobal = data.variables;
			break;
		case 'addOwnfieldG':
			if(!isEmpty(data.variables))
			{
				this.ownfieldsGlobal[data.variables.id] = data.variables.fname;
				this.updateOwnfieldsGlobalList();
			}
			break;
		case 'editOwnfieldG':
			if(!isEmpty(data.variables))
			{
				for(var i in data.variables)
				{
					this.ownfieldsGlobal[i] = data.variables[i];
				}
				if(this.fpanel.formContactEdit)
					this.formContactEdit.updateOwnGlobalFields();
				if(document.getElementById(this.id +'_ownGlobalFieldsBox'))
					this.updateOwnGlobalFieldsEditBox(data.variables.results);
			}
			break;
		case 'delOwnfieldG':	//добавленные или отредактированные поля
			if(data.variables)
			{
				for(var i=0; i<data.variables.length; i++)
				{
					delete this.ownfieldsGlobal[data.variables[i]];
				}
				if(this.fpanel.formContactEdit)
					this.formContactEdit.updateOwnGlobalFields();	//в форме ред-я контакта; из другой, по идее, уже удалился
			}
			break;

/*
		case 'updateOwnFields':	//добавленные или отредактированные поля
			if(data.variables.results)
			{
				for(var i in data.variables.results)
				{
					this.ownfieldsGlobal[i] = data.variables.results[i];
				}
				if(this.fpanel.formContactEdit)
					this.formContactEdit.updateOwnGlobalFields();
				if(document.getElementById(this.id +'_ownGlobalFieldsBox'))
					this.updateOwnGlobalFieldsEditBox(data.variables.results);
			}
			break;
		
		case 'delOwnFields':	//добавленные или отредактированные поля
			if(data.variables)
			{
				for(var i=0; i<data.variables.length; i++)
				{
					delete this.ownfieldsGlobal[data.variables[i]];
				}
				if(this.fpanel.formContactEdit)
					this.formContactEdit.updateOwnGlobalFields();	//в форме ред-я контакта; из другой, по идее, уже удалился
			}
			break;
*/

		case 'add':
			if(!data.variables.errors.length)
			{
				var row = gCache.get('ab_contacts_add', data.event.item.uID);
				if(row) this.dbLite[data.variables.id] = row;
				this.refreshShowedContacts();
				this.finput.contact = {};
				de(this.fpanel.formContactEdit);
				window.alert(this.lang.msg['ContactAdded']);
			}
			else
			{
				window.alert(this.lang.msg['ErrorContactAdd']);
			}
			break;

		case 'edit':
			if(!data.variables.errors.length)
			{
				var row = gCache.get('ab_contacts_edit', data.event.item.uID);
				if(row) this.dbLite[data.variables.id] = row;
				this.refreshShowedContacts();
				this.finput.contact = {};
				de(this.fpanel.formContactEdit);
				window.alert(this.lang.msg['ContactUpdated']);
			}
			else
			{
				window.alert(this.lang.msg['ErrorContactEdit']);
			}
			break;

		case 'searchByKeyword':
			this.showContactsSearchedByKeyword(data.variables);
			break;

		case 'getContactFull':
			switch(data.variables.type)
			{
				case 'view':
					this.showContactFull(data.variables.data.id, data.variables.data);
					break;
				case 'edit':
					this.fillFormContactEdit(data.variables.data.id, data.variables.data);
					break;
			}
			break;

		default:
			break;
	}
}

__Addressbook.prototype.onDelete = function()
{
	if(this.workspaceId && Desktop.State.cMain.content[this.workspaceId])
		Desktop.DeleteTabByID('cMain', this.workspaceId);
	if(this.timers)
	{
		if(this.timers.t1) window.clearTimeout(this.timers.t1);
		if(this.timers.t2) window.clearInterval(this.timers.t2);
	}
}

__Addressbook.prototype.createPanelSettings = function()
{
	var self = this;
	this.TabsOptions = new __Tabs(this.Options, 'gadget');
	this.TabsOptions.create(this.tabIds.ownfieldsG, this.lang['MyFields']);
	this.TabsOptions.show(this.tabIds.ownfieldsG);
	this.initFormOwnGlobalFields();
}

__Addressbook.prototype.createPanelContent = function()
{
	var self = this;
	this.Tabs = new __Tabs(this.Content, 'gadget');
	this.Tabs.create(this.tabIds.fios, Locale['FIO']);
	this.Tabs.create(this.tabIds.dates, Locale['Dates']);
	this.Tabs.create(this.tabIds.search, Locale['Search']);
	this.Tabs.create(this.tabIds.exports, 'Обмен');
	this.Tabs.show(this.tabIds.fios);

	this.showFormContactSearchByLetter();
	this.showFormContactSearchByKeyword();

	this.fpanel.contactsByLetter = ce('TABLE', ce('DIV', this.Tabs.data[this.tabIds.fios].content, null), {className: 'wborder'}, {width: '95%', marginTop: '18px', display: 'none'});
	ce('DIV', this.fpanel.contactsByLetter.parentNode, {className: 'href', innerHTML: this.lang['AddContact'], onclick: function() {self.createFormContactEdit('add'); Desktop.SetActiveByID('cMain', self.workspaceId); return false;}}, {background: 'url(/img/addressbook/add.gif) no-repeat center left', padding: '8px 0px 0px 20px', height: '20px'});
	
	this.fpanel.contactsByKeyword = ce('TABLE', ce('DIV', this.Tabs.data[this.tabIds.search].content, null), {className: 'wborder'}, {width: '95%', marginTop: '10px', display: 'none'});
	ce('DIV', this.fpanel.contactsByKeyword.parentNode, {className: 'href', innerHTML: this.lang['AddContact'], onclick: function() {self.createFormContactEdit('add'); Desktop.SetActiveByID('cMain', self.workspaceId); return false;}}, {background: 'url(/img/addressbook/add.gif) no-repeat center left', padding: '8px 0px 0px 20px', height: '20px'});
	
	this.fpanel.annivs = ce('DIV', this.Tabs.data[this.tabIds.dates].content);	
	this.fpanel.exports = ce('DIV', this.Tabs.data[this.tabIds.exports].content);
	
	this.redrawExportForm();
	
	//this.fpanel.export.innerHTML = 'dfsdfdsf';		
}

//-------------------------------------------------------------------------------	
//создает форму экспорта/импорта
__Addressbook.prototype.redrawExportForm = function()
{
	var self = this;	
	var tmp_str = '<form id=address_import'+this.id+' target=hidden_import action="/misc/addressbook_import.php" method=POST и enctype=multipart/form-data><FIELDSET><legend style="margin-left: 10px; padding: 0px 5px 0px 5px;">Импорт</legend><table class=paging>';
	
	tmp_str+= '<input type=hidden name=gadgetID value="'+self.id+'">';
	
	tmp_str+= '<tr><td>Источник:</td><td><select name=sourceType style="font-size: 10px; width: 150px">';
	
	for(var s in this.exportSources) { 
		tmp_str+='<option value='+s+' >'+this.exportSources[s]+'</option>';
	}		
	tmp_str+='</select></td></tr>';	
	
	tmp_str+= '<tr><td>Язык файла:</td><td><select name=cvsLang style="font-size: 10px; width: 150px">';
	
	/*
	for(var lng in  AvailableLangs) { 
		tmp_str+='<option value='+lng+' '+
			((Lang == lng)?'selected':'') +'>'+AvailableLangs[lng]+'</option>';
	}		
	*/
		
	for(var lng in  this.langs) { 
		tmp_str+='<option value='+lng+' '+
			((Lang == lng)?'selected':'') +'>'+this.langs[lng]+'</option>';
	}	
			
	tmp_str+='</select></td></tr>';
		
	
	
	tmp_str+='<tr><td>Файл: </td><td><input type=file name=importFile size=13 style="font-size: 10px; width: 150px"></td></tr>';	
	tmp_str+='<tr><td colspan=2 style="text-align: right"><input type=submit class=std_button2 value="Импортировать"></td></tr>';
	tmp_str+= '</table></FIELDSET></form>';
		
	tmp_str+= '<iframe style="display: none;"  height=100 name=hidden_import border=1></iframe>';
		
		
	//*********************
	//фрма экспорта	
	
	tmp_str+= '<form id=address_export'+this.id+' target=_blank action="/misc/addressbook_export.php" method=POST и enctype=multipart/form-data><FIELDSET><legend style="margin-left: 10px; padding: 0px 5px 0px 5px;">Экспорт</legend><table class=paging>';
	
	tmp_str+= '<input type=hidden name=gadgetID value="'+self.id+'">';
	
	tmp_str+= '<tr><td>Тип файла:</td><td><select name=targetType style="font-size: 10px; width: 150px">';
	
	for(var s in this.exportSources) { 
		tmp_str+='<option value='+s+' >'+this.exportSources[s]+'</option>';
	}		
	tmp_str+='</select></td></tr>';	
	
	tmp_str+= '<tr><td>Язык файла:</td><td><select name=cvsLang style="font-size: 10px; width: 150px">';
	/*
	for(var lng in  AvailableLangs) { 
		tmp_str+='<option value='+lng+' '+
			((Lang == lng)?'selected':'') +'>'+AvailableLangs[lng]+'</option>';
	}
	*/
	for(var lng in  this.langs) { 
		tmp_str+='<option value='+lng+' '+
			((Lang == lng)?'selected':'') +'>'+this.langs[lng]+'</option>';
	}	
			
	tmp_str+='</select></td></tr>';
		
	tmp_str+='<tr><td colspan=2 style="text-align: right"><input type=submit class=std_button2 value="Экспортировать"></td></tr>';
	tmp_str+= '</table></FIELDSET></form>';
		
		
		
	this.fpanel.exports.innerHTML = tmp_str;
	
	//инициализация нужных объектов
	var form_import = $('address_import'+this.id);
	form_import.onsubmit = self.ON_Import;
	
	//var form_export = $('address_export'+this.id);
	//form_export.onsubmit = self.ON_Export;
	
	if(!document.xdata) document.xdata = {};
	
	document.xdata[this.id] = {gadgetObj: self};
		
}

//-------------------------------------------------------------------------------
//submit формы импорта адресной книги
__Addressbook.prototype.ON_Import = function()
{
	if(!this.importFile.value) {
		alert ('Выберите файл для импорта');
		return false;
	}

	return true;
}

//-------------------------------------------------------------------------------
//submit формы экспорта адресной книги
__Addressbook.prototype.ON_ExportImport = function()
{
	
	return true;
}

//-------------------------------------------------------------------------------
//ответ на импорт
__Addressbook.prototype.CB_Import = function(xdata) {
		
	var gadgetObj = xdata.gadgetObj;
	if(!gadgetObj) return false;
	
	if(!xdata.status) {
		alert(xdata.message);
		return false;
	}

	Update.request('Addressbook', 'module', 'startup', {id: gadgetObj.id}, {}, true);
	alert('Импорт успешно завершен');

	return true;
}


//Создаёт панель списка контактов и инструментов для них
__Addressbook.prototype.createPanelContacts = function()
{
	var self = this;
	this.fpanel.listContacts = {byLetter: null, byKeyword: null};
	for(var i=0; i<2; i++)
	{
		if(!i) {
			var t = this.fpanel.contactsByLetter;
			var section = 'byLetter';
		}else{
			var t = this.fpanel.contactsByKeyword;
			var section = 'byKeyword';
		}
		
		var oTr = ce('TR', ce('THEAD', t), null, {backgroundColor: '#BFC6D6'});
		ce('H4', ce('TH', oTr, null, {verticalAlign: 'middle'}), {innerHTML: Locale['Contacts'] +':'}, {margin: '2px'});
		var oTd = ce('TH', oTr, null, {textAlign: 'right', verticalAlign: 'middle'});
		ce('IMG', oTd, {src: '/img/addressbook/edit.gif', border: 0, title: Locale['ToEdit'], className: 'href', section: section, onclick: edit}, {margin: '1px'});
		ce('IMG', oTd, {src: '/img/addressbook/del.gif', border: 0, title: Locale['ToDelete'], className: 'href', section: section, onclick: del}, {margin: '1px'});
		if(!i) this.fpanel.listContacts.byLetter = ce('TBODY', t);
		else this.fpanel.listContacts.byKeyword = ce('TBODY', t);
	}

	function getChecked(section)
	{
		var t = self.fpanel.listContacts[section].getElementsByTagName('INPUT');
		var elements = [];
		for(var i=0; i<t.length; i++)
		{
			if(t[i].type == 'checkbox' && t[i].cid && t[i].checked)
				elements.push(t[i].cid);
		}
		return elements;
	}

	function edit()
	{
		var ar = getChecked(this.section);
		if(ar.length == 0)
		{
			window.alert(self.lang.msg['ForEditNeedSelectContact']);
		}
		else if(ar.length > 1)
		{
			window.alert(self.lang.msg['ForEditNeedSelectContactOnlyOne']);
		}
		else
		{
			self.initContactEdit(ar[0]);
		}
	}
	function del()
	{
		var ar = getChecked(this.section);
		if(ar.length == 0)
		{
			window.alert(self.lang.msg['ForDeleteNeedSelectContact']);
		}
		else
		{
			if(window.confirm(self.lang.msg['SureToDeleteSelectedContacts']))
			{
				for(var i=0; i<ar.length; i++)
				{
					if(t = document.getElementById(self.id +'_displContact_byLetter_'+ ar[i]))
						de(t);
					if(t = document.getElementById(self.id +'_displContact_byKeyword_'+ ar[i]))
						de(t);
					delete self.dbLite[ar[i]];
				}
				Update.request('Addressbook', 'module', 'delete', {id: self.id}, {ids: ar}, false);
			}
		}
	}

}

//Форма добавления/редактирования контактов
__Addressbook.prototype.createFormContactEdit = function(action)
{
	var self = this;

	//Определяем функции-члены (некая имитация)
	this.formContactEdit.updateOwnGlobalFields = function()
	{
		var tid = self.id +'_formContacteditOwnfieldGsBox';
		var oTbody = null;
		var backup = {};
		if(!(oTbody = document.getElementById(tid)))
		{
			oTbody = ce('TBODY', ce('TABLE', oForm), {id: tid});
		}
		else
		{
			var t = oTbody.getElementsByTagName('INPUT');
			for(var i=0; i<t.length; i++)
			{
				backup[t[i].id] = t[i].value;
			}
			var tmp = oTbody.parentNode;
			de(oTbody);
			oTbody = ce('TBODY', tmp, {id: tid});
		}

		self.finput.contact.ownfieldsGlobal = {};
		var t = null;
		for(var i in self.ownfieldsGlobal)
		{
			oTr = ce('TR', oTbody);
			ce('TD', oTr, {innerHTML: self.ownfieldsGlobal[i] +': '}, {paddingTop: '5px'});
			var fid = self.id +'_inputOwnfieldsGlobal_'+ i;
			self.finput.contact.ownfieldsGlobal[i] = ce('INPUT', ce('TD', oTr, null, {padding: '5px 0px 0px 5px'}), {type: 'text', id: fid}, {width: '150px'});
			if(backup[fid]) self.finput.contact.ownfieldsGlobal[i].value = backup[fid];
			createNoteBlock('ownfieldsGlobal_'+ i +'_', ce('DIV', ce('TD', oTr, null, {paddingTop: '5px'}), null, {paddingLeft: '5px'}));
			if(backup['ownfieldsGlobal_'+ i +'_Note'])
				self.finput.contact[field +'Note'].value = backup['ownfieldsGlobal_'+ i +'_Note'];
		}
	}

/* Создаёт блок ввода телефонов, емейлов, веб-пейджеров и всего прочего, на то похожего */
	this.formContactEdit.createPhoneLikeBlock = function(section, title)
	{
		if(!self.finput.contact[section])
			self.finput.contact[section] = [];
		var obj = {};
		var oTr = ce('TR', oTbody);
		var oTd = ce('TD', oTr, {innerHTML: title +':'}, {width: '57px'});
		oTd = ce('TD', oTr, null, {width: '92px', paddingLeft: '5px'});

		if(section != 'ownfields' && section != 'annivs' && self.types[section])	//тип предустановлен
		{
			obj.type = ce('SELECT', null, null, {width: '92px'});
			var firstStep = true;
			for(var i in self.types[section])
			{
				var properties = {value: i, innerHTML: self.types[section][i]};
				if(firstStep) properties.selected = 'true';
				ce('OPTION', obj.type, properties);
				firstStep = false;
			}
			oTd.appendChild(obj.type);
		}
		else
		{
			obj.type = ce('INPUT', oTd, {type: 'text', maxLength: 127}, {width: '92px'});
		}

		oTd = ce('TD', oTr, {noWrap: true}, {width: '300px', verticalAlign: 'top'});
		if(section == 'annivs')
		{
			obj.mdata = {};
			createDateInput(obj.mdata, oTd);
		}
		else
		{
			obj.mdata = ce('INPUT', oTd, {type: 'text'}, {width: '150px'});
		}
	
		obj.values = [];
		obj.i = false;
		var i = self.finput.contact[section].push(obj);
		createNoteBlock(section+''+(i-1), oTd);
		ce('IMG', ce('TD', oTr, null, {width: '18px', verticalAlign: 'top'}), {i: (i-1), section: section, src: '/img/icons/x2.gif', title: Locale['ToDelete'], onclick: delBlock});
		return (i-1);

		function delBlock()
		{
			de(this.parentNode.parentNode);
			var i = self.finput.contact[this.section][this.i].i;
			delete self.finput.contact[this.section][this.i];
			if(action == 'edit')
			{
				self.finput.contact[this.section][this.i] = {i: i, deleted: true};
			}
		}
/*
		var t = ce('INPUT', oTd, {type: 'button', 'className': 'std_button', value: '+'}, {marginLeft: '10px'});
		t.onclick = function() {self.formContactEdit.addPhoneLikeItem(section); self.formContactEdit.setFlag(section, true); return false;}
		oAdded[section] = ce('UL', ce('TD', ce('TR', oTbody), {colSpan: 6}));
*/
	}

	this.formContactEdit.setFlag = function(section, flag)
	{
		self.finput.contact.flags[section] = flag;
	}

	Desktop.initTabFromModule(this.id);
	this.workspace.style.padding = '15px';
	var oDiv = this.workspace;
	this.fpanel.messages = ce('DIV', oDiv, {className: 'error'});
	this.fpanel.formContactEdit = ce('FORM', oDiv, null, {width: '90%', padding: '5px 10px 15px', backgroundColor: '#FFFFFF', border: '1px solid #888888'});
	var oForm = this.fpanel.formContactEdit;
	var oTbody = ce('TBODY', ce('TABLE', oForm, {className: 'wform'}, {width: '90%'}));
	var oTr = ce('TR', oTbody);
	var oTd = ce('TD', oTr);
	if(action == 'add')
		ce('H3', oTd, {innerHTML: this.lang['AddingNewContact']});
	else if(action == 'edit')
		ce('H3', oTd, {innerHTML: this.lang['EditingContact']});
	ce('INPUT', ce('TD', oTr, null, {textAlign: 'right'}), {type: 'submit', className: 'std_button2', value: Locale['ToSave']});

	oTbody = ce('TBODY', ce('TABLE', oForm, {className: 'wform'}));

	this.finput.contact = {};
	this.finput.contact.flags = {};	//flags - набор hidden-полей, семафорящих факт изменения в блоках групп, телефонов и т.д.; реагируют тривиально на onChange - не наверняка, зато в большинстве случаев дешёвый кислород для сервера

	oTr = ce('TR', oTbody);
	ce('TD', oTr, {innerHTML: Locale['Surname']+':'});
	oTd = ce('TD', oTr, {width: '99%'}, {paddingLeft: '3px'});
	this.finput.contact.surname = ce('INPUT', oTd, {type: 'text', id: this.id +'_inputSurname'}, {width: '150px'});

	createNoteBlock('surname', oTd);

	oTr = ce('TR', oTbody);
	ce('TD', oTr, {innerHTML: Locale['Name']+':'});
	oTd = ce('TD', oTr, null, {paddingLeft: '3px', whiteSpace: 'nowrap'});
	this.finput.contact.name = ce('INPUT', oTd, {type: 'text', id: this.id +'_inputName'}, {width: '150px'});
	createNoteBlock('name', oTd);
	oTr = ce('TR', oTbody);
	ce('TD', oTr, {innerHTML: Locale['Middlename']+':'});
	oTd = ce('TD', oTr, null, {paddingLeft: '3px'});
	this.finput.contact.middlename = ce('INPUT', oTd, {type: 'text', id: this.id +'_inputMiddlename'}, {width: '150px'});
	createNoteBlock('middlename', oTd);
	oTr = ce('TR', oTbody);
	ce('TD', oTr, {innerHTML: Locale['Nickname']+':'});
	oTd = ce('TD', oTr, null, {paddingLeft: '3px'});
	this.finput.contact.nickname = ce('INPUT', oTd, {type: 'text', id: this.id +'_inputNickname'}, {width: '150px'});
	createNoteBlock('nickname', oTd);
	oTr = ce('TR', oTbody);
	ce('TD', oTr, {innerHTML: Locale['Birthday']+':'});
	this.finput.contact.birthdate = {};
	var oTd = ce('TD', oTr, null, {paddingLeft: '5px'});
	createDateInput(this.finput.contact.birthdate, oTd);
	createNoteBlock('birthdate', oTd);

	oTr = ce('TR', oTbody);
	ce('TD', oTr, {innerHTML: Locale['Address']+':'});
	oTd = ce('TD', oTr, null, {paddingLeft: '5px'});
	this.finput.contact.address = ce('TEXTAREA', oTd, {id: this.id +'_inputAddress'}, {width: '150px', height: '42px'});
	createNoteBlock('address', oTd);
/*
	oTr = ce('TR', oTbody);
	ce('TD', oTr, {innerHTML: 'Группы:'});
	this.finput.contact.groups = ce('SELECT', ce('TD', oTr, null, {paddingLeft: '5px'}), {id: this.id +'_inputGroup', multiple: true}, {height: '80px'});
	this.finput.contact.groups.onchange = function() {self.formContactEdit.setFlag('groups', true)};
	for(var i in this.contactGroups)
	{
		ce('OPTION', this.finput.contact.groups, {value: i, innerHTML: this.contactGroups[i]});
	}
*/
	var oAdded = {};
	var oDiv = ce('DIV', oForm, {innerHTML: '<strong>'+ Locale['ToAdd']+'</strong>'}, {margin: '15px 0px', border: '1px solid #BBBBBB', padding: '10px'});
	var t = ce('SELECT', null, null, {width: '130px', margin: '0px 10px'});
	for(var i in this.phoneLiketypes)
	{
		ce('OPTION', t, {value: i, innerHTML: this.phoneLiketypes[i]});
	}
	oDiv.appendChild(t);
	ce('INPUT', oDiv, {type: 'BUTTON', value: 'ОК', className: 'std_button', onclick: function() {self.formContactEdit.createPhoneLikeBlock(this.previousSibling.value, this.previousSibling.options[this.previousSibling.selectedIndex].innerHTML)}});
	oTbody = ce('TBODY', ce('TABLE', oDiv, {className: 'wform'}, {width: '90%', marginTop: '15px'}));

	this.formContactEdit.updateOwnGlobalFields();
/*
	ce('BR', this.finput.contact.ownfields.type.parentNode);
	this.finput.contact.ownfields.typePreset = ce('SELECT', this.finput.contact.ownfields.type.parentNode, null, {width: '90px'})
	ce('OPTION', this.finput.contact.ownfields.typePreset, {value: '', innerHTML: '-новое-', defaultSelected: true});
	for(var i=0; i<this.ownfields.length; i++)
		ce('OPTION', this.finput.contact.ownfields.typePreset, {value: this.ownfields[i], innerHTML: this.ownfields[i]});

	this.finput.contact.ownfields.typePreset.onchange = function()
	{
		if(this.value != '')
		{
			self.finput.contact.ownfields.type.value = this.value;
			self.finput.contact.ownfields.type.readOnly = true;
		}
		else
		{
			self.finput.contact.ownfields.type.value = '';
			self.finput.contact.ownfields.type.readOnly = false;
		}
	}

	if(document.getElementById(this.id +'_ownGlobalFieldsBox'))
		this.updateOwnGlobalFieldsEditBox();
*/
	this.today = new Date();	//вероятно, надо бы сделать некий общий объект даты, а то немного нерационально; с другой стороны, инкапсуляции никто не отменял

	ce('SPAN', oForm, {innerHTML: '<br/>'+ Locale['Notice'] +': '});
	this.finput.contact.note = ce('TEXTAREA', oForm, {id: this.id +'_inputNote'}, {width: '150px', height: '50px'});
	ce('INPUT', ce('DIV', oForm, null, {width: '90%', marginTop: '15px', textAlign: 'right'}), {type: 'submit', className: 'std_button2', value: Locale['ToSave']}, {display: ''});

	oForm.onsubmit = function()
	{
		if(!checkFormContactEdit()) return false;	//тестим корректность введённых значений

		var obj = {};

		for(var section in self.finput.contact)
		{
			if(self.phoneLiketypes[section])	//это один из PhoneLike типов
			{
				for(var j=0; j<self.finput.contact[section].length; j++)
				{
					var t = self.finput.contact[section][j];
					if(!obj[section])
						obj[section] = [];
					if(!obj[section][j])
						obj[section][j] = {};

					obj[section][j].i = t.i;
					if(t.deleted)
					{
						obj[section][j].del = true;
						continue;
					}
					if(section == 'annivs')
					{
						if(t.mdata.day.value == '' || !checkDateInput(t.mdata))
						{
							continue;
						}
						else
						{
							if(t.mdata.day.value < 10) t.mdata.day.value = addZero(t.mdata.day.value);
							if(t.mdata.year.value && t.mdata.year.value != '0')
								obj[section][j].mdata = t.mdata.year.value;
							else
								obj[section][j].mdata = '3000';
							obj[section][j].mdata += '-'+ t.mdata.month.value +'-'+ t.mdata.day.value;
						}
					}
					else
					{
						if(t.mdata.value == '') continue;
						obj[section][j].mdata = t.mdata.value;
					}

					obj[section][j].type = t.type.value;
					obj[section][j].note = self.finput.contact[section+j+'Note'].value;
					delete self.finput.contact[section+j+'Note'];
				}
			}
			else if(section == 'birthdate')
			{
				if(self.finput.contact[section].day.value != '')
				{
					if(self.finput.contact[section].day.value < 10) self.finput.contact[section].day.value = addZero(self.finput.contact[section].day.value);
					if(self.finput.contact[section].year.value && self.finput.contact[section].year.value!='0')
						obj[section] = self.finput.contact[section].year.value;
					else
						obj[section] = '3000';
					obj[section] += '-'+self.finput.contact[section].month.value +'-'+ self.finput.contact[section].day.value;
				}
				else obj[section] = '';
			}
			else if(section == 'ownfieldsGlobal')
			{
				obj[section] = {};
				for(var i in self.finput.contact[section])
				{
					obj[section][i] = {value: self.finput.contact[section][i].value, note: self.finput.contact['ownfieldsGlobal_'+ i +'_Note'].value};
					if(self.finput.contact[section][i].fid) obj[section][i].fid = self.finput.contact[section][i].fid;
				}
			}
			else if(section.substr(0, 15) == 'ownfieldsGlobal')	//комменты; увы, ничего лучше как-то не не легло в концепцию данной парадигмы
				continue;
			else
			{
				obj[section] = self.finput.contact[section].value;
			}
		}
		var rid = Update.request('Addressbook', 'module', action, {id: self.id}, obj, true);	//запрос на дни рождения и годовщины

		//готовим строку в dbLite
		var row = {};
		if(obj.name) row.name = obj.name;
		if(obj.surname) row.sname = obj.surname;
		if(obj.nickname) row.nname = obj.nickname;
		if(obj.middlename) row.mname = obj.middlename;
		if(obj.birthdate)
		{
			row.bdoy = numOfDayFromStr(obj.birthdate);
			row.bdate = obj.birthdate;
		}
		if(obj.annivs)
		{
		}
		for(var s in self.phoneLiketypes[section])
		{
			if(!isEmpty(obj[s]))
				for(var j=0; j<obj[s].length; j++)
				{
					if(obj[s][j].del) continue;
					if(!row[s])
						row[s] = {};
					if(s == 'annivs')
					{
						row[s][obj[s][j].mdata] = {doy: numOfDayFromStr(obj[s][j].mdata), title: obj[s][j].type};
					}
					else
					{
						if(!row[s][obj[s][j].type]) row[s][obj[s][j].type] = [];
						row[s][obj[s][j].type].push(obj[s][j].mdata);
					}
				}
		}
		gCache.add('ab_contacts_'+action, rid, row);

		return false;
	}

/* Проверяет форму */
	function checkFormContactEdit()
	{
		if(self.finput.contact.surname.value == '' && self.finput.contact.name.value == '' && self.finput.contact.middlename.value == '' && self.finput.contact.nickname.value == '')
		{
			window.alert(self.lang.msg['NeedToAtLeastOneOfFields']);
			self.finput.contact.surname.focus();
			return false;
		}
		if(self.finput.contact.birthdate.day.value != '')
		{
			if(!checkDateInput(self.finput.contact.birthdate)) return false;
		}
		return true;
	}

/* Создаёт блок комментария */
	function createNoteBlock(field, oArea)	//создаёт сворачиваемый блок комментария для поля
	{
		var t = ce('INPUT', oArea, {type: 'button', 'className': 'std_button', field: field, value: '*', title: Locale['Notice']}, {margin: '0px 5px 0px 10px'});
		//self.finput.contact[field +'Note'] = ce('INPUT', oArea, {type: 'hidden', maxLength: 63}, {width: '160px'});
		self.finput.contact[field +'Note'] = ce('INPUT', oArea, {type: 'text', maxLength: 63, id: field +'Note'}, {width: '100px', display: 'none'});
		t.onclick = function() {createNoteBlockOnClick(this);}
	}

/* Функция для onClick на кнопке раскрытия поля комментария */
	function createNoteBlockOnClick(oBtn)	//чтобы не писать каждой кнопке [...] обработчик
	{
		//if(self.finput.contact[oBtn.field +'Note'].type == 'hidden')
		if(self.finput.contact[oBtn.field +'Note'].style.display == 'none')
		{
			oBtn.value = '*';
			//self.finput.contact[oBtn.field +'Note'].type = 'text';
			self.finput.contact[oBtn.field +'Note'].style.display = '';
			self.finput.contact[oBtn.field +'Note'].focus();
		}
		else
		{
			oBtn.value = '*';
			//self.finput.contact[oBtn.field +'Note'].type = 'hidden';
			self.finput.contact[oBtn.field +'Note'].style.display = 'none';
		}
	}

/* Создаёт блок ввода даты */
	function createDateInput(oStore, oParent)
	{
		oStore.day = ce('INPUT', oParent, {type: 'text', maxLength: 2}, {width: '16px', marginRight: '2px'});
		oStore.month = ce('SELECT', null);
		for(var m in Locale.Months)
		{
			ce('OPTION', oStore.month, {value: addZero(m), innerHTML: Locale.Months[m]});
		}
		oParent.appendChild(oStore.month);
		oStore.year = ce('INPUT', oParent, {type: 'text', maxLength: 4}, {width: '30px', margin: '0px 2px 0px 2px'});
		ce('SPAN', oParent, {innerHTML: 'г.'});
	}

/* Проверяет блок ввода даты */
	function checkDateInput(oStore)	//проверяет введённую дату
	{
		oStore.day.value = oStore.day.value - 0;
		if(oStore.day.value > gVars.Months.MaxDays[oStore.month.value] || oStore.day.value < 0)
		{
			window.alert(self.lang.msg['EnterCorrectDay']);
			oStore.day.style.color = '#FF0000';
			oStore.day.focus();
			return false;
		}
		else oStore.day.style.color = '';

		oStore.year.value = oStore.year.value - 0;
		if(oStore.year.value != 0 && (oStore.year.value > self.today.getFullYear() || oStore.year.value < 1001))
		{
			window.alert(self.lang.msg['EnterCorrectYear']);
			oStore.year.style.color = '#FF0000';
			oStore.year.focus();
			return false;
		}
		else oStore.year.style.color = '';

		return true;
	}
}

//Заполняем форму редактирования полученными от сервера данными
__Addressbook.prototype.fillFormContactEdit = function(contact_id, data)
{
	var self = this;
	this.finput.contact.contactId = ce('INPUT', this.fpanel.formContactEdit, {type: 'hidden', value: contact_id});
	this.finput.contact.surname.value = data.sname;
	this.finput.contact.surnameNote.value = data.snameN;
	this.finput.contact.name.value = data.name;
	this.finput.contact.nameNote.value = data.nameN;
	this.finput.contact.middlename.value = data.mname;
	this.finput.contact.middlenameNote.value = data.mnameN;
	this.finput.contact.address.value = data.address;
	this.finput.contact.addressNote.value = data.addressN;
	this.finput.contact.nickname.value = data.nname;
	this.finput.contact.nicknameNote.value = data.nnameN;
	var date = new Date();
	if(data.bdate)
	{
		this.finput.contact.birthdate.day.value = data.bdate.substr(8,2);
		this.finput.contact.birthdate.month.options[data.bdate.substr(5,2)-1].selected = true;
		var tmp = data.bdate.substr(0,4);
		if(tmp != '3000')
			this.finput.contact.birthdate.year.value = tmp;
		else
			this.finput.contact.birthdate.year.value = '';
	}
	this.finput.contact.birthdateNote.value = data.bdateN;
	this.finput.contact.note.value = data.note;

	for(var section in this.phoneLiketypes)
	{
		fillPhoneLikeItem(section);
	}

	if(!isEmpty(data.ownfieldsG))
	{
		for(var i in data.ownfieldsG)
		{
			self.finput.contact.ownfieldsGlobal[i].value = data.ownfieldsG[i].value;
			self.finput.contact.ownfieldsGlobal[i].fid = i;
			self.finput.contact['ownfieldsGlobal_'+ i +'_Note'].value = data.ownfieldsG[i].note;
		}
	}

	function fillPhoneLikeItem(section)
	{
		if(isEmpty(data[section])) return;

		for(var i in data[section])
		{
			var j = self.formContactEdit.createPhoneLikeBlock(section, self.phoneLiketypes[section]);
			var obj = self.finput.contact[section][j];
			if(section == 'annivs')
			{
				obj.mdata.day.value = data[section][i].mdata.substr(8, 2);
				obj.mdata.month.options[data[section][i].mdata.substr(5, 2)-1].selected = true;
				var t = data[section][i].mdata.substr(0, 4);
				if(t != '3000')
					obj.mdata.year.value = t;
				else
					obj.mdata.year.value = '';
			}
			else
			{
				obj.mdata.value = data[section][i].mdata;
			}
			obj.i = i;
			obj.type.value = data[section][i].type;
			self.finput.contact[section+j+'Note'].value = data[section][i].note;
		}
	}
}

__Addressbook.prototype.showFormContactSearchByLetter = function()
{
	var self = this;
	//алфавит для выбора контактов по первой букве
	this.fpanel.abc = ce('FORM', this.Tabs.data[this.tabIds.fios].content, {innerHTML: ''});
	var oTr = ce('TR', ce('TBODY', ce('TABLE', this.fpanel.abc)));
	this.finput.showContactSelectLetterLoc = ce('SELECT', null, {onchange: goSearch}, {marginBottom: '20px'});
	ce('OPTION', this.finput.showContactSelectLetterLoc, {innerHTML: '['+ Locale.Abc[0] +'-'+ Locale.Abc[Locale.Abc.length-1] +']'})
	for(var i=0;  i<Locale.Abc.length; i++)
	{
		ce('OPTION', this.finput.showContactSelectLetterLoc, {value: Locale.Abc[i], innerHTML: Locale.Abc[i]});
	}

	var oTd = ce('TD', oTr);
	oTd.appendChild(this.finput.showContactSelectLetterLoc);
	if(Lang != 'EN')
	{
		this.finput.showContactSelectLetterEn = ce('SELECT', null, {onchange: goSearch}, {margin: '0px 0px 20px 10px'});
		ce('OPTION', this.finput.showContactSelectLetterEn, {innerHTML: '[A-Z]'}, {paddingRight: '5px'})
		var abc_en = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
		for(var i=0;  i<abc_en.length; i++)
		{
			ce('OPTION', this.finput.showContactSelectLetterEn, {value: abc_en[i], innerHTML: abc_en[i]});
		}
			oTd = ce('TD', oTr);
			oTd.appendChild(this.finput.showContactSelectLetterEn);
	}
	ce('SPAN', ce('TD', oTr, null, {padding: '4px 0px 0px 10px'}), {innerHTML: '['+ this.lang['AllRecords'] +']', className: 'href', onclick: function() {self.showContactsSearchedByLetter();}});

	function goSearch()
	{
		if(this.value) self.showContactsSearchedByLetter(this.value);
		return false;
	}
}

//Форма поиска по ключевому слову
__Addressbook.prototype.showFormContactSearchByKeyword = function()
{
	var self = this;
	this.fpanel.formSearchByKeyword = ce('FORM', this.Tabs.data[this.tabIds.search].content, {innerHTML: this.lang['SearchByKeyword'] +':<br/>'}, {marginBottom: '12px'});
	this.finput.showContactKeyword = ce('INPUT', this.fpanel.formSearchByKeyword, {type: 'text'});
	ce('INPUT', this.fpanel.formSearchByKeyword, {type: 'submit', 'className': 'std_button', value: 'OK'});

	this.fpanel.formSearchByKeyword.onsubmit = function()
	{
		if(self.finput.showContactKeyword.value.length < self.keywordMinLength)
		{
			window.alert(self.lang.msg['KeywordMustContentNotLessThanSymbols'][0] + '<strong>'+ self.keywordMinLength +'</strong> '+ self.lang.msg['KeywordMustContentNotLessThanSymbols'][1] +'.');
			self.finput.showContactKeyword.focus();
		}
		else
			processKeyword(self.finput.showContactKeyword.value);
		return false;
	}

	function processKeyword(keyword)	//пытаемся классифицировать ключевое слово
	{
		var obj = {};
		if(!/[^\d\-\(\)]/.test(keyword))
		{
			if(!/[^\d]/.test(keyword))
				obj.type = 'number';
			else if(/^\d{1,2}[\-\.]\d{1,2}[\-\.]\d{4}$/.test(keyword))
				obj.type = 'date';
			else
				obj.type = 'phone';
		}
		else if(/^[a-z\d\-\_\.\s]+\@[a-z\d\-\.]+$/i.test(keyword))
		{
			obj.type = 'email';
		}
		else
		{
			obj.type = 'string';
		}
		obj.keyword = keyword;

		Update.request('Addressbook', 'module', 'searchByKeyword', {id: self.id}, obj, true);
	}
}

//Обновляет таблицу недавно найденных контактов
__Addressbook.prototype.refreshShowedContacts = function()
{
/*
	if(this.finput.showContactKeyword && this.finput.showContactKeyword.value)
	{	//недавно искалось по ключевому слову
		this.showContactsSearchedByKeyword(this.finput.showContactKeyword.value);
	}
*/
	if(this.allRecordsShowed)
	{	//были выведены все записи
		this.showContactsSearchedByLetter();
	}
	else if(this.finput.showContactSelectLetterLoc && this.finput.showContactSelectLetterLoc.selectedIndex > 0)
	{	//по локальному алфавиту
		this.showContactsSearchedByLetter(this.finput.showContactSelectLetterLoc.options[this.finput.showContactSelectLetterLoc.selectedIndex].value);
	}
	else if(this.finput.showContactSelectLetterEn && this.finput.showContactSelectLetterEn.selectedIndex > 0)
	{	//по английскому алфавиту
		this.showContactsSearchedByLetter(this.finput.showContactSelectLetterEn.options[this.finput.showContactSelectLetterEn.selectedIndex].value);
	}
	this.processAnniversaries();
}

//Выводит строку контакта в кратком варианте
__Addressbook.prototype.showContact = function(contact_id, section, addinfo)
{
	var self = this;
	this.fpanel.listContacts[section].parentNode.style.display = '';
	var oTr = ce('TR', this.fpanel.listContacts[section], {id: this.id +'_displContact_'+section+'_'+ contact_id}, {backgroundColor: '#FFFFFF'});
	var oTd = ce('TD', oTr, {width: '75%'}, {verticalAlign: 'middle'});
	var oSpan = ce('SPAN', oTd, {cid: contact_id, className: 'href', onclick: show, onmouseover: f1, onmouseout: f2});
	if(this.dbLite[contact_id].sname)
	{
		oSpan.innerHTML = this.dbLite[contact_id].sname;
		if(this.dbLite[contact_id].name) oSpan.innerHTML += ' '+ this.dbLite[contact_id].name.substr(0, 1) +'.';
	}
	else if(this.dbLite[contact_id].name)
		oSpan.innerHTML += this.dbLite[contact_id].name;
	if(this.dbLite[contact_id].nname)
	{
		if(oSpan.innerHTML != '')
			oSpan.innerHTML += ' ('+ this.dbLite[contact_id].nname +')';
		else
			oSpan.innerHTML = this.dbLite[contact_id].nname;
	}
	if(!this.dbLite[contact_id].sname && !this.dbLite[contact_id].name && !this.dbLite[contact_id].nname && this.dbLite[contact_id].mname)
		oSpan.innerHTML = this.dbLite[contact_id].mname;
	if(addinfo) oSpan.innerHTML += ' <em>/'+ addinfo +'/</em>';
	if(oSpan.innerHTML == '') oSpan.innerHTML = '...';

	ce('INPUT', ce('TD', oTr, {width: '25%', align: 'right'}), {type: 'checkbox', cid: contact_id}, {marginRight: '5px'});

	var t = this.dbLite[contact_id];
	t.desc = '';

	if(t.phones)	//можно ли настолько наглеть? :)
	{
		t.desc += '<strong>'+ this.lang['Phones'] +':</strong>';
		for(var s in t.phones)
		{
			for(var i=0; i<t.phones[s].length; i++)
			{
				t.desc += '<br/>'+t.phones[s][i];
			}
		}
	}
	if(t.emails)
	{
		if(t.desc) t.desc += '<br/>';
		t.desc += '<strong>'+ this.lang['Emails'] +':</strong>';
		for(var s in t.emails)
		{
			for(var i=0; i<t.emails[s].length; i++)
			{
				t.desc += '<br/>'+t.emails[s][i];
			}
		}
	}

	function show()
	{
		self.showContactFull(this.cid);
		Desktop.SetActiveByID('cMain', self.workspaceId);
		return false;
	}

	function f1(e)
	{
		if(self.dbLite[this.cid].desc == '') return;
		e = e || window.event;
		Tooltip.Show(self.dbLite[this.cid].desc, Event.element(e), null, null, $('Module.'+self.id));
	}
	function f2()
	{
		if(self.dbLite[this.cid].desc == '') return;
		Tooltip.Hide();
	}
}

//Выводит полную информацию о контакте
__Addressbook.prototype.showContactFull = function(contact_id, data)
{
	var self = this;
	if(!data)
	{
		Update.request('Addressbook', 'module', 'getContactFull', {id: this.id}, {id: contact_id, type: 'view'}, true);
		return;
	}
	else
	{
		Desktop.initTabFromModule(this.id);
		this.workspace.style.padding = '15px';
		var oTbody = ce('TBODY', ce('TABLE', this.workspace, {className: 'wborder workspace'}, {backgroundColor: '#F4F4F4', width: '100%'}));
		var oTr = null;
		var oTd = null;

		if(data.sname)
		{
			oTr = ce('TR', oTbody);
			ce('TD', oTr, {innerHTML: '<b>'+ Locale['Surname'] +':</b>'});
			oTd = ce('TD', oTr, {innerHTML: data.sname+' '});
			if(data.snameN)
				ce('EM', oTd, {innerHTML: '('+ data.snameN +')'});
		}
		if(data.name)
		{
			oTr = ce('TR', oTbody);
			ce('TD', oTr, {innerHTML: '<b>'+ Locale['Name'] +':</b>'});
			oTd = ce('TD', oTr, {innerHTML: data.name+' '});
			if(data.nameN)
				ce('EM', oTd, {innerHTML: '('+ data.nameN +')'});
		}
		if(data.mname)
		{
			oTr = ce('TR', oTbody);
			ce('TD', oTr, {innerHTML: '<b>'+ Locale['Middlename'] +':</b>'});
			oTd = ce('TD', oTr, {innerHTML: data.mname+' '});
			if(data.mnameN)
				ce('EM', oTd, {innerHTML: '('+ data.mnameN +')'});
		}
		if(data.nname)
		{
			oTr = ce('TR', oTbody);
			ce('TD', oTr, {innerHTML: '<b>'+ Locale['Nickname'] +':</b>'});
			oTd = ce('TD', oTr, {innerHTML: data.nname+' '});
			if(data.nnameN)
				ce('EM', oTd, {innerHTML: '('+ data.nnameN +')'});
		}
		if(data.address)
		{
			oTr = ce('TR', oTbody);
			ce('TD', oTr, {innerHTML: '<b>'+ Locale['Address'] +':</b>'});
			oTd = ce('TD', oTr, {innerHTML: data.address+' '});
			if(data.addressN)
				ce('EM', oTd, {innerHTML: '('+ data.addressN +')'});
		}
		if(data.bdate)
		{
			oTr = ce('TR', oTbody);
			ce('TD', oTr, {innerHTML: '<b>'+ Locale['Birthday'] +':</b>'});
			var tmp = data.bdate.substr(0,4);
			if(tmp != '3000')
				tmp = '.'+tmp;
			else
				tmp = '';
			oTd = ce('TD', oTr, {innerHTML: data.bdate.substr(8,2) +'.'+ data.bdate.substr(5,2) +tmp+' '});
			if(data.bdateN)
				ce('EM', oTd, {innerHTML: '('+ data.bdateN +')'});
		}

		//Годовщины
		if(data.annivs && !isEmpty(data.annivs))
		{
			oTr = null;
			for(var i in data.annivs)
			{
				if(!oTr)
				{
					oTr = ce('TR', oTbody);
					ce('TD', oTr, {innerHTML: '<b>'+ Locale['Dates'] +':</b>'});
					oTd = ce('TD', oTr);
				}
				else
					oTd.innerHTML += '<br/>';

				oTd.innerHTML += data.annivs[i].mdata.substr(8,2) +'.'+ data.annivs[i].mdata.substr(5,2);
				var tmp = data.annivs[i].mdata.substr(0,4);
				if(tmp != '3000')
					oTd.innerHTML += '.'+ tmp;
				if(data.annivs[i].type)
					oTd.innerHTML += ' '+data.annivs[i].type +' ';
				if(data.annivs[i].note)
					ce('EM', oTd, {innerHTML: ' ('+ data.annivs[i].note +')'});
			}
		}

		//Е-мэйлы
		if(data.emails && !isEmpty(data.emails))
		{
			oTr = null;
			for(var i in data.emails)
			{
				if(!oTr)
				{
					oTr = ce('TR', oTbody);
					ce('TD', oTr, {innerHTML: '<b>'+ this.lang['Emails'] +':</b>'});
					oTd = ce('TD', oTr);
				}
				else
					ce('BR', oTd);
				var img = '';
				switch(data.emails[i].type)
				{
					case 'private': img = 'email_private.gif'; break;
					case 'work': img = 'email_work.gif'; break;
					case 'other': img = 'email_other.gif'; break;
				}

				//ce('IMG', oTd, {src: '/img/icons/addressbook/'+ img, align: 'absmiddle'}, {marginRight: '4px'});
				ce('IMG', oTd, {src: '/img/icons/e_mail.gif', height: 16, width: 16, align: 'absmiddle'}, {marginRight: '4px'});

				ce('A', oTd, {href: 'mailto:'+data.emails[i].mdata,
									onclick: function () {return self.emailOnclick(this.href)},
									innerHTML: data.emails[i].mdata});

				if(data.emails[i].note) ce('EM', oTd, {innerHTML: '('+ data.emails[i].note +')'});
			}
		}
		//Телефоны
		if(data.phones && !isEmpty(data.phones))
		{
			oTr = null;
			for(var i in data.phones)
			{
				if(!oTr)
				{
					oTr = ce('TR', oTbody);
					ce('TD', oTr, {innerHTML: '<b>'+ this.lang['Phones'] +':</b>'});
					oTd = ce('TD', oTr);
				}
				else
					oTd.innerHTML += '<br/>';
				var img = '';
				switch(data.phones[i].type)
				{
					case 'mobile': img = 'phone_mobile.gif'; break;
					case 'home': img = 'phone_home.gif'; break;
					case 'work': img = 'phone_work.gif'; break;
					case 'fax': img = 'phone_fax.gif'; break;
					case 'other': img = 'phone_other.gif'; break;
				}
				ce('IMG', oTd, {src: '/img/addressbook/'+ img, align: 'absmiddle'}, {marginRight: '4px'});
				oTd.innerHTML += data.phones[i].mdata;
				if(data.phones[i].note) oTd.innerHTML += ' <em>('+data.phones[i].note +')</em>';
			}
		}
		//Веб-пейджеры
		if(data.webpagers && !isEmpty(data.webpagers))
		{
			oTr = null;
			for(var i in data.webpagers)
			{
				if(!oTr)
				{
					oTr = ce('TR', oTbody);
					ce('TD', oTr, {innerHTML: '<b>'+ this.lang['Webpagers'] +':</b>'});
					oTd = ce('TD', oTr);
				}
				else
					oTd.innerHTML += '<br/>';
				oTd.innerHTML += this.types.webpagers[data.webpagers[i].type] +': ';
				oTd.innerHTML += data.webpagers[i].mdata;
				if(data.webpagers[i].note)
					oTd.innerHTML += ' <em>('+data.webpagers[i].note +')</em>';
			}
		}
		//Собственные поля для данной записи
		if(!isEmpty(data.ownfields))
		{
			for(var i in data.ownfields)
			{
				oTr = ce('TR', oTbody);
				ce('TD', oTr, {innerHTML: data.ownfields[i].type+':'});
				oTd = ce('TD', oTr, {innerHTML: data.ownfields[i].mdata});
				if(data.ownfields[i].note)
					oTd.innerHTML += ' <em>('+ data.ownfields[i].note +')</em>';
			}
		}
		//Глобальные поля собственного производства
		if(!isEmpty(data.ownfieldsG))
		{
			for(var i in data.ownfieldsG)
			{
				oTr = ce('TR', oTbody);
				ce('TD', oTr, {innerHTML: this.ownfieldsGlobal[i]+':'});
				oTd = ce('TD', oTr, {innerHTML: data.ownfieldsG[i].value});
				if(data.ownfieldsG[i].note)
					oTd.innerHTML += ' <em>('+ data.ownfieldsG[i].note +')</em>';
			}
		}
		if(data.note)
		{
			oTr = ce('TR', oTbody);
			ce('TD', oTr, {innerHTML: Locale['Notice'] +':'});
			ce('TD', oTr, {colSpan: 2, innerHTML: data.note});
		}
	
		mActionsInspector.addAction(this.id, this.workspaceId, 'showContactFull', {contactId: contact_id});
	}
}

//Отображение контактов, найденных по ключевому слову
__Addressbook.prototype.showContactsSearchedByKeyword = function(vars)
{
	de(this.fpanel.listContacts.byKeyword);
	this.fpanel.listContacts.byKeyword = ce('TBODY', this.fpanel.contactsByKeyword);

	if(!isEmpty(vars.results))
	{
		for(var i in vars.results)
		{
			this.showContact(i, 'byKeyword', '..'+ vars.results[i] +'..');
		}
	}
	this.allRecordsShowed = false;
}

//Отображение контактов, найденных по ключевому слову
__Addressbook.prototype.showContactsSearchedByLetter = function(letter)
{
	de(this.fpanel.listContacts.byLetter);
	this.fpanel.listContacts.byLetter = ce('TBODY', this.fpanel.contactsByLetter);

	if(letter)
	{
		letter = letter.toLowerCase();
		this.allRecordsShowed = false;
	}
	else
		this.allRecordsShowed = true;
	var flag = false;
	for(var i in this.dbLite)
	{
		var contact = this.dbLite[i];
		//Ищем по фамилии, если её нет - по имени, если нет ни фамилии, ни имени - по никнейму
		if(!letter || ((contact.sname && contact.sname.substr(0, 1).toLowerCase() == letter) ||
			(!contact.sname && contact.name && contact.name.substr(0, 1).toLowerCase() == letter) ||
			(!contact.sname && !contact.name && contact.nname && contact.nname.substr(0, 1).toLowerCase() == letter) ||
			(!contact.sname && !contact.name && !contact.nname && contact.mname && contact.mname.substr(0, 1).toLowerCase() == letter)
			))
		{
			this.showContact(i, 'byLetter');
			flag = true;
		}
	}
}

__Addressbook.prototype.initContactEdit = function(contact_id)
{
	Update.request('Addressbook', 'module', 'getContactFull', {id: this.id}, {id: contact_id, type: 'edit'}, true);
	this.createFormContactEdit('edit');
}

//Вывод дней рождений - предстоящих и прошедших
__Addressbook.prototype.processAnniversaries = function()
{
	//Отныне сервер вообще не утруждает себя вычислением годовщин, а просто отдаёт дату и номер дня в году. Всё перебираем здесь
	this.today = new Date();
	var self = this;
	this.fpanel.annivs.innerHTML = '';
	var oTable = ce('TABLE', this.fpanel.annivs, {className: 'wborder'}, {display: 'none', width: '100%', backgroundColor: '#FFFFFF'})
	var oTbody = ce('TBODY', oTable);

	this.today = new Date();
	var year_now = this.today.getFullYear();
	var ts_now = this.today.getTime();
	var tzo_now = this.today.getTimezoneOffset();

	var anniv = new Date();
	var doy_now = numOfDay(this.today.getDate(), this.today.getMonth()+1, this.today.getFullYear());
	var k = 0;
	var title = '';
	var flag = false;
	for(var i in this.dbLite)
	{
		if(this.dbLite[i].bdate)
			processDay(this.dbLite[i].bdate, this.dbLite[i].bdoy, i, true);
		if(this.dbLite[i].annivs && !isEmpty(this.dbLite[i].annivs))
		{
			for(var d in this.dbLite[i].annivs)
			{
				if(processDay(d, this.dbLite[i].annivs[d].doy, i, false) && !flag)
					flag = true;
			}
		}
	}
	if(flag)
		this.Tabs.show(this.tabIds.dates);

	//Обрабатывает конкретный день; надо для того, чтобы объединить обработку дней рождений и массива прочих годовщин
	function processDay(d, doy, cid, birthdayFlag)
	{
		var year = d.substr(0, 4)-0;
		var maxdays_now = maxdays(year_now);	//догадываюсь, что не очень правильно юзать переменные внешней функции, но зато всё будет работать быстро
		var maxdays_prev = maxdays(year_now-1);	//а для красоты можно и переделать будет

		if((doy_now + self.anniversaryRemindTerm) > maxdays_now)	//сейчас конец декабря
		{
			var term = 0 - (maxdays_now + doy - doy_now);	//для унификации предстоящие даты делаем отрицательными
		}
		else if((doy_now - self.anniversaryRemindTerm) < 1)	//сейчас начало января
		{
			var term = maxdays_prev + doy_now - doy;
		}
		else	//штатная ситуация
		{
			var term = doy_now - doy;
		}
	
		var year_is_leap = ((maxdays(year) == 366) ? true : false);
		var year_now_is_leap = ((maxdays_now == 366) ? true : false);
		if(year_now_is_leap && !year_is_leap && doy >= 60)	//1 марта или позднее
		{
			term--;
		}
		else if(!year_now_is_leap && year_is_leap && doy > 60)	//1 марта или позднее
		{
			term++;
		}
		var j = 0;
		if(Math.abs(term) > self.anniversaryRemindTerm)	//дата нам не подходит
			return false;
		else
		{
			if(oTbody.parentNode.style.display == 'none')
				oTbody.parentNode.style.display = '';
			if(year!=3000) var age = year_now - year;
			else var age = 3000;
			if(age) age = Math.abs(age);
			var oTr = ce('TR', oTbody);
			if(birthdayFlag)
				var tmp = 'cake.gif';
			else
				var tmp = 'bell.gif';
			var oTd = ce('TD', oTr, {innerHTML: '<img src="/img/addressbook/'+tmp+'" align="absmiddle" style="margin-right: 5px"/>'}, {verticalAlign: 'middle'});

			var oSpan = ce('SPAN', oTd, {cid: cid, className: 'href', onclick: showFC});
			if(self.dbLite[cid].sname) oSpan.innerHTML = self.dbLite[cid].sname;
			if(self.dbLite[cid].name) oSpan.innerHTML += ' '+ self.dbLite[cid].name.substr(0, 1) +'.';
			if(self.dbLite[cid].nname)
			{
				if(oSpan.innerHTML != '')
					oSpan.innerHTML += ' ('+ self.dbLite[cid].nname +')';
				else
					oSpan.innerHTML = self.dbLite[cid].nname;
			}
			if(year != '3000')
				tmp = '.'+ year;
			else
				tmp = '';
			ce('TD', oTr, {cid: cid, d: d, term: term, bdFlag: birthdayFlag, age: age, innerHTML: d.substr(8, 2) +'.'+ d.substr(5, 2) +tmp, onmouseover: showTip, onmouseout: hideTip}, {verticalAlign: 'middle'})
			return true;
		}
	}

	function maxdays(y)	//вычисляет кол-во дней в году
	{
		if((y%4==0) && (y%100!=0) || (y%400==0)) return 366;
		else return 365;
	}

	function showFC()
	{
		self.showContactFull(this.cid);
		Desktop.SetActiveByID('cMain', self.workspaceId);
	}

	function showTip(e)
	{
		e = e || window.event;
		t = '<strong>';
		if(this.bdFlag)
			t += Locale['Birthday'] +'</strong>';
		else
			t += self.dbLite[this.cid].annivs[this.d].title;
		t += '</strong>';
		if(this.age!=3000) t += '<br/>'+ this.age +'&nbsp;'+ self.lang['Anniversary'];
		t += '<br/><span style="color: #FF0401">';
		if(!this.term) t += '<strong>'+ Locale['Today'] +'!</strong>';
		else
		{
			var tmp = declineByNum(this.term, self.lang['Day'][0], self.lang['Day'][1], self.lang['Day'][2]);
			if(this.term < 0) t += Locale['Time']['in'] +' '+ Math.abs(this.term) +' '+ tmp;
			else t += Locale['Was'] +' '+ Math.abs(this.term) +' '+ tmp +' '+ Locale['Time']['ago'];
		}
		t += '</span>';
	
		Tooltip.Show(t, Event.element(e), 150, null, $('Module.'+self.id));
	}

	function hideTip()
	{
		Tooltip.Hide();
	}
}

__Addressbook.prototype.processAddOwnfield = function(fname)
{
	var self = this;
	Update.request('Addressbook', 'module', 'addOwnfieldG', {id: self.id}, {fname: fname}, true);
	self.finput.ownfieldsG.field.value = '';
}

//редактирование собственных полей
__Addressbook.prototype.initFormOwnGlobalFields = function()
{
	var self = this;
	this.TabsOptions.data[this.tabIds.ownfieldsG].content.innerHTML = '';
	this.finput.ownfieldsG = {};
	this.fpanel.formOwnfieldsG = ce('FORM', this.TabsOptions.data[this.tabIds.ownfieldsG].content);
	ce('DIV', this.fpanel.formOwnfieldsG);
	this.finput.ownfieldsG.field = ce('INPUT', this.fpanel.formOwnfieldsG, {id: self.id + '_inputOwnField'});
	ce('INPUT', this.fpanel.formOwnfieldsG, {type: 'submit', value: Locale['ToAdd'], className: 'std_button'});
	this.fpanel.ownfieldsGlobalList = ce('UL', ce('DIV', this.fpanel.formOwnfieldsG, {innerHTML: '<span></span>'}, {marginTop: '10px'}), null, {marginTop: '7px'});
	this.fpanel.formOwnfieldsG.onsubmit = function()
	{
		if(self.finput.ownfieldsG.field.value.length < 1)
			return false;
		else if(self.finput.ownfieldsG.field.value.length < 2)
		{
			window.alert(self.lang.msg['FieldNameMustContentNotLessThanSymbols'][0] +' <strong>2</strong> '+ self.lang.msg['FieldNameMustContentNotLessThanSymbols'][1]);
			self.finput.ownfieldsG.field.focus();
		}
		else
		{
			Update.request('Addressbook', 'module', 'addOwnfieldG', {id: self.id}, {fname: self.finput.ownfieldsG.field.value}, true);
			self.finput.ownfieldsG.field.value = '';
		}
		return false;
	}
}

//Отображает текущие собственные глобальные поля в соотв. форме
__Addressbook.prototype.updateOwnfieldsGlobalList = function()
{
	var self = this;
	if(isEmpty(this.ownfieldsGlobal))
	{
		this.fpanel.ownfieldsGlobalList.previousSibling.innerHTML = '';
		return;
	}
	else
	{
		this.fpanel.ownfieldsGlobalList.previousSibling.innerHTML = this.lang['CurrentFields'] +':';
	}
	var oInput = null;
	for(var i in this.ownfieldsGlobal)
	{
		var input_id = this.id +'_ownGlobalFieldsInput_'+ i;
		if(oInput = document.getElementById(input_id))
			de(oInput.parentNode);	//если такой товарищ уже есть, сносим его вместе с LI
		var oLi = ce('LI', this.fpanel.ownfieldsGlobalList, null, {listStyleType: 'none'});
		ce('IMG', oLi, {fid: i, onclick: delField, title: 'удалить', src: '/img/icons/x2.gif', className: 'href'});

		oInput = ce('INPUT', oLi, {type: 'text', value: this.ownfieldsGlobal[i], fid: i, readOnly: true, id: input_id}, {marginLeft: '5px'});
		oInput.onfocus = function() {makeEditable(this, true)}
		oInput.onblur = function() {var t = this; self.timers.t1 = window.setTimeout(function() {makeEditable(t, false)}, 500)}
	}

	function delField()
	{
		if(window.confirm(self.lang.msg['SureToDeleteField']))
		{
			Update.request('Addressbook', 'module', 'delOwnfieldG', {id: self.id}, {fid: this.fid}, true);
			delete self.ownfieldsGlobal[this.fid];
			de(this.parentNode);
		}
	}
	function makeEditable(oInput, flag)
	{
		oInput.readOnly = !flag;
		btn_id = self.id +'_ownGlobalFieldsEditBtn'+ oInput.fid;
		if(flag)
		{
			if(!document.getElementById(btn_id))
				ce('INPUT', oInput.parentNode, {type: 'button', 'className': 'std_button', value: 'Cохр.', id: btn_id, 
					onclick: function() {
						if(self.ownfieldsGlobal[oInput.fid] != oInput.value)
						{
							if(oInput.value.length < 2)
								window.alert(self.lang.msg['FieldNameMustContentNotLessThanSymbols'][0] +' <strong>2</strong> '+ self.lang.msg['FieldNameMustContentNotLessThanSymbols'][1]);
							else
							{
								self.ownfieldsGlobal[oInput.fid] = oInput.value;
								Update.request('Addressbook', 'module', 'editOwnfieldG', {id: self.id}, {fid: oInput.fid, fname: oInput.value}, false);
//								window.alert('Поле отредактировано');
							}
						}
						return false;
					}});
		}
		else
		{
			de(document.getElementById(btn_id));
		}
	}
}

//Пытается инициализировать переменную объектом гаджета Email
__Addressbook.prototype.tryInitEmailGadgetObject = function()
{	//Надо как-то будет учесть, если Email-гаджет вдруг снесут
	if(this.oEmailGadget)
		return true;
	else
	{
		for(var i in Modules)
		{
			if(Modules[i].Object.type == 'EMail')
			{
				this.oEmailGadget = Modules[i].Object;
				return true;
			}
		}
	}
	return false;
}

//Все гиперссылки типа mailto пытаемся отправить в гаджет
__Addressbook.prototype.emailOnclick = function(href)
{
	if(this.tryInitEmailGadgetObject())
	{
		this.oEmailGadget.prepareNewMessageForm(href.substr(7));
		return false;
	}
	else
		return true;	//mailto будет обработан стандартным образом
}

__Addressbook.prototype.onTabDelete = function()
{
	if(this.workspace)
	{
		this.workspace = null;
		this.workspaceId = null;
	}
}