angular.module("app").directive("directoryPicker", function ($rootScope, $q, $timeout, BackendService, DirPickerService) {
    return {
        restrict: 'E',
        replace: true,
        templateUrl: "../app/directives/directoryPicker/directoryPicker.html",
        scope: {
            instance: '=',
            dirPickerId: '@',
            multiselection: '@'
        },
        link: function (scope, element, attrs) {

            function afterInit() {
                if (typeof dhtmlXTreeObject == "undefined") {
                    return;
                }

                console.log("Initializing directory picker '" + scope.dirPickerId + "'");

                tree = new sqTree(scope.dirPickerId);
                tree.onClick = function (fileType, filePath, id, name, element, e) {
                    DirPickerService.getFilePath(id).then(function (result) {
                        if (result.success && result.filePath) {
                            scope.instance.selectedPath = result.filePath;
                        }
                    });
                    if (multiSelectionOn && e.ctrlKey) {
                        if (selectedPathsIds instanceof Array) {
                            if (selectedPathsIds.indexOf(id) < 0) {
                                selectedPathsIds.push(id);
                            } else {
                                selectedPathsIds.splice(selectedPathsIds.indexOf(id), 1);
                            }
                        } else {
                            if (id == selectedPathsIds) {
                                selectedPathsIds = [];
                            } else {
                                var oldId = selectedPathsIds;
                                selectedPathsIds = [oldId, id];
                            }
                        }
                    } else if (multiSelectionOn && e.shiftKey) {
                        selectedPathsIds = [];
                        if (id < lastSelectedId) {
                            for (var i = id; i <= lastSelectedId; i++) {
                                if (i in tree.itemsData) {
                                    selectedPathsIds.push(i);
                                }
                            }
                        } else {
                            for (var i = lastSelectedId; i <= id; i++) {
                                if (i in tree.itemsData) {
                                    selectedPathsIds.push(i);
                                }
                            }
                        }
                    } else {
                        selectedPathsIds = id;
                    }
                    lastSelectedId = id;
                    highlightSelected();
                    if (element.classList.contains("expanded")) {
                        return;
                    }
                    saveOpenStates();
                    DirPickerService.loadItemsForId(id, function (items) {
                        if ("id" in items && "item" in items && items.item.length > 0) {
                            tree.appendItemsTo(items.id, items.item);
                            tree.redraw();
                            loadOpenStates();
                            $(tree.treeElementInner).find(".item[data-id=" + items.id + "]").addClass("expanded");
                            highlightSelected();
                        }
                    });
                }

            }

            scope.instance.openDir = function (dirPath) {
                //load the first level of the tree
                if (DirPickerService.rootItemsLoaded) {
                    onOpen(dirPath);
                } else if (!DirPickerService.rootItemsLoaded && !DirPickerService.rootItemsLoading) {
                    DirPickerService.loadRootItems(tree, function () {
                        onOpen(dirPath);
                    });
                }
            }

            function saveOpenStates() {
                openStates.length = 0;
                var openedItems = $(tree.treeElementInner).find(".item.expanded");
                for (var i = 0; i < openedItems.length; i++) {
                    var id = openedItems[i].getAttribute('data-id');
                    openStates.push(id);
                }
            }

            function loadOpenStates() {
                for (var i = 0; i < openStates.length; i++) {
                    var id = openStates[i];
                    $(tree.treeElementInner).find(".item[data-id=" + id + "]").addClass("expanded");
                }
            }

            function highlightSelected() {
                $(tree.treeElementInner).find(".item.selected").removeClass("selected");
                if (selectedPathsIds instanceof Array) {
                    for (var i = 0; i < selectedPathsIds.length; i++) {
                        var id = selectedPathsIds[i];
                        $(tree.treeElementInner).find(".item[data-id=" + id + "]").addClass("selected");
                    }
                } else {
                    $(tree.treeElementInner).find(".item[data-id=" + selectedPathsIds + "]").addClass("selected");
                }
            }

            function onOpen(dirPath) {
                tree.collapseAll();

                pathIndex = 0;

                dirPath = dirPath.replace(/\\/g, "/"); //replace backslashes
                dirPath = dirPath.replace(/\/+/g, "/"); //replace multiple slashes
                pathsToLoad = dirPath.split("/");
                pathsToLoad[0] += "\\"; //drive path must end with \

                scope.instance.selectedPath = dirPath;
                pathsToLoadIndex = 0;

                loadNextSubdirectoryFast();
            }

            function loadNextSubdirectoryFast() {
                var nextItemToLoad = pathsToLoad[pathsToLoadIndex];

                var nextItemDom = $(tree.treeElementInner).find(".item").filter(function () {
                    return $(this).attr("data-text") == encodeURI(nextItemToLoad);
                });

                if (nextItemDom.length > 0) {
                    var itemToLoadId = nextItemDom.attr("data-id");
                    saveOpenStates();
                    DirPickerService.loadItemsForId(itemToLoadId, function (items) {
                        if ("id" in items && "item" in items && items.item.length > 0) {
                            tree.appendItemsTo(items.id, items.item);
                            tree.redraw();
                            loadOpenStates();
                            $(tree.treeElementInner).find(".item[data-id=" + itemToLoadId + "]").addClass("expanded");
                            pathsToLoadIndex++;
                            if (pathsToLoadIndex < pathsToLoad.length) {
                                loadNextSubdirectoryFast();
                            } else {
                                $(tree.treeElement).animate({
                                    scrollTop: $(tree.treeElementInner).find(".item[data-id=" + itemToLoadId + "]").offset().top - 80
                                }, 0);
                            }
                        }
                    });
                }
            }

            //returns promise
            scope.instance.getSelectedPaths = function () {
                if (selectedPathsIds instanceof Array) {
                    return DirPickerService.getFilePaths(selectedPathsIds);
                } else {
                    return DirPickerService.getFilePath(selectedPathsIds);
                }
            }

            scope.instance.setMultiSelection = function (multiSelection) {
                multiSelectionOn = multiSelection;
            }

            var tree;
            var pathsToLoad = [];
            var pathIndex = 0;
            var lastFolderId = 0;
            var selectedPathsIds = [];
            var openStates = [];
            var multiSelectionOn = false;
            var lastSelectedId = "";
            var pathsToLoadIndex = 0;
            var pathsToLoadInterval = 0;

            scope.instance.selectedPath = '';

            $timeout(afterInit, 0, false);
        }
    };
});