function cssDragDropMenu (ulid, options) {
	var menu = $(ulid);
	
	menu.options = Object.extend({
	draggableclass:   		'',
	draghandleclass:		'',
    folderclass:      		'',
	draggedclass:     		'',
	dragoverclass:			'',
	newsubmenudummyclass:	'', 
    newsubmenudummytext:  	'Drop here', 
	
	irrelevantclass:		'', 
	irrelevantfolderclass:	'',
	irrelevantopenclass:	'', 
	irrelevantoverclass:	'', 
    
	isFolder:	function(lie,def)	{return def;},
	
	onChange:	function(lie) 	{return;}, // should be reall callback (user should have possibility to cancel action)
	
	isDropable:	function(lie,parent,before,after,def)	{return def;},
	
	onStartDragging: function (lie, ule) {return;}, // should be reall callback (user should have possibility to cancel action)
	onEndDragging: function (lie, ule, index) {return;},  // should be reall callback (user should have possibility to cancel action)
	timeout: 200
    }, arguments[1] || { });
	
	var randommark = '_' + ulid + '_' + Math.round(1000000000*Math.random());
	if (!menu.options.newsubmenudummyclass) menu.options.newsubmenudummyclass = 'newsubmenudummyclass' + randommark;
	if (!menu.options.openedclass) menu.options.openedclass = 'openedclass' + randommark;
	if (!menu.options.irrelevantclass) menu.options.irrelevantclass = 'irrelevantclass' + randommark;
	if (!menu.options.irrelevantfolderclass) menu.options.irrelevantfolderclass = 'irrelevantfolderclass' + randommark;
	if (!menu.options.irrelevantopenclass) menu.options.irrelevantopenclass = 'irrelevantopenclass' + randommark;
	if (!menu.options.irrelevantoverclass) menu.options.irrelevantoverclass = 'irrelevantoverclass' + randommark;

	menu.menuout = true;
	menu.froze = false;
	menu.ulvisibledummyli = null;
	menu.currentli = null;
	menu.dragged = false;
	menu.timer = null;
	
	menu.dragParentLI = null;
	menu.dragNextLI = null;
	menu.dragParentLI = null;
	
	menu.removeItem = function(lie) {
		if ($(lie)) {
			var tmp = $(lie).parentNode;
			$(lie).remove();
			if (menu.options.folderclass) this.setULFolderClass(tmp);
			}
		}
		
	menu.addItem = function(itemcontent,elem,position) {
		elem = $(elem);
		if (!elem) return;
		if (elem.nodeName=='LI') {
			if (position=='top') elem.insert({'before': itemcontent});
			else elem.insert({'after': itemcontent});
			par = elem.parentNode;
			}
		if (elem.nodeName=='UL') {
			if (position=='top') elem.insert({'top': itemcontent});
			else elem.insert({'bottom': itemcontent});
			par = elem;
			}
		
		if (menu.options.folderclass) this.setULFolderClass(par);
		if (this.sortableCreated) {
			par.select('li').each(this.createDummyUL);
			par.select('ul').each(this.createDummyLI);		
			this.createSortable();
			}
		}
	
	menu.showDummyLI = function(ule) {
		if (this.ulvisibledummyli) this.hideDummyLI();
		var dummyli=ule.down("li."+menu.options.newsubmenudummyclass);//find(function (childe) { return ( (childe.nodeName=='LI') && childe.hasClassName(menu.options.newsubmenudummyclass)); } );
		if (!dummyli || !(dummyli.parentNode==ule)) return;
		var otherli=ule.childElements().find(function (childe) { return ((childe.nodeName=='LI') && childe.hasClassName(menu.options.draggableclass) && !childe.hasClassName(menu.options.irrelevantclass) && !childe.hasClassName(menu.options.newsubmenudummyclass) && childe.visible() ) } ) ;
		if (otherli) {
			this.ulvisibledummyli = null;
			dummyli.hide();
			}
		else {
			this.ulvisibledummyli = dummyli;
			dummyli.show();
			}
		};
		
	menu.hideDummyLI = function() {
		if (this.ulvisibledummyli) 
			this.ulvisibledummyli.hide();
		this.ulvisibledummyli = null;
		}	
	
	menu.dragOverLi = function(newe) {
		var olde = this.currentli;
		if (olde) {
			if (olde!=newe) olde.removeClassName(this.options.dragoverclass);
			if ( (!newe || !newe.descendantOf(olde)) && olde.descendantOf(this) && (tmp=olde.down('ul'))) 
				{
				tmp.removeClassName('forceopened');
				this.hideDummyLI();
				}
			// close old opened LI if new is NOT child of old.
			olde.ancestors().find(function (ae) {
				if (!ae.descendantOf(menu)) return true;
				if ((ae.nodeName=='LI') && !(newe && newe.descendantOf(ae)) && (tmp=ae.down('ul'))) tmp.removeClassName('forceopened');
				return false;
				} );
			// if old LI opened close ancestors
			}

		if (newe) {
			newe.ancestors().reverse().find(function (ae) {
				// if (!ae.descendantOf(menu)) return true;
				if ( ae.descendantOf(menu) && (ae.nodeName=='LI')  && (tmp=newe.down('ul') ) ) tmp.addClassName('forceopened');
				return false;
				} );
			tmp = newe.down('ul');
			if (tmp.parentNode==newe)
				this.showDummyLI(tmp);
			if (tmp=newe.down('ul')) tmp.addClassName('forceopened'); 
			newe.addClassName(this.options.dragoverclass);
			}
		else {
			this.hideDummyLI();
			}
		this.currentli = newe;
		};
	
	
	menu.setULFolderClass = function(ule) {
		if (!ule || !this.options.folderclass || !(tmp=ule.up('li')) || (!tmp.descendantOf(this)) ) return;
		var tmpval=ule.childElements().any(function (childe) {
				return ( (childe.nodeName=='LI') && childe.visible() && !childe.hasClassName(menu.options.irrelevantfolderclass) && !childe.hasClassName(menu.options.irrelevantclass) );
				});
		var tmpret=this.options.isFolder(tmp,tmpval);
		if ((tmpret===true) || ((tmpret!==false) && tmpval))
			tmp.addClassName(this.options.folderclass);
		else 
			tmp.removeClassName(this.options.folderclass);
		}
	
	
	menu.startDragging = function (lie) {
		this.oldule = lie.up('ul');
		this.options.onStartDragging(lie, this.oldule);

		this.dragParentLI = lie.parentNode;
		this.dragNextLI = lie.previousSiblings().find(function (childe) {
				return (lie.nodeName=='LI') && !lie.hasClassName(menu.options.newsubmenudummyclass) && !lie.hasClassName(menu.options.irrelevantclass) && lie.visible();
				} ) || null;
		this.dragParentLI = lie.nextSiblings().find(function (childe) {
				return (lie.nodeName=='LI') && !lie.hasClassName(menu.options.newsubmenudummyclass) && !lie.hasClassName(menu.options.irrelevantclass) && lie.visible();
				} ) || null;
		this.dragging = true;
	/*	this.dragging = true;
		this.menuout = false;
		var tmp = lie.up('li');//ancestors().find(function (el) {return (el.nodeName=='LI');});
		tmp = tmp?tmp:null;
		this.changeItem(tmp);*/
		if (tmp=lie.down('ul')) tmp.hide();
		lie.addClassName(this.options.draggedclass);
		};
		
	menu.endDragging = function (lie) {
		this.dragOverLi(null);
		lie.removeClassName(this.options.draggedclass);
		if (tmp=lie.down('ul')) tmp.show();
		this.dragging = false;
		/*this.changeItem(null);
		this.dragging = false;
		this.menuout = false;
		this.changeItem(lie);*/
		var tmp = lie.parentNode;
		this.setULFolderClass(this.oldule);
		this.setULFolderClass(tmp);
		/*var position = 0;
		var positionfound = false;*/
		this.options.onEndDragging(lie,tmp,tmp.childElements().findAll(function (childe) 
			{ return (!childe.hasClassName(menu.options.newsubmenudummyclass) && (childe.nodeName=='LI') ); }).indexOf(lie));
		};
		
	menu.createDummyUL = function(lie) {
		var tmp = lie.down('ul');
		if (!tmp || !(tmp.parentNode==lie))
			lie.insert({ top: '<ul style="display: none;" class="" id="'+lie.id.replace(/li_/,'ul_')+'"></ul>'});
		}
	
	menu.createDummyLI = function(ule) {
		ule.insert({ top: '<li style="display: none;" id="cssDragDropMenuHiddenDummy_' + ule.id + '" class="' + menu.options.draggableclass + ' ' + menu.options.newsubmenudummyclass + ' ' + menu.options.irrelevantfolderclass + '">' + menu.options.newsubmenudummytext + '</li>'});
		}
		
	
	menu.sortableCreated = false;
	
	menu.createSortable = function()
		{
		if (!Sortable.onHover_old) {
			Sortable.onHover_old = Sortable.onHover;

			Sortable.onHover = function (element, dropon, overlap) {
				if(Element.isParent(dropon, element)) return;
				if(overlap > .33 && overlap < .66 && Sortable.options(dropon).tree) return;
				var tmpmenu = Sortable._findRootElement(element);
				var nextelement = null;
				var prevelement = null;
				var parentelement = dropon.parentNode;
				
				var notFakeLI = function (lie) {
					return (lie.nodeName=='LI') && !lie.hasClassName(tmpmenu.options.newsubmenudummyclass) && !lie.hasClassName(tmpmenu.options.irrelevantclass) && lie.visible();
					}
					
				var realprevelement = dropon.previousSiblings().find(notFakeLI) || null;
				var realnextelement = dropon.nextSiblings().find(notFakeLI) || null;
				
				if (overlap>0.5) {
					nextelement = notFakeLI(dropon)?dropon:realnextelement;
					prevelement = realprevelement;
				  }
				else {
					nextelement = realnextelement;
					prevelement = notFakeLI(dropon)?dropon:realprevelement;
				  }

				if ((prevelement!=tmpmenu.dragPrevLI) || (nextelement!=tmpmenu.dragNextLI) || (parentelement!=tmpmenu.dragParentLI)) {
					var tmpval=true;
					var tmpret=tmpmenu.options.isDropable(element,parentelement,prevelement,nextelement,tmpval);
					if ((tmpret===true) || ((tmpret!==false) && tmpval)) {
						tmpmenu.dragPrevLI = prevelement;
						tmpmenu.dragNextLI = nextelement;
						tmpmenu.dragParentLI = parentelement;
						Sortable.onHover_old(element, dropon, overlap);
						}
					if (!dropon.hasClassName(tmpmenu.options.newsubmenudummyclass)) 
						tmpmenu.dragOverLi(dropon);
					else 
						tmpmenu.showDummyLI(dropon.parentNode);
					}
				}
			}

		if (Prototype.Browser.Opera) $(ulid).select('li.' + menu.options.draggableclass).each(function (el) {el.style.position='static';} );
		
		Sortable.create(menu.id,
						{
						handle: menu.options.draghandleclass,
						only: menu.options.draggableclass,
						ghosting: false, 
						constraint: false,
						starteffect: function (e) {
							menu.startDragging(e);
							},
						endeffect: function (e) {
							menu.endDragging(e);
							},
						onChange: menu.options.onChange,
						tree: true
						}
					);
	}
	
	menu.makeDragable = function () {
		if (!this.options.draggableclass)
			{
			this.options.draggableclass = 'draggableclass_' + ulid + '_' + Math.round(1000000000*Math.random());
			$(ulid).select('li').each(function(cli) {
					if (!cli.hasClassName(menu.options.irrelevantclass))
						cli.addClassName(menu.options.draggableclass);
				} );
			}
	
		$(ulid).select('li').each(this.createDummyUL);
		$(ulid).select('ul').each(this.createDummyLI);
		this.createSortable();
		this.sortableCreated = true;
		}
	
	
	return menu;
	}
	

