ï»¿/*
 * Treeview 1.2 - jQuery plugin to hide and show branches of a tree
 *
 * Copyright (c) 2006 Jörn Zaefferer, Myles Angell
 *
 * Dual licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 *
 * Revision: $Id: jquery.treeview.js 1443 2007-02-27 20:08:28Z joern $
 *
 */

/**
 * Takes an unordered list and makes all branches collapsable.
 *
 * The "treeview" class is added if not already present.
 *
 * To hide branches on first display, mark their li elements with
 * the class "closed". If the "collapsed" option is used, mark intially open
 * branches with class "open".
 *
 * @example .treeview, .treeview ul { 
 * 	padding: 0;
 * 	margin: 0;
 * 	list-style: none;
 * }	
 * 
 * .treeview li { 
 * 	margin: 0;
 * 	padding: 4px 0 3px 20px;
 * }
 * 
 * .treeview li { background: url(images/tv-item.gif) 0 0 no-repeat; }
 * .treeview .collapsable { background-image: url(images/tv-collapsable.gif); }
 * .treeview .expandable { background-image: url(images/tv-expandable.gif); }
 * .treeview .last { background-image: url(images/tv-item-last.gif); }
 * .treeview .lastCollapsable { background-image: url(images/tv-collapsable-last.gif); }
 * .treeview .lastExpandable { background-image: url(images/tv-expandable-last.gif); }
 * @desc The following styles are necessary in your stylesheet. There is are alternative sets of images available.
 *
 * @example $("ul").Treeview();
 * @before <ul>
 *   <li>Item 1
 *     <ul>
 *       <li>Item 1.1</li>
 *     </ul>
 *   </li>
 *   <li class="closed">Item 2 (starts closed)
 *     <ul>
 *       <li>Item 2.1
 *         <ul>
 *           <li>Item 2.1.1</li>
 *           <li>Item 2.1.2</li>
 *         </ul>
 *       </li>
 *       <li>Item 2.2</li>
 *     </ul>
 *   </li>
 *   <li>Item 3</li>
 * </ul>
 * @desc Basic usage example
 *
 * @example $("ul").Treeview({ speed: "fast", collapsed: true});
 * @before <ul>
 *   <li class="open">Item 1 (starts open)
 *     <ul>
 *       <li>Item 1.1</li>
 *     </ul>
 *   </li>
 *   <li>Item 2
 *     <ul>
 *       <li>Item 2.1</li>
 *       <li>Item 2.2</li>
 *     </ul>
 *   </li>
 * </ul>
 * @desc Create a treeview that starts collapsed. Toggling branches is animated.
 *
 * @example $("ul").Treeview({ control: #treecontrol });
 * @before <div id="treecontrol">
 *   <a href="#">Collapse All</a>
 *   <a href="#">Expand All</a>
 *   <a href="#">Toggle All</a>
 * </div>
 * @desc Creates a treeview that can be controlled with a few links.
 * Very likely to be changed/improved in future versions.
 *
 * @param Map options Optional settings to configure treeview
 * @option String|Number speed Speed of animation, see animate() for details. Default: none, no animation
 * @option Boolean collapsed Start with all branches collapsed. Default: none, all expanded
 * @option <Content> control Container for a treecontrol, see last example.
 * @option Boolean unique Set to allow only one branch on one level to be open
 *		   (closing siblings which opening). Default: none
 * @option Function toggle Callback when toggling a branch.
 * 		   Arguments: "this" refers to the UL that was shown or hidden.
 * 		   Works only with speed option set (set speed: 1 to enable callback without animations).
 *		   Default: none
 * @type jQuery
 * @name Treeview
 * @cat Plugins/Treeview
 */
 // converts Tree Ids because slashes in ids are forbidden
 // this function maybe has to be extended


// Jquery extension
(function($) {

	// classes used by the plugin
	// need to be styled via external stylesheet, see first example
	var CLASSES = {
		open: "open",
		closed: "closed",
		expandable: "expandable",
		collapsable: "collapsable",
		lastCollapsable: "lastCollapsable",
		lastExpandable: "lastExpandable",
		last: "last",
		hitarea: "hitarea",
		highlighted : "highlighted",
		loaded : "loaded",
		contentEntry : "contentEntry", 
		current : "current",
		selected : "selected"
	};
	
	
	// styles for hitareas
	var hitareaCSS = {

	};
	// ie specific styles for hitareas
	if( $.browser.msie ) {
		$.extend( hitareaCSS, {
		//	background: "#fff",
			//filter: "alpha(opacity=0)",
			//display: "inline"
		});
	}
	
	$.extend($.fn, {
	
	Treeview: function( settings) {
		$.extend($.fn, {
			swapClass: function(c1, c2) {
				return this.each(function() {
					var $this = $(this);
					if ( $.className.has(this, c1) )
						$this.removeClass(c1).addClass(c2);
					else if ( $.className.has(this, c2) )
						$this.removeClass(c2).addClass(c1);
				});
			},
			replaceClass: function(c1, c2) {
				return this.each(function() {
					var $this = $(this);
					if ( $.className.has(this, c1) )
						$this.removeClass(c1).addClass(c2);
				});
			}
		});
		$.extend(this, {
		getType : function(typeString) {
			if (!typeString) 
				return false;
			for (var type in this.types) {
				if (this.types[type].name==typeString)
					return this.types[type];
			}
			return false;
		},
		areChildrenAllowed : function(typeString) {
			if (!typeString) {
				return false;
			}
			var types = typeString.split(' ');
			for (var i=0;i<types.length;i++) {
				var type = this.getType(types[i]);
				if (type && type._allowChildren>0)
					return true;
			}
			return false;
		},
		isOrderSafe : function(typeString) {
			if (!typeString) {
				return false;
			}
			var types = typeString.split(' ');
			for (var i=0;i<types.length;i++) {
				var type = this.getType(types[i]);
				if (type && type._orderSafe>0)
					return true;
			}
			return false;		
		},
		buildTreeEntry : function(info) {
			var tree = this;
			var $mother = $("[@rev="+info._pId+"]");
			if ($mother.length==0)
				$mother = tree.children("li");
			var $caption = $("<a></a>").text(info.name);
			var $entry = $("<li></li>").append($caption);
			var id = tree.generateId("entry");
			var pId = $mother.children("ul:eq(0)").attr("id");	
			$entry
				.attr("rev",info._id)
				.addClass(info._type)
				.attr("id",id)
				.addClass(pId);
			if (tree.areChildrenAllowed(info._type) && info._elCount > 0) {
				var $entries = $("<ul></ul>").attr("id",tree.generateId("mother"));
				$entry.append($entries);
			}
			
			return $entry;
		},		
	
		buildTree : function(elId) {
				var tree = this;
				var theItem = $("[@rev="+elId+"]");
				elId = elId ? elId : "" ;
				$.getJSON(tree.settings.json_url, 
				{   getContents : true , 
					id : elId, 
					rob : this.settings.rob,
					random : Math.round(Math.random()*1000)
				} , function(data) {
					$.cookie('rob_'+tree.settings.rob+'_path', elId);
					tree.processContent(data, elId, false);
				});		
		},
		refreshTree :function(instant) {
			var tree = this;
			var json_url = tree.settings.json_url;
			var $content = $(tree.settings.content);				
			
			tree.ticker++;
			if ((tree.ticker<5 && !instant) || tb_exists_window()) {
					return;
			}
			tree.ticker = 0;
			function updateIds($element) { // <li> with subelements
				var elId = $(element).attr("rev");
				if ($element.children("ul").length>0) {
					$.getJSON(json_url,
						{	
							getTree : true,
							id : elId, 
							deep : true, // muss noch serverseitig implementiert werden
							_version : tree.version,
							random : Math.round(Math.random()*1000)
						}, 
						function(obj) { 
							if (obj._el && obj._el.length>0) {
								for (var i=0; i < obj._el.length; i++) {
									var $span = $("ul li a", element).contains(obj._el[i].name);
									if ($span.length>0 && $span.parent().attr("rev")!=obj._el[i]._id) { // if existent and modified
										$span.parent().attr("rev",obj._el[i]._id);
										if (obj._el[i]._el && obj._el[i]._elCount > 0 &&  // if subelement has children
											$span.parent().filter("."+CLASSES.collapsable).length>0) { // if flapped
												updateIds($span.parent());
										}
									}
								}
							}						
						}
					);
				}
			}
			$.getJSON(settings.json_url,
					{ getChanges: true ,
					  _version : tree.version, 
					  rob : tree.settings.rob,
					  random : Math.round(Math.random()*1000)
					}, 
			function(data) {
				try {
					tree.setVersion(data._version);
					var changes = data.changes;
					var counter = 0;
					for (var i=0;i<changes.length;i++) {
						if (changes[i]._pId) {
							var $mother = $("[@rev="+changes[i]._pId+"]", tree);
						} else {
							var $mother = $(tree).children("li");
						}

						switch(changes[i].action) {	
							case 'move': 
							if (tree.areChildrenAllowed(changes[i]._type)) {
								var $element = $("[@rev="+changes[i]._oldId+"]", tree);
								if ($element.length>0) { // if shown
									var $mother2 = $element.parent();
									$element.remove();
									if ($mother2.children().length==0) {
										$mother2
											.parent().removeClass("open")
											.remove();
									}
								} else {
									$element = tree.buildTreeEntry(changes[i]);
								}
								$element.attr("rev", changes[i]._id);								
								updateIds($element);
								if ($mother) {
									if ($mother.filter("."+CLASSES.collapsable).length>0) { // if mother is expanded
										$mother.children("ul").append($element);
									} else if ($mother.filter("."+CLASSES.expandable).length>0) { // mother is collapsed
										if ($mother.children("ul").length==0) {
											$mother.append("<ul></ul>");
										}
									} else {
										$mother
											.append("<ul></ul>")
											.children("ul").append(element)
											.addClass(CLASSES.open);
									}
								}
							}
							$element = $("[@rev="+changes[i]._oldId+"]",$content);
							if ($element.length>0) {
								$element.remove();
							} else {
								$element = tree.buildContentEntry(changes[i]);
							}
							if ($content.attr("rev")==changes[i]._pId) {
								$content.append($element);
							}
								
							break;
							case 'add' :
								if ($("[@rev="+changes[i]._id+"]",tree).length==0) { // if isn't existent yet
									if ($mother.length>0) {
										if (($mother.children("ul").length==0) && tree.areChildrenAllowed(changes[i]._type)) {
											var list = $("<ul></ul>").attr("id",tree.generateId("mother"));//.addClass("loaded");
											$mother.append(list);//addClass("open").
										} else if ($mother.children("ul.loaded").length>0) {
											var $treeEntry = tree.buildTreeEntry(changes[i]);
											if (!tree.areChildrenAllowed(changes[i]._type))			
												$treeEntry.hide();
											$mother.children("ul").append($treeEntry);
										}
									}
								}
								
								var contentId = $content.attr("rev");
								if (typeof contentId == "undefined") 
									contentId = "";
								if ($("[@rev="+changes[i]._id+"]",$content).length==0 && contentId==changes[i]._pId) {
									var $contentEntry = tree.buildContentEntry(changes[i]);
									$content.append($contentEntry);
								} 
								
							break;
							case 'delete':
								mother = $("[@rev="+changes[i]._id+"]", tree).parent();
								$("[@rev="+changes[i]._id+"]").remove();
								if (mother.children().length==0) {
									mother
										.removeClass("open")
										.remove();
								}
							break;
							case 'modify':
								tree.modifyElement(changes[i], $content);
								tree.modifyElement(changes[i], $(tree));
							break;

						}
					}
					tree.treeInit();
				} catch (err) {
					alert("error "+err.description);
				}
			});

		},
		modifyElement : function(data, context) {
			var tree = this;
			var $element = $("[@rev="+data.original_object._id+"]",context);
			if ($element.length>0) {
				if (data.new_object.name) {
					$element.children("a").text(data.new_object.name);
				}
				if (data.new_object._id && data.new_object._id!=data.original_object._id) {
					$element.attr("rev", data.new_object._id);
					if ($element.parent().attr("id")=="content") {
						var newElement = tree.buildContentEntry(data.new_object);
						$element.after(newElement).remove();
						$element = newElement;
					}
				} 
				if (data.new_object._sortOrder != data.original_object._sortOrder) {
					// neue sortierung
					var actualPos = tree.findElement($element.parent().get(0), $element.get(0));
					if (actualPos != (data.new_object._sortOrder-1)) {
						$element.insertBefore($element.parent().children().get(data.new_object._sortOrder-1));
					}
					
				}
			}
		},
		findElement : function(mother, element) {
			var index=-1;
			$(mother).children().each(function(i) {
				if (this==element) {
					index = i;
				}
			});
			return index;
		},
		loadContent : function (elId) {
			// this is a a
			var tree = this;
			var attr = tree.settings.attributeName;
			var theItem = $("[@rev="+elId+"]");
			elId = elId ? elId : "" ;
			$.getJSON(tree.settings.json_url, 
			{   getContents : true , id : elId, 
				rob : this.settings.rob,
				random : Math.round(Math.random()*1000)
			} , function(data) {
				//$.cookie('rob_first',null);
				$.cookie('rob_'+tree.settings.rob+'_path', elId);
				tree.processContent(data, elId, true);
				//$("#debug").append("loadContent callback<br />");
			});
		
		},
		processContent : function (data, elId, loadContent) {
			try {
			var tree = this;
			var objs = new Array();
			var ii = 0;
			var mother = elId ? $("[@rev="+elId+"]" , tree) : $(tree).children("li").attr("rev", data._id);
			var loadTree = true;
			var hiddenEntries = 0;
			if (loadContent) {
				$("a").removeClass(CLASSES.current);
				mother.children("a").addClass(CLASSES.current);
				$(tree.settings.content).html("").attr("rev", data._id);
			}

			if (mother.children("ul").length == 0 || mother.children("ul").children().length>0) { // if already loaded
				loadTree = false;
			}
			
			if (data._el) {
				for (var i=0;i<data._el.length;i++) {
					if (loadTree) {
						mother.addClass(CLASSES.open);
						entryJ = tree.buildTreeEntry(data._el[i]);
						if (!tree.areChildrenAllowed(data._el[i]._type)) {
							entryJ.hide();
							hiddenEntries++;
						}
						mother.children("ul").append(entryJ);
					}

					if (loadContent) {
						$(tree.settings.content).append(tree.buildContentEntry(data._el[i]));
					}
					if ((data._el[i]._el && data._el[i]._el.length>0) || ($.cookie('rob_'+tree.settings.rob+'_path')==data._el[i]._id && tree.areChildrenAllowed(data._el[i]._type))) {
						objs[ii] = data._el[i];
						ii++;
					}
				}
			}
			if (loadTree) {
				mother.children("ul").addClass("loaded").show();
				if (mother.children("ul").children("li").length==0) {
					mother.children("ul").remove();
				}
			}
			$(tree.settings.content).attr("class","").addClass(data._type);
			
			if (ii>0) {
				for (j=0; j<ii; j++) {
					tree.processContent(objs[j], objs[j]._id, true);
				}
			}
			if (data._el && hiddenEntries==data._el.length)
				mother.children("ul").remove();
			tree.treeInit();
			} catch(err) {
			alert("error");
			}
		},
		deleteElement : function(info) {
			var tree = this;
			if (!tree.collection)  {
				tree.collection = $(".selected", tree.settings.content).not($(info).parent()).add($(info).parent());;
			}
			
			$.each(tree.collection, function(i) {
				var ajaxSuccess = false;
				if ((i+1)==tree.collection.length) {
					ajaxSuccess = function(data) {
						robAnswer(data,tree);
					};
				}
				var id = $(tree.collection[i]).attr("rev");
				$.getJSON(tree.settings.json_url, 
					{ 	writeChanges : true,
						_id : id,
						action : "delete",
						_version : tree.attr("rel"),
						rob : tree.settings.rob,
						random : Math.round(Math.random()*1000)
					}, ajaxSuccess
				);
			});
			tree.collection=false;
		},
		generateId : function(prefix) {
			var id;
			do {
				id = prefix+"_"+Math.round(Math.random()*10000);
			} while ($("#"+prefix+"_"+id).length>0);
			return id;
		},
		
		buildContentEntry : function(info) {
				var tree = this;
				pId = info._pId ? info._pId : "";
				var $caption = $("<a></a>")
					.text(info.name)
					.attr("href",tree.settings.popup_url+"?_id="+info._id+"&_pId="+pId+"&rob="+tree.settings.rob)
					.addClass("thickbox")
					.addClass(CLASSES.contentEntry);
				var contextMenu;
				if ($('#contextmenu_'+info._type).length>0) {
					contextMenu = 'contextmenu_'+info._type;
				} else {
					contextMenu = 'contextmenu_default';
				}
				$caption
				/*.bind('contextmenu', function() {
					$(this).addClass("highlighted");
				}) */
				.contextMenu(contextMenu,
				 {
				      bindings: {
					'contextmenu_delete': function(t) {tree.deleteElement(t); },
						'contextmenu_copy': function(t) { 
							$(t).parent().addClass(CLASSES.selected);
							//tree.copy = new Array($(t).parent().attr(tree.settings.attributeName));
							
							tree.copyElements();
							$(t).parent().removeClass(CLASSES.selected);
							/* tree.setInfo("Sie haben das Element <strong>"+$(t).text()+"</strong> nun in die Zwischenablage kopiert. Fügen Sie "
							+"es nun an einer beliebigen Stelle wieder ein, indem Sie die rechte Maustaste und dann \"Einfügen\" drücken"); */
						},
						'contextmenu_info' : function(t) { alert($(t).parent().attr(tree.settings.attributeName)); }
				      }
				    }
				);
				var $entry = $("<li></li>").append($caption);
				$entry.
					attr(tree.settings.attributeName,info._id)
					.addClass(info._type)
					.addClass("content")
					.attr("id",tree.generateId("content_entry"));
				tb_init($("a", $entry));
				return $entry;					
		},
		
		getVersion : function() {
			var tree = this;
			if (!$(tree).attr("rel") && !tree.version) {
				
				$.getJSON(tree.settings.json_url, 
					{ 	getVersion : true, 
						rob : this.settings.rob ,
						random : Math.round(Math.random()*1000)
					}, tree.setVersion);
			}
		},
		setVersion : function(version) {
			tree.version = version;
			$(tree).attr("rel", version);
			return true;
		},
		
		toggleDragMode : function() {
			if (this.dragMode==0) {
				this.dragMode=1;
			} else {
				this.dragMode=0;
			}
			this.initDragMode(true);
		},
		
		initDragMode : function(changeIt) {
			var tree = this;
			var content = $(this.settings.content);
			if (this.dragMode==0) { // drag&drop
				for (var type in this.types) {
				
					type = this.types[type].name;
					if (tree.isOrderSafe(type) && changeIt) {
						$("//li."+type+"/ul, //ul."+type).each(function() {	
							if (this.sortCfg) 
							$(this).SortableDestroy();
						});
					} 
					if ( !tree.areChildrenAllowed(type) ) {
						continue;
					}
					$("li."+type+" a").Droppable({
						accept			: ' ',
						hoverclass		: CLASSES.highlighted,
						tolerance		: 'pointer',
						// when an accepted draggble is drop on a droppable this functin is called. Applies to the droppable and gets as parameter the draggable DOMElement
						onDrop			: function(dropped)
						{
							tree.ready=true;
							for (var index=0; index<tree.collection.length;index++) {
								//while (!tree.ready);
								//var toRemove = 0;								
								var status = false;
								var onSuccess = false;
								dropped = tree.collection[index];
								if ($(dropped).attr("rev")==$(this).parent().attr("rev")) {
									//alert("self-service");
									continue;
								}

								/*if (tree.areChildrenAllowed($(dropped).attr("class"))) {
									toRemove++;
								}
								if (toRemove==0) {
									$(dropped).remove();
								} */
								
								var newpId = $(this).parent().attr("rev");
								newpId = typeof newpId != "undefined" ? newpId : "";
								
								if ((index+1) == tree.collection.length) {
									onSuccess = function(data) {
										robAnswer(data, tree);
										tree.ready = true;
									};
								}
								$.getJSON(tree.settings.json_url, 
									{ 
										writeChanges : true,
											action : "move",
											_id : $(dropped).attr(tree.settings.attributeName),
											_newpId : newpId,
											_version : $(tree).attr("rel"),
											rob : tree.settings.rob,
											random : Math.round(Math.random()*1000)
												
									}, onSuccess);
							}
							return false;
						
						}
					});						
				
				//	alert("ende"+type);
				} 
			$("li li",tree).Draggable({
				revert		: true,
				ghosting	: true,
				cursorAt 	: { top: 0, left:0 } ,
				snapDistance : 20,
				onStart : function() {
					//$("#info").html($(this).parent().html());
					//alert($(this).parent().html());
					markedItem = $("a.current");
					markedItem.removeClass("current");						
					
					return true;
				},
				onStop : function() {
					//alert("end");
					markedItem.addClass("current");
					//$(this).children("div."+CLASSES.hitarea).css(hitareaCSS);
					//tree.treeInit();
					$(this).css("position", "static");
					return true;
				}
			 
			 });
			 $("li",content).Draggable({
				revert		: true,
				ghosting	: true,
				cursorAt 	: { top: 0, left:0 },
				onStart: function(cloneEl, x, y) {
					$("#debug").append("dragStart <br />");
					markedItem = $("a.current").removeClass("current");
					
					//$(this).addClass("selected");
					tree.collection = new Array($(this));
					return;
					var collection = jQuery("#"+$(this).parent().attr("id")+' .selected');//.not(this);
					tree.collection = collection.clone().removeClass("selected");
					$(cloneEl).parent().html(tree.collection).css("overflow","visible");
				},
				
				onStop : function()
				{
					
					tree.collection = false;
					markedItem.addClass("current");
				}							
			});  
			var content = $(this.settings.content).get(0);
			//if (content)
			//	content.isSelectable = false;
			/*
			$(this.settings.content).Selectable(
					{
						accept : 'content',
						selectedclass : 'selected',
						opacity: 0.2,
						helperclass : 'rectangle',
						onselect : function(serial) {
							$(this).children("li.selected").children("a").addClass("selected");
						}
					}
			);		 */
			$("#dragHelper").addClass("treeview");						
			
									
			} else {
				if (changeIt)  {
					$("*").DraggableDestroy();
					$("*").DroppableDestroy();
					//$("*").SelectableDestroy();
				}
				for (var i=0;i<tree.types.length;i++) {
					type=tree.types[i].name;
					if (!tree.isOrderSafe(type))
						continue;

					$("//li."+type+"/ul, //ul."+type).each(function() {
								var id = $(this).attr("id") ? $(this).attr("id") : "";
								$(this).Sortable({
									accept : id,
									axis: 'vertically',
									//containment : 'parent',
									fit: true,
									revert : true,
									fx : 200,
									ghosting: false,
									onChange : function(ser) {
										
										var mother = ser[0].id;
										//alert(mother);
										var toSend = {};
										var i=0;
										$("#"+mother).children("li").each(function() {
										
											toSend["_sortOrder_"+i] = $(this).attr(tree.settings.attributeName);
											i++;
										});
										toSend["_sortOrder_length"] = i;
										if (id=="content") {
											id1=$("#"+mother).attr(tree.settings.attributeName);
										} else {
											id1 = $("#"+mother).parent().attr(tree.settings.attributeName);
											
										}
										id1 = id1 ? id1 : "";
										toSend = $.extend(toSend, 
											{ 	writeChanges : true, 
												action : "changeOrder", 
												_version : $(tree).attr("rel"),
												_id : id1,
												rob : tree.settings.rob,
												random : Math.round(Math.random()*1000)
											});
																				
										$.getJSON(tree.settings.json_url, toSend, function(data) {
											robAnswer(data,tree);
										});
									},
									onOut : function() {
									}
						
							});
							
						});
					}
			}
		
		
		},
		buildActions : function() {
			var tree = this;
			var i;
			for (var key in tree.types) {
				
				if (!tree.types[key].name)
					continue;
				type = tree.types[key].name;
				var name = tree.types[key]._title ? tree.types[key]._title : type;
				var actionId = "contextmenu_new_"+type;
				entry = $("<li></li>")  .attr("id",actionId)
							.attr("onmouseover", 'myTree.setInfo("Ein neues Element vom Typ '+name+' erstellen.", true)')
							.attr("onmouseout", "myTree.swapInfo()");

				link = $("<a></a>")
							.attr("href","popup.php?action=add&_type="+type+"&rob="+tree.settings.rob)
							.text("Neu: "+name)
							.appendTo(entry)
							.addClass(type)
							.addClass("contextMenuLink");
				entry.prependTo("#contextmenu_actions ul");

			}
			return true;
			
		},
		paste : function() {
				var tree = this;
				if (tree.copy) {
					$.each(tree.copy, function(i,elId) {
						$.getJSON(settings.json_url, 
						{
								writeChanges : true,
								_id : elId, 
								_pId : $(tree.settings.content).attr(tree.settings.attributeName),
								action : "copy",
								_version : tree.version,
								rob : tree.settings.rob,
								random : Math.round(Math.random()*1000)
								
						}, 
						function(data) {
							robAnswer(data, tree);
						});
					});
					tree.setInfo("Sie haben " + (tree.copy.length) + " Elemente eingefÃ¼gt.");
					tree.copy = false;
				}
				if (tree.move) {
					$.each(tree.move, function(i,elId) {
						$.getJSON(settings.json_url, 
						{
								writeChanges : true,
								_id : elId, 
								_newpId : $(tree.settings.content).attr(tree.settings.attributeName),
								action : "move",
								_version : tree.version,
								rob : tree.settings.rob,
								random : Math.round(Math.random()*1000)
						}, 
						function(data) {
							robAnswer(data, tree);
						});
					});
					tree.setInfo("Sie haben " + tree.move.length+" Elemente verschoben.");
					tree.move = false;
				}				
		},
		copyElements : function() {
			var tree = this;
			tree.move = false;
			if ($("li.selected", tree.settings.content).length>0) {
				tree.copy = new Array();
				$("li.selected", tree.settings.content).each(function() {
					tree.copy[tree.copy.length] = $(this).attr(tree.settings.attributeName);
				});
				var anz = tree.copy.length;
				tree.setInfo("Sie haben "+anz+" "+(anz==1 ? "Element" : "Elemente")+" in die Zwischenablage kopiert.");
			}		
		},
		cutElements : function() {
			var tree = this;
			tree.copy = false;
			if ($("li.selected", tree.settings.content).length>0) {
				tree.move = new Array();
				$("li.selected", tree.settings.content).each(function() {
					tree.move[tree.move.length] = $(this).attr(tree.settings.attributeName);
				});
				var anz = tree.move.length;
				tree.setInfo("Sie haben "+anz+" "+(anz==1 ? "Element" : "Elemente")+" zum Verschieben ausgewählt.");
			}		
		},
		processTypes : 	function(data) {
						var tree = this;
						this.types = data.types;
						this.version = data.version;
						$(this).attr("rel", data.version);
						this.buildActions();
						$(this.settings.content).contextMenu("contextmenu_actions",
						 {  bindings : {
								'contextmenu_insert' : function(t) {
									tree.paste();
								}
							},
							onShowMenu : function(e, menu) {
								$("a",menu).click(function() { $(menu).hide(); });
								tb_init($("a", menu).get());
								if (!tree.copy && !tree.move) {
									$(".contextmenu_insert").hide();
								} else {
									$(".contextmenu_insert").show();
								}
								return menu;
							},
							shadow : false
						 }
							
						);							
					
		},
		setInfo : function(html, temp) {
			if (temp)
				this.infoBackup = $("#info").html();
			else
				this.infoBackup = false;
			$("#info").html(html);
		},
	
		swapInfo : function () {
			if (this.infoBackup !== false) {
				$("#info").html(this.infoBackup);
				this.infoBackup = false;
			}
		},		
	
			treeInit : function() {
				//alert("hallo");
				//$("#debug").append("treeInit <br />");
				// remove old things
				if ($(this).length==0)
					return;
				
				var tree = this;
				settings = this.settings;
				var content = $(settings.content).get(0);
				
				$("*", tree)
					.removeClass(CLASSES.expandable)
					.removeClass(CLASSES.last)
					.removeClass(CLASSES.lastExpandable)
					.removeClass(CLASSES.collapsable)
					.removeClass(CLASSES.lastCollapsable)
					.unbind("click");

				$("li div."+CLASSES.hitarea, tree).remove();
				// add treeview class to activate styles
				$(tree).addClass("treeview");
				//alert("hallo" + this);
				// mark last tree items

				$("li:last-child", tree).addClass(CLASSES.last);
				
				// collapse whole tree, or only those marked as closed, anyway except those marked as open
				$( (settings.collapsed ? "li" : "li." + CLASSES.closed) + ":not(." + CLASSES.open + ") > ul", tree).hide();
			
				// find all tree items with child lists
				//$("li[ul[li]]", tree)
				
				$("li",tree)
						.children("a")
						.click(function() {
							//$(this).parent().not(".open").children("div").click(); // click on hitarea
							tree.loadContent($(this).parent().attr(tree.settings.attributeName));
						})
						.end()
						.prepend("<div class=\"" + CLASSES.hitarea + "\">&nbsp;</div>")
						// find hitarea
//						.find("div." + CLASSES.hitarea)
						// apply styles to hitarea
//						.css(hitareaCSS);
;
				
				$("li[ul]",tree)
					// handle closed ones first
					//.click(toggler)

					.filter("[>ul:hidden]")
						.addClass(CLASSES.expandable)
						.swapClass(CLASSES.last, CLASSES.lastExpandable)				
						.end()
					// handle open ones
					.not("[>ul:hidden]")
						.addClass(CLASSES.collapsable)
						.swapClass(CLASSES.last, CLASSES.lastCollapsable)
						.end()
					// append hitarea
				//	.prepend("<div class=\"" + CLASSES.hitarea + "\">&nbsp;</div>")
					// find hitarea
					.find("div." + CLASSES.hitarea)
						// apply styles to hitarea
					//	.css(hitareaCSS)
						//.end()
					//.filter("[>ul:hidden]")
						//.find("div."+CLASSES.hitarea)
						// apply toggle event to hitarea
						.click( toggler )
						//.click(toggler)
						.end();

						
				//tree.getVersion();						

				
			document.onkeydown = function(e) {
				
				//c = 67
				// x = 88
				// v = 86
				//alert(e.keyCode);
				 // MSIE nimmt das Event-Objekt aus window.event, DOM-kompatible Browser aus dem e-Funktionsparameter
				 if (!e) e=window.event;
				 // keyCode muss 70 sein und ctrlKey true
				 if (e.ctrlKey || e.metaKey) {
				  switch(e.keyCode) {
					case 67: 
						tree.copyElements();
					break;
					case 88: 
						tree.cutElements();						
					break;
					case 86: 
						tree.paste();
					break;
				  }
				}	
			};
				
				
				// if control option is set, create the treecontroller
				if ( settings.control )
					treeController(tree, settings.control);
				//$("*", tree).DroppableDestroy();
				

				//this.dragMode = 0;
				tree.initDragMode();
			}
			});					

			
			// currently no defaults necessary, all implicit
			var settings = $.extend({}, settings);
			// save the settings in the current jquery object
			this.settings = settings;
			// types
			this.dragMode = 0; // 0 for drag&drop, 1 for sort
			this.ticker = 0;
			this.infoBackup = false;
			
			// select
			this.collection = false;
			this.copy = false;
			this.move = false;
			var tree = this;



			// factory for treecontroller
			function treeController(tree, control) {
				// factory for click handlers
				function handler(filter) {
					return function() {
						// reuse toggle event handler, applying the elements to toggle
						// start searching for all hitareas
						toggler.apply( $("div." + CLASSES.hitarea, tree).filter(function() {
							// for plain toggle, no filter is provided, otherwise we need to check the parent element
							return filter ? $(this).parent("." + filter).length : true;
						}) );
						return false;
					}
				}
				// click on first element to collapse tree
				$(":eq(0)", control).click( handler(CLASSES.collapsable) );
				// click on second to expand tree
				$(":eq(1)", control).click( handler(CLASSES.expandable) );
				// click on third to toggle tree
				$(":eq(2)", control).click( handler() ); 
			}
		
			// handle toggle event
			function toggler() {
				// this refers to hitareas, we need to find the parent list first
				$( this ).parent()
					// swap classes
					.swapClass( CLASSES.collapsable, CLASSES.expandable )
					//.swapClass( CLASSES.lastCollapsable, CLASSES.lastExpandable )
					// find child lists
					.find( ">ul."+CLASSES.loaded )
					// toggle them
						//.toggle( settings.speed, settings.toggle )
						.toggle()
						.end();
				$(this).siblings("ul:not(."+CLASSES.loaded+")")
					.each(function() {
						tree.buildTree($(this).parent().attr(tree.settings.attributeName));
						$(this).addClass(CLASSES.loaded);
					});
				
				
				if ( settings.unique ) {
					$( this ).parent()
						.siblings()
						.replaceClass( CLASSES.collapsable, CLASSES.expandable )
						//.replaceClass( CLASSES.lastCollapsable, CLASSES.lastExpandable )
						.find( ">ul" )
						.hide( settings.speed );
				} 
			}
			if (!settings.embed)
				this.treeInit();
			return this;
		}
	});
})(jQuery);
function robAnswer(answer,tree) {
	
	var status = false;
	status = answer.changes[0].status;
	if (status) {
		tree.refreshTree(true);
	} else {
		alert("error : "+answer.changes[0].error);
	}
}

function ajaxFileUpload(id,tree)
{
	$.ajaxFileUpload(
		{
			url: tree.settings.json_url,
			secureuri : false,
			fileElementId: id,
			dataType: 'json',
			success: function ajaxSuccess(data, status)
			{
				if (!data.status) {
					return false;
				}
				var inputJ = $('<input />')
						.attr("type","text")
						.attr("name",id)
						.attr("id", id+"_tmp")
						.attr("size","30")
						.val(data.names[0])
						.attr("readonly","readonly")
						.addClass("readonly")
							.insertAfter($("#"+id))
						.end();			
				$("#"+id).remove();
				$("#"+id+"_tmp").attr("id",id);
				var nameField = $("#name");
				if (nameField.val()=="") {
					nameField.val(data.names[0]);
				}
			},
			error: function (data, status, e)
			{
				//alert("error");
			}
		});
	return false;
}

function tb_exists_window() {
	if ($("#TB_window").length>0)
		return true;
	return false;

}