/** @class */
jscape.AccountManagementService = jscape.ManagementService.extend(
    /** @lends {jscape.AccountManagementService.prototype} */
{
    listUsers: function (startIndex, count, query) {
        return this._request("GET", "/rest/accounts").matrix({start: startIndex, count: count}).send(query)
                .then(function (data) { return jscape.Page.fromJSON(data, jscape.UserInfo.fromJSON); });
    },

    getUsernames: function() {
        return this._request("GET", "/rest/accounts").options({global: false}).matrix({names: true}).send()
                .then(function (data) { return (data || []).sort(); });
    },

    getUser: function(username) {
        return this._request("GET", "/rest/accounts/{account}").uri({account: username}).send()
                .then(function(data) { return jscape.UserData.fromJSON(data); });
    },

    getPersonalInfo: function(username) {
        return this._request("GET", "/rest/accounts/{account}/personal-info").uri({account: username}).send()
                        .then(function(data) { return jscape.PersonalInfoData.fromJSON(data); });
    },

    setPersonalInfo: function(username, data) {
        return this._request("PUT", "/rest/accounts/{account}/personal-info").uri({account: username}).send(data);
    },

    addUser: function(data, templateName) {
        return this._request("POST", "/rest/accounts").headers({"x-js-template": templateName}).send(data)
                .then(function(data) { return jscape.UserInfo.fromJSON(data); });
    },

    updateUser: function(username, data) {
        return this._request("PUT", "/rest/accounts/{account}").uri({account: username}).send(data)
                .then(function(data) { return jscape.UserInfo.fromJSON(data); });
    },

    deleteUser: function(username) {
        return this._request("DELETE", "/rest/accounts/{account}").uri({account: username}).send();
    },

    changeUserPassword: function (username, password) {
        return this._request("POST", "/rest/accounts/{account}/changepassword").uri({account: username}).send(password);
    },

    testPasswordCompliance: function(username, password) {
        return this._request("POST", "/rest/compliance/test-pwd").sendSync({account: username, password: password});
    },

    resetUserOtp: function(username) {
        return this._request("POST", "/rest/accounts/{account}/resetotp").uri({account: username}).send();
    },

    getUserQuota: function(username) {
        return this._request("GET", "/rest/accounts/{account}/quota").uri({account: username}).send()
                        .then(function (data) { return jscape.UserQuotaInfo.fromJSON(data); });
    },

    getUserTemplateNames: function() {
        return this._request("GET", "/rest/account-templates").send();
    },

    getUserTemplate: function (templateName) {
        return this._request("GET", "/rest/account-templates/{template}").uri({template: templateName}).send()
                .then(function (data) { return jscape.UserData.fromJSON(data); });
    },

    getGroupNames: function () {
        return this._request("GET", "/rest/groups").send();
    },

    getReverseProxyNames: function() {
        return this._request("GET", "/rest/reverse-proxies").options({global: false}).matrix({names: true}).send();
    },

    listDirectoryMonitors: function(username, startIndex, count, query) {
        return this._request("GET", "/rest/accounts/{account}/dir-monitors").options({global: false}).uri({account: username}).matrix({start: startIndex, count: count}).send(query)
                .then(function (data) { return jscape.Page.fromJSON(data, jscape.DirectoryMonitorInfo.fromJSON); });
    },

    listContacts: function (startIndex, count, query) {
        return this._request("GET", "/rest/v2/contacts").matrix({start: startIndex, count: count}).send(query)
                .then(function (data) { return jscape.Page.fromJSON(data, jscape.ContactInfo.fromJSON); });
    },

    getContact: function(id) {
        return this._request("GET", "/rest/v2/contacts/{contact}").uri({contact: id}).send()
                .then(function(data) { return jscape.ContactData.fromJSON(data); });
    },

    addContact: function(data) {
        return this._request("POST", "/rest/v2/contacts").send(data)
                .then(function(data) { return jscape.ContactInfo.fromJSON(data); });
    },

    updateContact: function(id, data) {
        return this._request("PUT", "/rest/v2/contacts/{contact}").uri({contact: id}).send(data)
                .then(function(data) { return jscape.ContactInfo.fromJSON(data); });
    },

    deleteContact: function(id) {
        return this._request("DELETE", "/rest/v2/contacts/{contact}").uri({contact: id}).send();
    },

    listWebThemes: function (startIndex, count, query) {
        return this._request("GET", "/rest/web-themes").matrix({start: startIndex, count: count}).send(query)
                .then(function (data) { return jscape.Page.fromJSON(data, jscape.WebThemeInfo.fromJSON); });
    },

    getWebThemeNames: function () {
        return this._request("GET", "/rest/web-themes").options({global: false}).matrix({names: true}).send()
                .then(function (data) { return (data || []).sort(); });
    },

    getWebTheme: function(themeName) {
        return this._request("GET", "/rest/web-themes/{theme}").uri({theme: themeName}).send()
                .then(function(data) { return jscape.WebThemeData.fromJSON(data);})
    },

    addWebTheme: function(data) {
        return this._request("POST", "/rest/web-themes").send(data)
                .then(function(data) { return jscape.WebThemeInfo.fromJSON(data);})
    },

    updateWebTheme: function(themeName, data) {
        return this._request("PUT", "/rest/web-themes/{theme}").uri({theme: themeName}).send(data)
                .then(function(data) { return jscape.WebThemeInfo.fromJSON(data);})
    },

    deleteWebTheme: function(themeName) {
        return this._request("DELETE", "/rest/web-themes/{theme}").uri({theme: themeName}).send();
    },

    webThemeUri: function(name) {
        return this._request("POST", "/rest/web-themes/{theme}/uri", false).uri({theme: name}).send();
    },

    listDropZones: function (startIndex, count, query, owned) {
        return this._request("GET", "/rest/drop-zones").matrix({start: startIndex, count: count, owned: !!owned}).send(query)
                .then(function (data) { return jscape.Page.fromJSON(data, jscape.DropZoneInfo.fromJSON); });
    },

    getDropZone: function(name) {
        return this._request("GET", "/rest/drop-zones/{zone}").uri({zone: name}).send()
                .then(function(data) { return jscape.DropZoneData.fromJSON(data); });
    },

    addDropZone: function(data) {
        return this._request("POST", "/rest/drop-zones").send(data)
                .then(function(data) { return jscape.DropZoneInfo.fromJSON(data); });
    },

    updateDropZone: function(name, data) {
        return this._request("PUT", "/rest/drop-zones/{zone}").uri({zone: name}).send(data)
                .then(function(data) { return jscape.DropZoneInfo.fromJSON(data); });
    },

    deleteDropZone: function(name) {
        return this._request("DELETE", "/rest/drop-zones/{zone}").uri({zone: name}).send();
    },

    dropZoneUri: function(name) {
        return this._request("POST", "/rest/drop-zones/{zone}/uri", false).uri({zone: name}).send();
    },

    listAdhocTransfers: function (startIndex, count, query) {
        return this._request("GET", "/rest/adhoc-transfers").matrix({start: startIndex, count: count}).send(query)
                .then(function (data) { return jscape.Page.fromJSON(data, jscape.AdHocTransferInfo.fromJSON); });
    },

    getAdHocTransfer: function(transferId) {
        return this._request("GET", "/rest/adhoc-transfers/{id}").uri({id: transferId}).send()
                .then(function(data) { return jscape.AdHocTransferInfo.fromJSON(data); });
    },

    extendAdHocTransfer: function(transferId, expires, transferObjectIds) {
        return this._request("PUT", "/rest/adhoc-transfers/{id}/extend").uri({id: transferId}).send({expires: expires, objectIds: transferObjectIds || []})
                .then(function(info) { return jscape.AdHocTransferInfo.fromJSON(info); });
    },

    revokeAdHocTransfer: function(transferId, transferObjectIds) {
        return this._request("PUT", "/rest/adhoc-transfers/{id}/revoke").uri({id: transferId}).send({objectIds: transferObjectIds || []})
                .then(function(info) { return jscape.AdHocTransferInfo.fromJSON(info); });
    },

    generateKeyPair: function(keyType, keyLength, fileType, filePassword) {
        return this._request("POST", "/rest/keys/ssh/generate").sendDownload({keytype: keyType, keylength: keyLength, filetype: fileType, filepassword: filePassword});
    },

    importPublicKey: function(file, type) {
        return this._request("POST", "/rest/keys/ssh/import").sendFormMultipart({file: file, type: type});
    },

    deletePublicKey: function() {
        return this._request("DELETE", "/rest/keys/ssh").send();
    },

    getPgpSystemKeyNames: function() {
        return this._request("GET", "/rest/keys/pgp").options({global: false}).matrix({names: true}).send();
    },

    generatePgpKey: function(type, length, realName, email, password) {
        return this._request("POST", "/rest/keys/pgp/generate").sendDownload({keytype: type, keylength: length, realname: realName, email: email, filepassword: password});
    },

    importPgpKey: function(file) {
        return this._request("POST", "/rest/keys/pgp/import").sendFormMultipart({file: file});
    },

    deletePgpKey: function() {
        return this._request("DELETE", "/rest/keys/pgp").send();
    },

    getDlpRuleNames: function() {
        return this._request("GET", "/rest/dlp-rules").options({global: false}).matrix({names: true}).send();
    },

    _request: function (method, url, parse) {
        var req = new jscape.VersionAwareRequest(method, url, this.timeout, parse);
        req.csrf = this.csrf;
        return $.isPlainObject(req.csrf) ? req.headers(req.csrf) : req;
    }
});

/** @class */
jscape.VersionAwareRequest = jscape.Request.extend(
    /** @lends {jscape.VersionAwareRequest.prototype} */
{
    /** @override */
    send: function(data) {
        var url = this.url || this.settings.url;
        if (("POST" === this.settings.type || "PUT" === this.settings.type) && jQuery.etag[url]) {
            this.settings.ifModified = false;
            this.headers({"If-Match": jQuery.etag[this.url]}, false);
            this.settings.complete = function(jqXhr, status) {
                var tag = jqXhr.getResponseHeader("Etag");
                if (tag) {
                    jQuery.etag[url] = tag;
                }
            };
        } else {
            this.settings.ifModified = true;
        }
        return this._super(data)
                .done(function (data) {
                          if ($.isPlainObject(data) && data.hasOwnProperty("version")) {
                              delete data.version;
                          }
                          return data;
                      });
    }
});