if(jQuery) (function($){
	
	$.extend($.fn, {
		violetTree: function(o) {
			if( !o ) var o = {};
			if( o.user == undefined ) o.user = null;
			if( o.homeDirNameDisplay == undefined ) o.homeDirNameDisplay = 'Home';
			if( o.host == undefined ) o.host = 'http://localhost/';
			if( o.script == undefined ) o.script = 'ajax/privatecontent/getcontent';
			if( o.container == undefined ) o.container = null;
			if( o.dirIDprefix == undefined ) o.dirIDprefix = 'vsdir_';

			if( o.expandSpeed == undefined ) o.expandSpeed= 500;
			if( o.collapseSpeed == undefined ) o.collapseSpeed= 500;
			if( o.expandEasing == undefined ) o.expandEasing = null;
			if( o.collapseEasing == undefined ) o.collapseEasing = null;
			if( o.me == undefined ) o.me = this;

			if( o.directoryTreeData == undefined ) o.directoryTreeData = null;
			if( o.grid == undefined ) o.grid = null;
			if( o.contextmenuON == undefined ) o.contextmenuON = true;
			
			var currentObj = {};
			if ( currentObj.type == undefined ) currentObj.type = 'directory';
			
			// PRIVATE methods
			var sendCommand = function (p) {
				if( p.postdata == undefined ) p.postdata = null;
				if( p.script == undefined ) p.script = o.script;
				if( p.callbackSuccess == undefined ) p.callbackSuccess = null;
				if( p.callbackDone == undefined ) p.callbackDone = null;
				if( p.callbackFail == undefined ) p.callbackFail = null;
				if( p.callbackAlways == undefined ) p.callbackAlways = null;

				if (p.script != null) {
					$.post(o.host + p.script, p.postdata, function (data){
						if (data) {
							parseData = $.parseJSON(data);
						}

						if (p.callbackSuccess != null) {
							p.callbackSuccess(parseData);
						}

					}).done(function() {if (p.callbackDone != null)p.callbackDone(this);}).fail(function() {if (p.callbackFail != null)p.callbackFail(this);}).always(function() {if (p.callbackAlways != null)p.callbackAlways(this);});
				}
			}

			var loadTree = function () {
				sendCommand ({postdata:null,callbackSuccess:renderTree});
			};

			var renderTree = function  (parseData) {
				$(o.container).find ('.vstree').remove();
				
				o.directoryTreeData = parseData;				
				var directoryData = parseData.DIRECTORIES;
				
				var homeNode = createNode({
					id:0,
					name:o.homeDirNameDisplay,
				});
				
				selectDir($(homeNode).find('> A'));
				if (directoryData != null) {
					var count = 0;
					for (var i = 0; i < directoryData.length ; i++) {
						var htmlNode = $(o.container).find('#' + o.dirIDprefix + directoryData[i].parentID);
						
						var node = createNode ({
							id: directoryData[i].id,
							name: directoryData[i].name,
							currentNode: $(htmlNode).find('> A'),
							hidden: (directoryData[i].parentID > 0) ? true : false
						})
						
						count ++;
					};
				}
			};

			//Create a node of Tree
			var createNode = function (d) {
				if( !d ) var d = {};
				if( d.id == undefined ) d.id = null;
				if( d.name == undefined ) d.name = null;
				if( d.currentNode == undefined ) d.currentNode = null;
				if( d.hidden == undefined ) d.hidden = true;
				if( d.clickEvent == undefined ) d.clickEvent = openDir;
				if( d.customEvent == undefined ) d.customEvent = null; //customEvent.eventName, customEvent.eventTrigger
				if( d.addToJSONData == undefined ) d.addToJSONData = false;
				
				var disabledItemsList = null;
				if (d.name == o.homeDirNameDisplay)
					disabledItemsList = ['rename','copy','cut','delete'];
				
				if (d.currentNode != null) {
					var strHTML = '<ul class="vstree"><li id="' + o.dirIDprefix + d.id + '" class="directory collapsed"><a href="#" rel="' + d.name + '">' + d.name + '</a></li></ul>';

					$(d.currentNode).parent().append(strHTML);
					if (d.hidden == true) 
						$(o.container).find('#' + o.dirIDprefix + d.id).parent().css('display','none');
					
				}else if (d.id == 0){
					var strHTML = '<ul class="vstree"><li id="' + o.dirIDprefix + d.id + '" class="home"><a href="#" rel="' + d.name + '">' + d.name + '</a></li></ul>';
					$(o.container).append(strHTML);
				}

				//bind new node to data
				if (d.addToJSONData == true) {
					var newdir = {};
					newdir.id = d.id;
					newdir.name = d.name;
					newdir.parentID = $(o.container).find(d.currentNode).parent().attr('id').substring(o.dirIDprefix.length, $(d.currentNode).parent().attr('id').length);
					o.directoryTreeData.DIRECTORIES.push(newdir);
					sendtoGrid();
				}
				
				//bind event on new node
				$(o.container).find('#' + o.dirIDprefix + d.id).find('a').bind("click", function(e){d.clickEvent(this);return false;});
				
				if (o.contextmenuON) {
					$(o.container).find('#' + o.dirIDprefix + d.id).find('a').contextMenu({
						menu: 'treeMenu',
						disabledItems: disabledItemsList
					}, function(action, el, pos) {
						selectDir(el);
						switch(action) {
							case 'rename':
								rename(el);
								break;
							case 'newfolder':
							case 'share':
							case 'copy':
							case 'cut':
								o.grid.showModal(currentObj, action);
								break;
							case 'delete':
								break;
							default:
								break;
						}
					});
				}
				
				if (d.customEvent != null) 
					$(o.container).find('#' + o.dirIDprefix + d.id).find('a').bind(d.customEvent.eventName, function(e){d.customEvent.eventTrigger(this)});

				return $(o.container).find('#' + o.dirIDprefix + d.id);
			}
			//END - Create a node of Tree
			
			var deleteNode = function (parsedData) {
				if (parsedData.isSuccess == false) return false;
				if (!$('#' + o.dirIDprefix + parsedData.id).hasClass('home'))
					$('#' + o.dirIDprefix + parsedData.id).parent().remove();
			}

			var isHome = function (n) {
				return $(n).parent().hasClass('home');
			}

			var countNodeChild = function (n) {
				var parent = $(n).parent();
				return $(parent).find('UL').size();
			}
			
			var openDirById = function (dirID) {
				console.log(o.grid);
				var item = o.grid.searchItem(dirID, 'directory');
				var treeNode = $(o.container).find('#' + o.dirIDprefix + item.id);
				
				if(item.parentID != 0) {
					var parent = $(o.container).find('#' + o.dirIDprefix + item.parentID);
					if( $(parent).hasClass('collapsed') ) {
						$(parent).removeClass('collapsed').addClass('expanded');
						$(parent).find('> UL:hidden').slideDown({ duration: o.expandSpeed, easing: o.expandEasing });
					}
				}
				
				if( $(treeNode).hasClass('collapsed') ) {
					$(treeNode).find('> UL:hidden').slideDown({ duration: o.expandSpeed, easing: o.expandEasing });
					$(treeNode).parent().parent().find('> UL:hidden').slideDown({ duration: o.expandSpeed, easing: o.expandEasing });
					$(treeNode).removeClass('collapsed').addClass('expanded');
				}
				
				selectDir($(treeNode).find('> A'));
			}

			var openDir = function (i) {
				closeAllChild($(i).parent());
				
				if( $(i).parent().hasClass('collapsed') ) {
					$(i).parent().find('> UL:hidden').slideDown({ duration: o.expandSpeed, easing: o.expandEasing });
					$(i).parent().removeClass('collapsed').addClass('expanded');
				}
				else if( $(i).parent().hasClass('expanded') ) {
					$(i).parent().find('> UL').slideUp({ duration: o.collapseSpeed, easing: o.collapseEasing });
					$(i).parent().removeClass('expanded').addClass('collapsed');
				}
				
				selectDir(i);
			}
			
			var closeAllChild = function (i) {
				if ($(i).hasClass('home')) return;
				var aryChildDir = $(i).find ('UL');
				for (var i = 0; i < aryChildDir.length; i++) {
					$(aryChildDir[i]).slideUp({ duration: o.collapseSpeed, easing: o.collapseEasing });
					$(aryChildDir[i]).find('> LI').removeClass('expanded').addClass('collapsed');
				}
			}

			var selectDir = function (c) {
				$('.currentDir').removeClass('currentDir');
				$(c).addClass('currentDir');
				
				var cid = $(c).parent().attr('id');
				var pid = cid.substring(o.dirIDprefix.length, cid.length);
				
				currentObj.id = pid;
				currentObj.name = $(c).attr('rel');
				
				keyboardRename ();
				
				sendtoGrid();
			}

			var sendtoGrid = function () {
				if (o.grid == null) return false;
				
				o.grid.setTree(o.me);
				o.grid.setData({
								directoryTreeData: o.directoryTreeData,
								curentParent:$(o.container).find('.currentDir').parent().attr('id'),
								dirIDprefix: o.dirIDprefix
							});
			}

			var rename = function (o) {
				var editor = document.createElement ('INPUT');
				editor.type = 'text';
				editor.className = 'rename';
				
				$(o).text('');
				$(o).append(editor);
				
				$(editor).attr('value', currentObj.name);  
				editor.focus();
				$(editor).select();
				
				$(editor).bind('focusout',function (e) {
					cancelRename($(o));
				});
				
				$(editor).bind('keypress',function (e) {
			        var keycode = (e.keyCode ? e.keyCode : e.which);
			        if(keycode == '13'){
			        	completeRename($(o));
			        }
			        else {
			        	
			        }
			        e.stopPropagation();
				});
			}
			
			var cancelRename = function (o) {
				$(o).find('>INPUT').remove();
				$(o).text(currentObj.name);
			}
			
			var completeRename = function (o) {
				var postdata = {id:currentObj.id,
						objtype:'directory',
						newname:$(o).find('INPUT.rename').val()}
				
				sendCommand({
					script:'ajax/privatecontent/rename',
					postdata:postdata,
					callbackSuccess: function (parsedData) {
						if (parsedData.RESULT == true) {
							currentObj.name = parsedData.UPDATED.name;
							$(o).find('INPUT.rename').remove();
							$(o).text(currentObj.name);
						}else return false;
					}
				});
			}
			
			var keyboardRename = function () {
				$(document).bind('keydown','keypress', function(e) {
					var selectedItem = $('.currentDir');
					
					switch( e.keyCode ) {
						case 113:
							rename(selectedItem);
							break;
						case 27:
							cancelRename(selectedItem);
							break;
						default:
							break;
					}
				});
			}
			
			loadTree();
			// END - PRIVATE methods


			this.expandAll = function() {
				$(o.container).find('UL:hidden').slideDown({ duration: o.expandSpeed, easing: o.expandEasing });
			};

			this.getCurrentDirName = function() {
				return $(o.container).find('.currentDir').attr('rel');
			};

			this.getCurrentDir = function() {
				return $(o.container).find('.currentDir');
			};

			this.createDir = function(data) {
				var cNode = $('#' + o.dirIDprefix + data.parentID).find('> A');
				createNode({
					id: data.id,
					name: data.name,
					currentNode: cNode,
					hidden: false,
					addToJSONData:true});
			};

			this.deleteDir = function (c) {
				if (isHome(c)) return;
				var childExisted = (countNodeChild(c) > 0) ? true:false;
				
				$.confirm ({
				    text: 'Bạn có muốn xóa thư mục <span style="font-weight:bold">' + currentObj.name + "</span> không?",
				    title: "Xác nhận xóa!",
				    confirm: function(button) {
						var cid = $(c).parent().attr('id');
						var pid = cid.substring(o.dirIDprefix.length, cid.length);
						var postdata = {id:pid,delallchild:true}
						sendCommand({
							script:'ajax/privatecontent/deletedir',
							postdata:postdata,
							callbackSuccess: function (parsedData) {deleteNode(parsedData)}
						});
				    },
				    cancel: function(button) {
				        // do something
				    },
				    confirmButton: "Đồng ý xóa",
				    cancelButton: "Không",
				    post: false
				});
			}
			
			this.upload = function () {
				$('#box-upload').modal('show');
				
				$("#fileuploader").uploadFile({
					url: o.host + 'ajax/privatecontent/upload',
					fileName:"myfile",
					multiple:true,
					maxFileCount: 5,
					dragDropStr: "<span><b>Kéo thả các file vào đây!</b></span>",
					uploadErrorStr:"Tải lên có lỗi!"
				});
				
				$('#box-upload').on('hide.bs.modal', function () {
					$('#box-upload').find('.modal-body>.row>.col-xs-12>').remove();
					$('#box-upload').find('.modal-body>.row>.col-xs-12').append('<div id="fileuploader">Chọn file:</div>');
				});
			}

			this.copy = function () {
				
			}

			this.paste = function () {
				
			}
			
			this.openTreeOffset = function (nodeID) {
				openDirById(nodeID);
			}

			this.initialize = function() {
        		return this;
    		};
    		
    		this.getSelectedObj = function () {
    			return currentObj;
    		}

			return this.initialize();
		}
	});

})(jQuery);