function TV_MultiSelect(source, options) {

	var TV_MultiSelect = this;

	options.prefix = options.prefix || {};
	options.hold = options.hold || {};

	var options = {
		max_elements:	options.max_elements == 0 || options.max_elements > 0 ? options.max_elements : 5,
		skip_nodes:		options.skip_nodes || [],
		single:			options.single || false,
		autoselect:		options.autoselect || false,
		method:			options.method || 'POST',
		action:			options.action || 'get_sections',
		prefix: {
			link:		options.prefix.link 	|| 'sa_',
			alink:		options.prefix.alink 	|| 'sal_',
			element:	options.prefix.element	|| 'se_'
		},
		hold: {
			ui_list:	options.hold.ui_list 	|| 'ui_sections',
			list:		options.hold.list 		|| 'sections',
			holder:		options.hold.holder 	|| 'holder_'+$('.TV_MultiSelectHolder').size()+'_'
		}
	};

	var selected_nodes = [];
	var current_nodes = [];
	var separator = ' » ';
	var source = source;

	var active = false;
	var cache = {};

	options.hold.holder += String(new Date().getMilliseconds());
	document.write('<input type="hidden" name="'+options.hold.list+'" id="'+options.hold.list+'" value="" />');
	document.write('<ol style="margin:5px;padding: 0px 0px 15px 17px;display:none" id="'+options.hold.ui_list+'"></ol>');
	document.write('<span id="'+options.hold.holder+'" class="TV_MultiSelectHolder"></span>');

	var $list = $('#'+options.hold.list);
	var $ui_list = $('#'+options.hold.ui_list);
	var $holder = $('#'+options.hold.holder);

	this.choose = function(id, remember) {

		if ( remember === true )
			selected_nodes.push(id);

		if (remember !== true) {
			selected_nodes = $.grep(selected_nodes,
				function(n) {
					return id != n;
				}
			);
		}
		$list.val(selected_nodes);
	}

	this.render_sections = function(sections) {

		if ( !sections || !sections.length )
			return;

		for (var n=0; n<sections.length; n++ ) {

			if ( !sections[n].nodes || !sections[n].nodes.length )
				continue;

			if ( options.max_elements > 0 && selected_nodes.length+1 > options.max_elements)
				continue;

			var parent = sections[n].id;
			this.choose(parent, true);

			var el_list = $('<li></li>').attr(
				'id', options.prefix.element+parent
			);

			for (var e=0; e<sections[n].nodes.length; e++ ) {
				el_list.html(el_list.html()+sections[n].nodes[e].name);

				if ( sections[n].nodes.length-1 == e && sections[n].nodes[e].path)
					el_list.html(el_list.html()+(sections[n].nodes[e].path ? ' ('+sections[n].nodes[e].path+')' : ''));

				if ( sections[n].nodes.length-1 != e )
					el_list.html(el_list.html()+separator);
			}

			el_list.append(
				$('<a></a>').attr({
					title: 'Удалить',
					href: 'javascript:void(0)'
				}).html(
					'<img src="/_img/themes/frameworks/jquery/treeview/bullet_delete.gif" alt="Удалить" border="0" hspace="4"  style="vertical-align:middle">'
				).bind(
					'click',
					{el_list: el_list, parent: parent},
					function(e) {
						e.data.el_list.remove();
						TV_MultiSelect.choose(e.data.parent, false);

						if ( selected_nodes.length == 0)
							$ui_list.hide();
					}
				)
			);
			$ui_list.append(el_list);
			$ui_list.show();
		}
	}

	this.get_sections = function(parent) {

		if ( cache[parent] )
			return this.show_list(parent,  cache[parent]);

		active = true;

		$.ajax({
            type:	options.method,
            url:	source,
            data: {
				action: options.action,
				parent: parent,
				skip_nodes: String(options.skip_nodes)
			},
            error: function(data) {
				alert('Не удалось получить список.');

				if ( current_nodes.length ) {
					var $parent_id = current_nodes[current_nodes.length-1].parent;
					$('#'+options.prefix.link+$parent_id).trigger('click');
				}
			},
            success: function(data) {
				TV_MultiSelect.show_list(parent, data);
			},
			dataType: 'json'
        });

		active = false;
	};

	this.render_current = function() {

		$holder.empty();
		$.map(current_nodes, function(section, i) {

			var $link = $('<a></a>').attr({
				id: options.prefix.link+section.parent,
				href: 'javascript:void(0)'
			}).html(section.name).bind(
				'click', {
					id: section.parent
				}, function(e) {

					if ( active )
						return;

					var sections = [];
					for (var s=0; s<current_nodes.length;s++) {
						if ( current_nodes[s].parent == e.data.id )
							break;
						sections.push(current_nodes[s]);
					}

					current_nodes = sections;
					TV_MultiSelect.render_current();
					TV_MultiSelect.get_sections(section.parent);
				}
			);

			$holder.append($link);

			if (i < current_nodes.length-1)
				$holder.append(separator);
		});
	}

	this.show_list = function(parent, data)
	{

		var select = $('<select></select>');

		select[0].length = data.list.length + 1;
		select[0].options[0].value = 0;

		if (current_nodes.length && options.single)
			select[0].options[0].text = ' - Все - ';
		else
			select[0].options[0].text = ' - Выберите раздел - ';

		for (var i = 1; i <= data.list.length; i++)
		{
			select[0].options[i].value = data.list[i - 1].id;
			select[0].options[i].text = data.list[i - 1].name;
			if (data.list[i - 1].type != 1)
				select[0].options[i].text = select[0].options[i].text + (data.list[i - 1].path ? ' (' + data.list[i - 1].path + ')' : '');
			select[0].options[i].last = data.list[i - 1].last;
		}

		cache[parent] = data;
		if ( current_nodes.length )
			$holder.append(separator);
		$holder.append(select);

		if ( options.single )
			this.append_add_link();

		select.bind(
			'change', function(e) {
				$(this).each(function() {
					var $value = this.options[this.selectedIndex].value;
					var $name = this.options[this.selectedIndex].text;
					var $last = this.options[this.selectedIndex].last;

					current_nodes.push({
						id:		$value,
						parent:	parent,
						name:	$name,
						last:	$last
					});

					TV_MultiSelect.render_current();
					if ( !$last )
						TV_MultiSelect.get_sections($value);
					else
					{
						if (options.autoselect == true)
							TV_MultiSelect.add_item();
						else
							TV_MultiSelect.append_add_link();
					}
					$(this).remove();
				});
			}
		);
	};

	this.append_add_link = function() {
		if ( !current_nodes.length )
			return;

		var $current_id = current_nodes[current_nodes.length-1].id;
		if ( $('#'+options.prefix.element+$current_id, $ui_list).size() )
			return;


		$holder.append(separator);

		$holder.append($('<a></a>').attr({
				title: 'Добавить',
				href: 'javascript:void(0)'
			}
			).css({
				margin: '0px 0px 0px 10px',
				whiteSpace: 'nowrap'
			}).html(
				'<img src="/_img/themes/frameworks/jquery/treeview/bullet_add.gif" alt="Добавить" border="0" hspace="4" style="vertical-align:middle">Добавить'
			).bind('click',this.add_item));
	}

	this.add_item = function(e) {
		if ( options.max_elements > 0 && selected_nodes.length >= options.max_elements) {
			alert('Максимальное количество элементов: '+options.max_elements);
			return;
		}

		var $parent_id = current_nodes[current_nodes.length-1].parent;
		var $current_id = current_nodes[current_nodes.length-1].id;

		var el_list = $('<li></li>').attr(
			'id', options.prefix.element+$current_id
		);

		$ui_list.append(el_list);

		for (var s=0; s<current_nodes.length;s++) {
			el_list.append(current_nodes[s].name);

			if ( s != current_nodes.length-1 )
				el_list.append(separator);
		}

		el_list.append(
			$('<a></a>').attr({
				title: 'Удалить',
				href: 'javascript:void(0)'
			}).html(
				'<img src="/_img/themes/frameworks/jquery/treeview/bullet_delete.gif" alt="Удалить" border="0" hspace="4"  style="vertical-align:middle">'
			).bind(
				'click',
				function(e) {
					el_list.remove();
					TV_MultiSelect.choose($current_id, false);

					if ( selected_nodes.length == 0)
						$ui_list.hide();
				}
			)
		);

		$ui_list.show();
		TV_MultiSelect.choose($current_id, true);
		$('#'+options.prefix.link+$parent_id).trigger('click');
	}

}

