function commentFormClass(options) {

	var FormClass = this;
	var defaults = {
		url: window.baseURL,
		expand: window.location.hash,

		FormHolderNum: 'js-comments-form-holder-',
		FormHolder: 'js-comments-form-holder',
		FormStatusHolder: 'js-comments-status-holder',
		FormCaptchaHolder: 'js-comments-captcha-holder',

		fieldHolder: 'js-comments-field-holder',
		fieldData: 'js-comments-field-data',

		fieldUserID: 'js-comments-field-userid',
		fieldParentID: 'js-comments-field-parentid',
		fieldName: 'js-comments-field-name',
		fieldNameText: 'js-comments-field-name-text',
		fieldText: 'js-comments-field-text',
		fieldGuest: 'js-comments-field-guest',
		fieldCaptcha: 'js-comments-field-captcha',
		fieldSubmit: 'js-comments-field-submit',

		pagesLoading: 'js-comments-pages-loading',
		pagesLink: 'js-comments-pages-link',

		isLoading: 'js-comments-loading-',
		commentVoteCount: 'js-comments-vote-count-',
		commentVote: 'js-comments-vote-',

		commentVoteBestCount: 'js-comments-vote-best-count-',
		commentVoteBest: 'js-comments-vote-best-',

		VotenNS: 'ns',
		VotenS: 's',

		commentsHName: 'js-comment',
		commentsList: 'js-comment-list',
		commentsCount: 'js-comments-count',
		commentsAnnounce: 'js-comments-announce-',
		commentsTree: 'js-comments-tree-',
		commentItem: 'js-comment-holder-',
		commentItemChildsLink: 'js-comment-childs-link-',
		commentItemChilds: 'js-comment-childs-holder-',
		commentItemChildsCount: 'js-comment-childs-count-'
	};

	var opts = $.extend({}, defaults, options);
	var inAction = false;

	$(document).ready (function() {
		if (opts.expand.search(/^#comment(\d+)$/) != -1) {

			var id = opts.expand.replace(/^#comment(\d+)$/,'$1');
			$('a[class^="'+opts.commentItemChildsLink+'"]:visible',
				$('.'+opts.commentItem+id).parents('ul:last')
			).trigger('click');

			window.location.href = opts.expand;
		}
	});

	this.moveForm = function(cid) {

		if ( inAction ) {
			ShowSystemMessage('Пожалуйста, подождите...');
			return ;
		}

		var form = $('.'+opts.FormHolder);
		var container = $('.'+opts.FormHolderNum+cid.toString());


		if ( form.size() && form.get(0).parentNode.className != container.attr('class') ) {
			container.html('');
			container.append(form);
			container.hide();


			container.attr('margin-left: 0px');
			if (cid > 0)
				container.css('margin-left','20px');

			$(
				'.'+opts.fieldParentID,
				$('.'+opts.fieldData)
			).val(cid);
		}

		if ( $('.'+opts.fieldSubmit).attr('disabled') ) {
			this.enableForm();
			container.show();

		} else
			container.toggle();
		if (container.css('display') == 'none') {
			$('.add-comment a.dashed-border').text('Добавить комментарий');
		} else {
			$('.add-comment a.dashed-border').text('Скрыть форму');
		}
	}

	this.enableForm = function() {

		var form = $('.'+opts.FormHolder);
		$('.'+opts.fieldSubmit, form).attr('disabled', false);
		$('.'+opts.FormStatusHolder).hide();
		$('.'+opts.fieldText, form).val('');
		$('.'+opts.fieldHolder).show();
	}

	this.disableForm = function() {

		$('.'+opts.fieldSubmit).attr('disabled', true);
		$('.'+opts.FormStatusHolder).hide();
		$('.'+opts.fieldHolder).hide();
	}

	this.expandAll = function(id) {

		var self = this;
		$('.'+opts.commentsAnnounce+id).hide();
		$('.'+opts.commentsTree+id).show();
		$('.'+opts.commentItemChilds+id).toggleClass('holder');

		$('.'+opts.commentItemChildsLink+id+':first').hide();
		$('.'+opts.commentItemChildsLink+id+':last').show();
	}

	this.collapseAll = function(id) {

		var self = this;
		$('.'+opts.commentsAnnounce+id).show();
		$('.'+opts.commentsTree+id).hide();
		$('.'+opts.commentItemChilds+id).toggleClass('holder');

		$('.'+opts.commentItemChildsLink+id+':first').show();
		$('.'+opts.commentItemChildsLink+id+':last').hide();
	}

	this.showChilds = function(id, _this) {
		if ( inAction ) {
			ShowSystemMessage('Пожалуйста, подождите...');
			return ;
		}

		$('.'+opts.isLoading+id).show();

		inAction = true;
		$.ajax(
			{
				url: opts.url,
				dataType: 'json',
				data: {
					action:'comment_childs',
					'id': id
				},
				success: function(data) { successChilds(data, _this, id); },
				error: function() { errorChilds(id); },
				type: 'POST'
				//async: true,
				//timeout: 5000
			}
		);
		return false;
	}

	this.getPage = function(p, edit, id) {
		if ( inAction ) {
			ShowSystemMessage('Пожалуйста, подождите...');
			return false;
		}

		this.moveForm(0);
		this.enableForm();
		//$('.'+opts.FormHolderNum+'0').hide();

		$('.'+opts.pagesLoading).show();
		$('.'+opts.pagesLink).hide();

		inAction = true;
		$.ajax(
			{
				url: opts.url,
				dataType: 'json',
				data: {
					action:'comment_page',
					'p': p
				},
				success: function(data) {

					inAction = false;
					if (data.status == 'ok') {

						if ( data.data )
							$('.'+opts.commentsList).html(
								data.data
							);

					}
					$('.'+opts.pagesLoading).hide();

					window.location.href = '#'+opts.commentsHName;

					if ( edit === true )
						successEdit({status: 'ok', id: id}, true);
				},
				error: function() {
					inAction = false;
					ShowSystemMessage('Не удалось получить страницу.');
					$('.'+opts.pagesLoading).hide();
					$('.'+opts.pagesLink).show();
				},
				type: 'POST'
				//async: true,
				//timeout: 5000
			}
		);
		return false;
	}

	this.Vote = function(id, result) {

		$.ajax(
			{
				url: opts.url,
				dataType: 'json',
				data: {
					'action': 'comment_vote',
					'id': id,
					'result': result
				},
				success: function(data) { successVote(data, id); },
				error: errorVote,
				type: 'POST'
				//async: true,
				//timeout: 5000
			}
		);
		return false;
	}

	this.Delete = function(id)
	{
		if ( inAction ) {
			ShowSystemMessage('Пожалуйста, подождите...');
			return false;
		}

		inAction = true;
		$.ajax(
			{
				url: opts.url,
				dataType: 'json',
				data: {
					'action': 'comment_delete',
					'id': id
				},
				success: function(data) {
					inAction = false;
					successDelete(data, id);
				},
				error: function() {
					inAction = false;
				},
				type: 'POST'
				//async: true,
				//timeout: 5000
			}
		);
		return false;
	}

	this.checkForm = function() {

		var form = $('.'+opts.FormHolder);

		var UserID = $('.'+opts.fieldUserID, form);
		var Name = $('.'+opts.fieldName, form);
		var Guest = $('.'+opts.fieldGuest+':checked', form);

		if ( (UserID.val() <= 0 || Guest.val() == 1) && this.isEmptyForm( Name.val() ))
		{
			alert('Пожалуйста, введите имя.');
			Name.get(0).focus();
			return false;
		}

		var Text = $('.'+opts.fieldText, form);
		if ( this.isEmptyForm( Text.val() ) )
		{
			alert('Вы не написали сообщение!');
			Text.get(0).focus();
			return false;
		}

		if ( Text.val().length < 1)
		{
			alert('Ваше сообщение слишком короткое.');
			Text.get(0).focus();
			return false;
		}

		if ( Text.val().length > 2000 )
		{
			alert('Ваше сообщение слишком большое. Максимальная длина - 2000 знаков.');
			Text.get(0).focus();
			return false;
		}

		var Captcha = $('.'+opts.fieldCaptcha, form);
		if ( Captcha.size() && Captcha.val().length == 0 ) {
			alert('Необходимо ввести код');
			Captcha.get(0).focus();
			return false;
		}

		$('.'+opts.fieldSubmit).attr('disabled', true);

		inAction = true;
		var ParentID = $('.'+opts.fieldParentID, form).val();
		$.ajax(
			{
				url: opts.url,
				dataType: 'json',
				data: {
					action:'comments_edit',
					Text: Text.val(),
					Name: Name.val(),
					ParentID: ParentID,
					captcha_code: Captcha.val()
				},
				success: successEdit,
				error: errorEdit,
				type: 'POST'
			}
		);
		return false;
	}

	this.isEmptyForm = function (val) {

		if ( val.length == 0 )
			return true;

		var ch;
		for (var i=0; i<val.length; i++){
			ch = val.charAt(i);
			if (ch!=" " && ch!="\n" && ch!="\t" && ch!="\r")
				return false;
		}
		return true;
	}

	this.Guest = function() {

		var form = $('.'+opts.FormHolder);
		var Guest = $('.'+opts.fieldGuest, form);
		var fieldName = $('.'+opts.fieldName, form);
		var fieldNameText = $('.'+opts.fieldNameText, form);
		if ( Guest.get(0).checked ) {
			fieldName.val('');
			fieldName.show();
			fieldNameText.hide();
		} else {
			fieldName.val('');
			fieldName.hide();
			fieldNameText.show();
		}

	}

	var successEdit = function(data, loaded) {
		inAction = false;

		if(data.status == 'ok')
		{
			if (data.id && data.parent == 0 && loaded !== true) {
				FormClass.getPage(0, true, data.id);
			} else if ( loaded === true ) {
				var commentsCount = $('.'+opts.commentsCount);
				$('.'+opts.FormStatusHolder).show();
				$('.'+opts.fieldHolder).hide();
				//$('.'+opts.FormHolderNum+'0').show();

				window.location.href = '#comment'+data.id;

			} else {

				var commentsCount = $('.'+opts.commentsCount);
				$('.'+opts.FormStatusHolder).show();
				$('.'+opts.fieldHolder).hide();

				if ( data.content )
					commentsCount.html(parseInt(commentsCount.html())+1);

				if ( data.childscount > 0 || data.parent == 0 ) {
					$('.'+opts.commentItemChilds+data.parent).append(data.content);
					$('.'+opts.commentItemChilds+data.parent).show();
				}

				if ( data.parent > 0 )
					$('.'+opts.commentItemChildsCount+data.parent).html(data.childscount);
			}

			$('.add-comment a.dashed-border').text('Добавить комментарий');
		} else if( data.status == 'error' ) {
			$('.'+opts.fieldSubmit).attr('disabled', false);
		}

		if ( data.captcha ) {
			$('.'+opts.FormCaptchaHolder).attr('src', data.captcha+"?r="+Math.random());
			$('.'+opts.fieldCaptcha, $('.'+opts.FormHolder)).val('');
		}

		if ( data.message )
			ShowSystemMessage(data.message);
	}

	var errorEdit = function() {
		inAction = false;
		ShowSystemMessage('Не удалось добавить комментарий');
		$('.'+opts.fieldSubmit).attr('disabled', false);
	}

	var successChilds = function(data, _this, id) {
		inAction = false;

		if (data.status == 'ok') {

			var childs = $('.'+opts.commentItemChilds+id);

			childs.empty();
			childs.append(data.content);
			childs.show();

			if ( typeof(_this) != 'undefined' && _this.parentNode) {
				$(_this.parentNode).append($(_this).html());
				$(_this).remove();
			}
		}
		$('.'+opts.isLoading+id).hide();
	}

	var errorChilds = function(id) {
		inAction = false;
		ShowSystemMessage('Не удалось получить ответы');
		$('.'+opts.isLoading+id).hide();
	}

	var successVote = function(data, id) {

		if (data.status == 'ok')
		{
			var VoteCount = $('.'+opts.commentVoteCount+id);
			var VoteBestCount = $('.'+opts.commentVoteBestCount+id);

			VoteCount.html(data.data > 0 ? '+'+data.data : data.data);
			VoteBestCount.html(data.data > 0 ? '+'+data.data : data.data);
			VoteCount.removeClass(opts.VotenNS).removeClass(opts.VotenS);
			VoteBestCount.removeClass(opts.VotenNS).removeClass(opts.VotenS);

			if ( data.data < 0 ) {
				VoteCount.addClass(opts.VotenNS);
				VoteBestCount.addClass(opts.VotenNS);
			} else if ( data.data > 0 ) {
				VoteCount.addClass(opts.VotenS);
				VoteBestCount.addClass(opts.VotenS);
			}

			$('.'+opts.commentVote+id).empty();
			$('.'+opts.commentVoteBest+id).empty();

			if ( data.message )
				ShowSystemMessage(data.message);
		}
		else if (data.status == 'error')
		{
			if ( data.message )
				ShowSystemMessage(data.message);
			$('.'+opts.commentVote+id).empty();
		}
	}

	var errorVote = function() {
		ShowSystemMessage('Ошибка голосования');
	}

	var successDelete = function(data, id) {
		if (data.status == 'ok') {
			if ( data.message )
				ShowSystemMessage(data.message);

			var list = $('li[class*="'+opts.commentItemChilds+'"]');
			var count = $('.'+opts.commentsCount);
			var flag_reduced = false;

			for(var idx=0;idx<list.length;idx++) {
				var items = $('.'+opts.commentItem+id, list[idx]);
				if ( !items || !items.length)
					continue ;

				//var count = $('.'+opts.commentItemChildsCount+list[idx].className.replace(/[^0-9]+/,'')); WTF is that?
				if ( count.html() > 0 ) {
					count.html( (count.html() - items.length).toString() );
				}

				flag_reduced = true;
				break;
			}

			$('.'+opts.commentItem+id).remove();
			if (!flag_reduced) {
				count.html( (count.html() - 1).toString() );
			}

			//$('.'+opts.commentItemChilds+id).remove();

		} else if (data.status == 'error') {
			if ( data.message )
				ShowSystemMessage(data.message);
		}
	}
}

function ShowSystemMessage(text) {
	if ( typeof(sys_timer) != 'undefined' )
		clearTimeout(sys_timer);

	SystemMessageResize();
	$('#system_message').hide();
	$('#system_message').html(text);
	$('#system_message').show('slow', function() {
	});
	sys_timer = setTimeout("ShowSystemMessageHide()", 3000);
}

function ShowSystemMessageHide()
{
	$('#system_message').hide('slow', function() {
	});
	sys_timer = clearTimeout(sys_timer);
}

function SystemMessageResize()
{
	if ($.browser.msie)
		$('#system_message').css('top', document.body.scrollTop + "px");
}

$(window).resize(function()
{
	SystemMessageResize();
});
$(window).scroll(function()
{
	SystemMessageResize();
});

