var docTypePermissionCtrl = (function () {

    function DocTypePermissionCache() {
        permissions = {};
    }

    var dtpCache = new DocTypePermissionCache();

    function DocTypePermissionCtrl() {
        this._queue = {};
    }

    /**
     * Scans elements with custom data attribute 'data-dtp' and disables the element.
     * 
     * When doc type permissions are checked and are valid for declared permission level, element is enabled.
     */
    DocTypePermissionCtrl.prototype.bind = function () {
        var self = this;
        
        $('[data-dtp]').each(function () {
            self.bindElt($(this));
        });
    };

    DocTypePermissionCtrl.prototype.bindElt = function ($elt) {
        /*if ($elt.attr('data-dtp-origin-class') === undefined) {
            $elt.attr('data-dtp-origin-class', $elt.attr('class'));
        }

        if ($elt.attr('data-dtp-origin-hidden') === undefined) {
            $elt.attr('data-dtp-origin-hidden', $elt.attr('hidden'));
        }

        if ($elt.attr('data-dtp-origin-disabled') === undefined) {
            $elt.attr('data-dtp-origin-disabled', $elt.attr('disabled'));
        }*/
    }

    DocTypePermissionCtrl.prototype.preventElt = function ($elt, permissionState) {
        switch (permissionState) {
            case 'class':
                $elt.attr('data-dtp-origin-class', $elt.attr('class'));
                var classes = $elt.attr('data-dtp-class');
                if (!classes) {
                    break;
                }
                classes = classes.split(' ');
                for (var i = 0; i < classes.length; i++) {
                    var c = classes[i];
                    if (!$elt.hasClass(c)) {
                        $elt.addClass(c);
                    }
                }
                break;
            case 'disabled':
                $elt.attr('data-dtp-origin-disabled', $elt.attr('disabled'));
                $elt.attr('disabled', 'true');
                break;
            case 'hidden':
            default: {
                $elt.attr('data-dtp-origin-hidden', $elt.attr('hidden'));
                $elt.attr('hidden', 'true');
                $elt.css('display', 'none');
                break;
            }
        }

        var mode = $elt.attr('data-dtp-mode');
        if (mode && mode === 'parent') {
            this.preventChildren($elt, permissionState);
        }
    };

    DocTypePermissionCtrl.prototype.allowElt = function ($elt, permissionState, override) {
        switch (permissionState) {
            case 'class': {
                var originClasses = $elt.attr('data-dtp-origin-class') ? $elt.attr('data-dtp-origin-class').split(' ') : [];
                var classes = $elt.attr('data-dtp-class');
                if (!classes) {
                    break;
                }
                classes = classes.split(' ');
                for (var i = 0; i < classes.length; i++) {
                    var c = classes[i];
                    if (override) {
                        if ($elt.hasClass(c) &&
                            (override || (originClasses.indexOf(c) === -1) && !override)) {
                            $elt.removeClass(c);
                        }
                    }
                    
                }
                break;
            }
            case 'disabled': {
                if (!$elt.hasClass('disabled')) {
                    if ($elt.attr('data-dtp-origin-disabled') && !override) {
                        $elt.attr('disabled', $elt.attr('data-dtp-origin-disabled'));
                    }
                    else {
                        $elt.removeAttr('disabled');
                    }
                }
                break;
            }
            case 'hidden':
            default: {
                if (!$elt.hasClass('hidden')) {
                    if ($elt.attr('data-dtp-origin-hidden')) {
                        $elt.attr('hidden', $elt.attr('data-dtp-origin-hidden'));
                    }
                    else {
                        $elt.removeAttr('hidden');
                    }
                    
                    $elt.css('display', '');
                }
                break;
            }
        }

        var mode = $elt.attr('data-dtp-mode');
        if (mode && mode === 'parent') {
            this.allowChildren($elt, permissionState, override);
        }
    };

    DocTypePermissionCtrl.prototype.preventChildren = function ($parent, permissionState) {
        var self = this;
        $parent.find('[data-dtp-state]').each(function () {
            var $child = $(this);
            self.preventElt($child, $child.attr('data-dtp-state') || permissionState);
        });
    };


    DocTypePermissionCtrl.prototype.allowChildren = function ($parent, permissionState, override) {
        var self = this;
        $parent.find('[data-dtp-state]').each(function () {
            var $child = $(this);
            self.allowElt($child, $child.attr('data-dtp-state') || permissionState, override);
        });
    };

    DocTypePermissionCtrl.prototype.loadPermissions = async function (docType, $parent, employeeId, permissionsAll, permissionsOwn) {
        dtpCache.permissions = await this.fetchDocTypePermissions(docType, employeeId, permissionsAll, permissionsOwn);
        for (var qname in this._queue) {
            var q = this._queue[qname];
            for (var i = 0; i < q.length; i++) {
                var qitem = q[i];
                if (qitem.done) {
                    await qitem.done();
                }
                else if (typeof qitem === 'function') {
                    qitem();
                }

            }
            delete this._queue[qname];
        }
        this.evalPermissions(dtpCache.permissions, $parent);
        return dtpCache.permissions;
    };

    DocTypePermissionCtrl.prototype.evalPermissions = function (permissions, $parent) {
        var self = this;
        if (!permissions && !dtpCache.permissions) {
            this.queue(function () {
                self.evalPermissions(permissions, $parent);
            });
            return;
        }

        if (!permissions) {
            permissions = dtpCache.permissions;
        }

        var $elts = (!$parent) ? $('[data-dtp') : $parent.find('[data-dtp]');
        $elts.each(function () {
            var $elt = $(this);
            var $mock = $('<div style="position: absolute; background: black; opacity: 0.7;"></div>');
            $mock.width($elt.outerWidth());
            $mock.height($elt.outerHeight());
            $mock.css({
                'top': $elt.position().top,
                'left': $elt.position().left
            });
            $elt.parent().append($mock);
            
            self.bindElt($elt);

            var permissionId = $elt.attr('data-dtp');
            var permissionState = $elt.attr('data-dtp-state') || 'hidden';
            var override = $elt.attr('data-dtp-override') === "true"
            var perm = permissions[permissionId];
            if (perm.HasPermission) {
                self.allowElt($elt, permissionState, override);
            }
            else {
                self.preventElt($elt, permissionState, override);
            }
            $mock.remove();
        });
    };

    DocTypePermissionCtrl.prototype.fetchDocTypePermission = function (docType, level) {
        return $.ajax({
            url: $("#GetDocTypeHasPermission").val() + qparams({
                docType: docType,
                level: level
            }),
            method: 'GET',
            dataType: 'json',
            success: function (docTypePermission) {
                return docTypePermission;
            }
        });
    };

    DocTypePermissionCtrl.prototype.fetchDocTypePermissions = function (docType, employeeId, permissionsAll, permissionsOwn) {
        return $.ajax({
            url: $("#GetDocTypeHasPermissions").val() + qparams({
                docType: docType,
                employeeId: employeeId,
                permissionsAll: permissionsAll,
                permissionsOwn: permissionsOwn
            }),
            method: 'GET',
            dataType: 'json',
            success: function (docTypePermissions) {
                return docTypePermissions;
            }
        });
    };

    DocTypePermissionCtrl.prototype.queue = function (p, qname) {
        if (qname === undefined) {
            qname = 'def';
        }

        if (this._queue[qname] === undefined) {
            this._queue[qname] = [];
        }
        this._queue[qname].push(p);
    };

    DocTypePermissionCtrl.prototype.decorateElt = function (elt, dtp, dtpState, selector) {
        var $elt = null;
        if (selector) {
            $elt = $(elt).find(selector);
        }
        else {
            $elt = $(elt);
        }
        $elt.attr('data-dtp', dtp);
        if (dtpState) {
            $elt.attr("data-dtp-state", dtpState);
        }
        return elt;
    };

    return new DocTypePermissionCtrl();
})();