if (jQuery)
    (function ($) {
        $.extend($.fn, {
            violetFileManager: function (o) {
                if (!o)
                    var o = {};
                if (o.tree == undefined)
                    o.tree = null;
                if (o.grid == undefined)
                    o.grid = null;

                if (o.maincontainer == undefined)
                    o.maincontainer = null;
                if (o.titlebar == undefined)
                    o.titlebar = null;
                if (o.toolsbar == undefined)
                    o.toolsbar = null;
                if (o.statusbar == undefined)
                    o.statusbar = null;

                if (o.oTree == undefined)
                    o.oTree = null;
                if (o.oGrid == undefined)
                    o.oGrid = null;
                if (o.host == undefined)
                    o.host = 'http://localhost/';
                if (o.hostmodule == undefined)
                    o.hostmodule = 'privatecontent/';
                if (o.script == undefined)
                    o.script = 'getcontent';
                if (o.data == undefined)
                    o.data = null;
                if (o.datasource == undefined)
                    o.datasource = 'ajax';

                o.host = o.host + 'ajax/';

                var isDev = false;
                var contextmenu = null;
                var oContainer = this;
                var tree = [];
                var totalItem = 0;
                var countItem = 0;
                var maxWidth = 0;
                var treeCurrentNode = null;
                var self = this;
                var oClipBoard = {items: null, act: null};

                /**
                 * Toolbar defined
                 * */
                var btnNewFolder = $('#' + o.toolsbar + ' > DIV.btn-group.basic > #btnNewFolder');
                var btnDel = $('#' + o.toolsbar + ' > DIV.btn-group.basic > #btnDel');
                var btnCopy = $('#' + o.toolsbar + ' > DIV.btn-group.basic > #btnCopy');
                var btnCut = $('#' + o.toolsbar + ' > DIV.btn-group.basic > #btnCut');
                var btnPaste = $('#' + o.toolsbar + ' > DIV.btn-group.basic > #btnPaste');
                var btnShare = $('#' + o.toolsbar + ' > DIV.btn-group.social > #btnShare');
                var btnPreview = $('#' + o.toolsbar + ' > DIV.btn-group.social > #btnPreview');
                var btnDownload = $('#' + o.toolsbar + ' > DIV.btn-group.creation > #btnDownload');
                var btnUpload = $('#' + o.toolsbar + ' > DIV.btn-group.creation > #btnUpload');
                var btnRefresh = $('#' + o.toolsbar + ' > DIV.btn-group.control > #btnRefresh');

                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.parseData == undefined)
                        p.parseData = null;
                    if (p.self == undefined)
                        p.self = this;

                    if (p.script != null && (o.datasource == 'ajax' || isDev)) {
                        $.post(o.host + o.hostmodule + p.script, p.postdata, function (data) {
                            if (data) {
                                parseData = $.parseJSON(data);
                                p.parseData = parseData;
                            }

                            if (p.callbackSuccess != null) {
                                if (parseInt(parseData.ERROR.errCode) === 0)
                                    p.callbackSuccess(parseData);
                                else {
                                    p.callbackFail(parseData.ERROR);
                                }
                            }

                        }).done(function () {
                            if (p.callbackDone != null)
                                p.callbackDone(p.parseData);
                        }).fail(function () {
                            if (p.callbackFail != null)
                                p.callbackFail(this);
                        }).always(function () {
                            if (p.callbackAlways != null)
                                p.callbackAlways(this);
                        });
                    }
                    else if (o.datasource == 'json') {
                        if (p.callbackSuccess != null)
                            p.callbackSuccess(o.data);
                        if (p.callbackDone != null)
                            p.callbackDone(this);
                    }

                };

                var getDirTreeMaxWidth = function () {
                    var scrWidth = $(o.maincontainer).width();
                    return parseInt(scrWidth / 2);
                }

                var layoutRender = function () {
                    var scrWidth = $('#' + o.maincontainer).width();
                    var scrHeght = $(window).height();
                    var dirTreeHeight = scrHeght - $('#' + o.titlebar).height() - $('#' + o.toolsbar).height() - $('#' + o.statusbar).height() - 2;
                    $('#' + o.tree).parent().height(dirTreeHeight);
                    $('#' + o.grid).parent().height(dirTreeHeight);
                    $('#' + o.grid).parent().width('calc(100% - ' + ($('#' + o.tree).parent().width() + 8) + 'px)');
                    var scollWidth = $('#' + o.grid).parent().width();
                    maxWidth = getDirTreeMaxWidth();
                    $(o.tree).height(dirTreeHeight - 5);
                }

                var createFileManager = function (parseData) {
                    o.data = parseData;
                    totalItem = o.data.DIRECTORIES.length;
                    o.oTree = $('#' + o.tree).violetTree({data: o.data.DIRECTORIES, manager: oContainer});
                    o.oGrid = $('#' + o.grid).violetGrid({data: o.data, manager: oContainer});
                };

                var getAllDirChild = function (parentID, aryChild) {
                    parentID = parentID == null ? 0 : parentID;
                    var dirList = searchItemsByParent(parentID, 'directory');
                    var index = aryChild.length;
                    aryChild[index] = parentID;
                    if (dirList.length > 0) {
                        for (var i = 0; i < dirList.length; i++) {
                            getAllDirChild(dirList[i].id, aryChild);
                        }
                    }
                }

                var buildTreeFromParent = function (dirID, node) {
                    var aryChildFiles = [];
                    var aryChildDirs = [];
                    var aryChildIDs = [];
                    var aryTmp = [];
                    var dir = o.data.DIRECTORIES[searchItemByID(dirID, 'directory')];
                    aryChildDirs = searchItemsByParent(dirID, 'directory');
                    aryChildFiles = searchItemsByParent(dirID, 'file');

                    node.id = dir.id;
                    node.name = dir.name;
                    node.type = 'directory';

                    $(aryChildDirs).each(function (index) {
                        var id = this.id;
                        var name = this.name;
                        var type = 'directory';
                        var cDir = {id: id, name: name, type: type, childs: null};
                        aryChildIDs[index] = cDir;
                    });

                    if ($(aryChildFiles).length > 0) {
                        if (node.files == undefined)
                            node.files = [];
                        $(aryChildFiles).each(function (index) {
                            var id = this.id;
                            var name = this.name;
                            var type = 'file';
                            var cFile = {id: id, name: name, type: type};
                            node.files[index] = cFile;
                        });
                    }

                    if ($(aryChildDirs).length > 0) {
                        if (node.childs == undefined)
                            node.childs = [];
                        $(aryChildIDs).each(function (index) {
                            node.childs[index] = new Object;
                            buildTreeFromParent(aryChildIDs[index].id, node.childs[index]);
                        });
                    }
                }

                var checkChildExisted = function (id) {
                    var dirList = searchItemsByParent(id, 'directory');
                    var fileList = searchItemsByParent(id, 'file');
                    return (dirList.length > 0) || (fileList.length > 0);
                }

                var doneInit = function () {
                    bindEventToToolbars();
                    documentEventsBinding();
                };

                var failInit = function (er) {
                    bootbox.alert(er.err);
                }

                var init = function () {
                    layoutRender();
                    $('#' + o.tree).parent().resizable({
                        maxWidth: maxWidth,
                        minWidth: 220,
                        handles: "e",
                        resize: function (event, ui) {
                            layoutRender();
                        }
                    });
                    $(window).resize(function () {
                        layoutRender();
                        $('#' + o.tree).parent().resizable({maxWidth: maxWidth});
                    });
                    sendCommand({postdata: null, callbackSuccess: createFileManager, callbackDone: doneInit, callbackFail: failInit});
                };

                var searchItemByID = function (id, type) {
                    var data = {};
                    switch (type) {
                        case 'directory':
                            data = o.data.DIRECTORIES;
                            break;
                        case 'file':
                            data = o.data.FILES;
                            break;
                        default:
                            break;
                    }

                    //for (var i = 0; i < data.length; i++) {
                    for (var i in data) {
                        if (data[i].id == id) {
                            return i;
                        }
                    }
                }

                var searchItemsByParent = function (parentID, type) {
                    var data = {};
                    var aryItem = [];
                    var index = aryItem.length;

                    switch (type) {
                        case 'directory':
                            data = o.data.DIRECTORIES;
                            break;
                        case 'file':
                            data = o.data.FILES;
                            break;
                        default:
                            break;
                    }

                    for (i in data) {
                        if (data[i].parentID == parentID) {
                            aryItem[index] = data[i];
                            index++;
                        }
                    }

                    return aryItem;
                }

                /**************************
                 * TOOLBAR EVENTS - START *
                 **************************/
                var btnRefreshClick = function (obj) {
                    $(o).find('i').addClass('icon-spin');
                    sendCommand({postdata: null,
                        callbackSuccess: function (parseData) {
                            o.data = parseData;
                            self.updateData({updateAll: true});
                            o.oTree.refeshTree();
                        },
                        callbackDone: function () {
                            $(o).find('i').removeClass('icon-spin');
                        },
                        callbackFail: failInit
                    });
                }

                var btnNewFolderClick = function () {
                    createFolderStart();
                }

                var btnUploadClick = function () {
                    uploadStart();
                    upload_init();

                }

                var btnDelClick = function () {
                    var items = o.oGrid.getHightLightItem();
                    if ($(items).length == 0) {
                        var dirID = $(o.oTree.getSelectedNode()).attr('id');
                        var item = o.data.DIRECTORIES[searchItemByID(dirID, 'directory')];
                        item.type = 'directory';
                        items = [item];
                    }
                    self.deleteItem(items);
                }

                var btnCopyClick = function () {
                    copy('copy');
                }

                var btnPasteClick = function () {
                    paste();
                }

                var btnCutClick = function () {
                    copy('move');
                }

                var bindEventToToolbars = function () {
                    $(btnRefresh).click(function (e) {
                        btnRefreshClick(this)
                    });

                    $(btnNewFolder).click(function (e) {
                        btnNewFolderClick()
                    });
                    $(btnUpload).click(function (e) {
                        btnUploadClick()
                    });

                    $(btnDel).click(function (e) {
                        btnDelClick()
                    });
                    $(btnCopy).click(function (e) {
                        btnCopyClick()
                    });
                    $(btnCut).click(function (e) {
                        btnCutClick()
                    });
                    $(btnPaste).click(function (e) {
                        btnPasteClick()
                    })

                    /*btnShare
                     btnPreview
                     btnDownload
                     btnUpload*/
                }
                /************************
                 * TOOLBAR EVENTS - END *
                 ************************/

                /***********************************
                 * DOCUMENT EVENTS BINDING - START *
                 ***********************************/
                var documentEventsBinding = function () {
                    $(document).bind('keydown', function (e) {
                        switch (e.which) {
                            case 113:
                            case 27:
                                var gridSelectedItems = o.oGrid.getHightLightItem();
                                if ($(gridSelectedItems).length > 0) {
                                    o.oGrid.rename(e.which);
                                } else {
                                    o.oTree.rename(e.which);
                                }
                                break;
                            case 46:
                                //delete
                                btnDelClick();
                                break;
                            case 65:
                                if (e.ctrlKey) {
                                    o.oGrid.selectAllNode();
                                }
                                break;
                            default:
                                break;
                        }
                    });
                }
                /***********************************
                 * DOCUMENT EVENTS BINDING - END *
                 ***********************************/

                /*******************************
                 * CREATE FOLDER - START *
                 *******************************/
                var createFolderStart = function () {
                    var promptOptions = {
                        title: "Tạo thư mục mới",
                        buttons: {
                            confirm: {
                                label: "Lưu"
                            },
                            cancel: {
                                label: "Hủy"
                            }
                        },
                        callback: function (result) {
                            if (result === null) {
                            } else {
                                createFolder(treeCurrentNode, result);
                            }
                        }
                    };

                    return bootbox.prompt(promptOptions);
                }

                var uploadStart = function () {

                    var promptOptions = {
                        title: "Tải lên",
                        message: "<form id='upload' method='post' action='http://api.violet.vn/space/upload' enctype='multipart/form-data'><div id='drop'>Kéo thả tệp vào đây <a> Chọn tệp </a><input type='hidden' name='dir' value='" + self.getTreeCurrentNode() + "'/><input type='hidden' name='userid' value='33'/><input type='file' name='upload_file' multiple /></div><ul></ul></form>",
                        buttons: {
                            success: {
                                label: "Tải lên",
                                className: "btn btn-primary",
                                callback: function () {

                                }
                            },
                        }
                    };

                    return bootbox.dialog(promptOptions);
                }
                var upload_done = function (result) {
                    alert(JSON.stringify(result, null, 4));
                }

                var upload_init = function () {
                    var ul = $('#upload ul');

                    $('#drop a').click(function () {
                        $(this).parent().find('input').click();
                    });
                    $('#upload').fileupload({
                         dropZone: $('#drop'),
                        add: function (e, data) {

                            var tpl = $('<li class="working"><input type="text" value="0" data-width="48" data-height="48"' +
                                    ' data-fgColor="#0788a5" data-readOnly="1" data-bgColor="#3e4043" /><p></p><span></span></li>');
                            tpl.find('p').text(data.files[0].name)
                                    .append('<i>' + formatFileSize(data.files[0].size) + '</i>');
                            data.context = tpl.appendTo(ul);
                            tpl.find('input').knob();
                            tpl.find('span').click(function () {

                                if (tpl.hasClass('working')) {
                                    jqXHR.abort();
                                }

                                tpl.fadeOut(function () {
                                    tpl.remove();
                                });

                            });
                            //alert(JSON.stringify(data, null, 4));
                            var jqXHR = data.submit();
                        },
                        progress: function (e, data) {

                            // Calculate the completion percentage of the upload
                            var progress = parseInt(data.loaded / data.total * 100, 10);

                            // Update the hidden input field and trigger a change
                            // so that the jQuery knob plugin knows to update the dial
                            data.context.find('input').val(progress).change();

                            if (progress == 100) {
                                data.context.removeClass('working');
                            }
                        },
                        fail: function (e, data) {
                            // Something has gone wrong!
                            data.context.addClass('error');
                        }

                    });
                    $(document).on('drop dragover', function (e) {
                        e.preventDefault();
                    });
                    function formatFileSize(bytes) {
                        if (typeof bytes !== 'number') {
                            return '';
                        }

                        if (bytes >= 1000000000) {
                            return (bytes / 1000000000).toFixed(2) + ' GB';
                        }

                        if (bytes >= 1000000) {
                            return (bytes / 1000000).toFixed(2) + ' MB';
                        }

                        return (bytes / 1000).toFixed(2) + ' KB';
                    }

                };

                var createFolder = function (parent, name) {
                    var postdata = {fname: name, fparentid: parent};
                    var script = 'createdir';
                    /*isDev = true;*/
                    sendCommand({
                        postdata: postdata,
                        script: script,
                        callbackSuccess: function (parseData) {
                            createFolderFinish(parseData);
                        },
                        callbackFail: function () {
                        }
                    });
                }

                var createFolderFinish = function (parseData) {
                    /*isDev = false;*/
                    if (parseData.ERROR.errCode == 0) {
                        var node = {id: parseData.id, name: parseData.name, parentID: parseData.parentID};
                        o.oTree.createNode(node);
                        o.data.DIRECTORIES[$(o.data.DIRECTORIES).length] = node;
                        if (o.oGrid)
                            o.oGrid.reloadGrid();
                    }
                }
                /*******************************
                 * CREATE FOLDER - END         *
                 *******************************/
                /********************************
                 * COPY & PASTE & MOVE - START  *
                 ************=*******************/
                var copy = function (act) {
                    //detect selected items
                    //push to clipboard
                    var items = o.oGrid.getHightLightItem();

                    if ($(items).length == 0) {
                        var node = o.oTree.getSelectedNode();
                        var itemID = $(node).attr('id');

                        if (itemID == 0)
                            return false;

                        items[0] = o.data.DIRECTORIES[searchItemByID(itemID, 'directory')];
                        items[0].type = 'directory';
                    }

                    if ($(items).length > 0) {
                        oClipBoard.items = items;
                        oClipBoard.act = act;
                    }
                    return true;
                }

                var paste = function () {
                    if ((oClipBoard.act != 'copy'
                            && oClipBoard.act != 'move')
                            || oClipBoard.items == null)
                        return;

                    var items = [];
                    var destination = self.getTreeCurrentNode();
                    if (oClipBoard.act != 'copy') {
                        $(oClipBoard.items).each(function (index) {
                            var node = new Object;
                            if (this.type == 'directory')
                                buildTreeFromParent(this.id, node);
                            else {
                                node.id = this.id;
                                node.type = 'file';
                            }

                            items[index] = node;
                        });
                    }
                    else {
                        items = oClipBoard.items;
                    }

                    var postdata = {act: oClipBoard.act, destination: destination, data: JSON.stringify(items)};
                    var script = oClipBoard.act;

                    sendCommand({
                        postdata: postdata,
                        script: script,
                        callbackSuccess: function (parseData) {
                            if (oClipBoard.act == 'copy') {
                                $(parseData.DIRECTORIES).each(function (index) {
                                    o.data.DIRECTORIES[$(o.data.DIRECTORIES).length] = this;
                                });

                                $(parseData.FILES).each(function (index) {
                                    o.data.FILES[$(o.data.FILES).length] = this;
                                });

                                o.data.DIRECTORIES.sort(function (a, b) {
                                    return a.parentID - b.parentID;
                                });

                                o.oTree.setData(o.data.DIRECTORIES);
                                o.oGrid.setData(o.data);
                                o.oTree.createCopyNode(parseData.DIRECTORIES);
                                o.oGrid.reloadGrid();
                            }
                            else if (oClipBoard.act == 'move') {

                            }
                        }
                    });

                }

                var move = function () {

                }

                var copyTo = function () {

                }

                var moveTo = function () {

                }

                /*****************************
                 * COPY & PASTE & MOVE - END *
                 *****************************/

                this.deleteItem = function (item) {

                    var confirmText = 'Bạn có muốn xóa ';

                    if ($.isArray(item) && item.length > 1) {
                        confirmText += 'các thư mục (và files) đã chọn?';
                    }
                    else if (item.length == 1) {
                        if (item[0].id == 0)
                            return false;
                        confirmText += (item[0].type == 'directory') ? 'thư mục' : 'file';
                        confirmText += ' <span style="font-weight:bold">' + item[0].name + "</span> không?";
                    }

                    confirmText += '<br /><div style="color:red">(hành động này sẽ xóa tất cả thư mục con và các file trong các thư mục đã chọn)</div>';

                    var parentID = item[0].parentID;

                    for (var i = 0; i < item.length; i++) {
                        if (item[i].type == 'directory') {
                            var aryChildDirTmp = [];
                            var aryChildDirID = [];
                            var aryChildFiles = searchItemsByParent(item[i].id, 'file');
                            var aryChildDirs = [];

                            getAllDirChild(item[i].id, aryChildDirTmp);
                            for (var d = 1; d < aryChildDirTmp.length; d++) {
                                aryChildDirID[d - 1] = aryChildDirTmp[d];
                            }

                            for (var j = 0; j < aryChildDirID.length; j++) {
                                if (o.data.DIRECTORIES[searchItemByID(aryChildDirID[j], 'directory')] != undefined)
                                    aryChildDirs[aryChildDirs.length] = o.data.DIRECTORIES[searchItemByID(aryChildDirID[j], 'directory')];

                                var aryTmp = searchItemsByParent(aryChildDirID[j], 'file');
                                if (aryTmp.length > 0)
                                    for (var f in aryTmp) {
                                        aryChildFiles[aryChildFiles.length] = aryTmp[f];
                                    }
                            }

                            item[i].childDirs = aryChildDirs;
                            item[i].childFiles = aryChildFiles;
                        }
                    }

                    var confirmOptions = {
                        message: confirmText,
                        buttons: {
                            confirm: {
                                label: "Xóa"
                            },
                            cancel: {
                                label: "Không xóa"
                            }
                        },
                        callback: function (result) {
                            if (result) {
                                var delobj = JSON.stringify(item);
                                var postdata = {delobj: delobj};
                                var script = 'delete';
                                sendCommand({
                                    postdata: postdata,
                                    script: script,
                                    callbackSuccess: function (parseData) {
                                        if ($(parseData.DIRECTORIES).length > 0) {
                                            $(parseData.DIRECTORIES).each(function (index) {
                                                o.oTree.deletion(this);
                                                o.oGrid.deletion(this, 'directory');
                                            });
                                        }

                                        if ($(parseData.FILES).length > 0) {
                                            $(parseData.FILES).each(function (index) {
                                                var file = o.data.FILES[searchItemByID(this, 'file')];
                                                o.oGrid.deletion(this, file.minetype);
                                            });
                                        }
                                    },
                                    callbackDone: function (obj) {
                                        if ($(parseData.DIRECTORIES).length > 0) {
                                            $(parseData.DIRECTORIES).each(function (index) {
                                                delete o.data.DIRECTORIES[searchItemByID(this, 'directory')];
                                            });
                                        }

                                        if ($(parseData.FILES).length > 0) {
                                            $(parseData.FILES).each(function (index) {
                                                delete o.data.FILES[searchItemByID(this, 'file')];
                                            });
                                        }

                                        o.oTree.setData(o.data.DIRECTORIES);
                                        o.oGrid.setData(o.data);
                                        self.setTreeCurrentNode(parentID);
                                        o.oGrid.reloadGrid();
                                    },
                                    callbackFail: function () {
                                    }
                                });
                            }
                        }
                    };

                    bootbox.confirm(confirmOptions);
                }

                this.setTreeCurrentNode = function (treeNode) {
                    //fire when click a node on Tree
                    //then fire action of Grid
                    treeCurrentNode = treeNode;
                    if (o.oGrid)
                        o.oGrid.reloadGrid();
                };

                this.getTreeCurrentNode = function () {
                    return treeCurrentNode;
                }

                this.gridNodeDblClick = function (node) {
                    if (node.minetype == 'directory') {
                        var treeNode = $('#' + o.tree).find('UL.vstree[rel^="node' + node.parentID + '"] > LI[rel^="folder"] > A#' + node.id);
                        o.oTree.activeNode(treeNode);
                    }
                    else {
                        //execute or preview file
                    }
                };

                this.createNewFolder = function () {

                }

                this.updateData = function (p) {
                    if (p.item == undefined)
                        p.item = null;
                    if (p.updateAll == undefined)
                        p.updateAll = false;
                    if (p.from == undefined)
                        p.from = null;
                    if (p.type == undefined)
                        p.type = null;
                    if (p.callback == undefined)
                        p.callback = null;

                    var obj = p.from == 'tree' ? o.oGrid : o.oTree;
                    if (!p.updateAll) {
                        var index = searchItemByID(p.item.id, p.type);
                        switch (p.type) {
                            case 'directory':
                                o.data.DIRECTORIES[index].name = p.item.name;
                                o.data.DIRECTORIES[index].parentID = p.item.parentID;
                                break;
                            case 'file':
                                o.data.FILES[index].name = p.item.name;
                                o.data.FILES[index].parentID = p.item.parentID;
                                o.data.FILES[index].minetype = p.item.minetype;
                                break;
                            default:
                                break;
                        }
                    }

                    o.oTree.setData(o.data.DIRECTORIES);
                    o.oGrid.setData(o.data);

                    if (p.callback != null) {
                        eval('obj.' + p.callback + '(p.item);')
                    }

                    //call sendCommand
                }

                this.searchItemsByParent = function (parentID, type) {
                    return searchItemsByParent(parentID, type);
                }

                this.searchItemByID = function (parentID, type) {
                    return searchItemByID(parentID, type);
                }

                this.initialize = function () {
                    init();
                    return this;
                };

                return this.initialize();
            }
        });
    })(jQuery);