var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    return function (d, b) {
        if (typeof b !== "function" && b !== null)
            throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var __assign = (this && this.__assign) || function () {
    __assign = Object.assign || function(t) {
        for (var s, i = 1, n = arguments.length; i < n; i++) {
            s = arguments[i];
            for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
                t[p] = s[p];
        }
        return t;
    };
    return __assign.apply(this, arguments);
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __generator = (this && this.__generator) || function (thisArg, body) {
    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
    return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
    function verb(n) { return function (v) { return step([n, v]); }; }
    function step(op) {
        if (f) throw new TypeError("Generator is already executing.");
        while (g && (g = 0, op[0] && (_ = 0)), _) try {
            if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
            if (y = 0, t) op = [op[0] & 2, t.value];
            switch (op[0]) {
                case 0: case 1: t = op; break;
                case 4: _.label++; return { value: op[1], done: false };
                case 5: _.label++; y = op[1]; op = [0]; continue;
                case 7: op = _.ops.pop(); _.trys.pop(); continue;
                default:
                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
                    if (t[2]) _.ops.pop();
                    _.trys.pop(); continue;
            }
            op = body.call(thisArg, _);
        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
    }
};
var LauncherControl = (function () {
    function LauncherControl() {
    }
    LauncherControl.prototype.make = function (options) {
        this.uiOptions = options;
        this.formControl = new LabeledFormControl(options, this.label());
        this.controlId = this.formControl.controlId;
        var col = document.createElement('div');
        col.className = "col-sm-6";
        var group = document.createElement('div');
        group.className = "input-group";
        col.appendChild(group);
        this.formControl.addControl(col);
        this.create(col, group);
        return this.formControl.host;
    };
    return LauncherControl;
}());
var ImageControl = (function (_super) {
    __extends(ImageControl, _super);
    function ImageControl(images, defaultImage, allowUnknown) {
        var _this = _super.call(this) || this;
        _this.images = images;
        _this.defaultImage = defaultImage;
        _this.allowUnknown = allowUnknown;
        return _this;
    }
    ImageControl.prototype.create = function (column, group) {
        this.group = group;
        if (this.images && this.images.length > 0) {
            this.buildSelect();
        }
        else if (this.allowUnknown) {
            this.buildInput();
        }
        else if (this.defaultImage) {
            this.buildFixed();
        }
    };
    ImageControl.prototype.buildSelect = function () {
        var _this = this;
        var _a, _b;
        this.clear();
        this.select = document.createElement('select');
        this.select.className = this.uiOptions.select_class;
        this.select.id = this.controlId;
        this.select.addEventListener("change", function () {
            var _a;
            (_a = _this.onChange) === null || _a === void 0 ? void 0 : _a.call(_this, _this.select.value);
        });
        if (!this.defaultImage) {
            var def = document.createElement('option');
            def.value = "";
            def.text = "Default";
            this.select.add(def);
        }
        for (var _i = 0, _c = this.images; _i < _c.length; _i++) {
            var val = _c[_i];
            var option = document.createElement('option');
            option.value = val.image;
            option.text = val.image;
            if (val.image === this.defaultImage) {
                option.selected = true;
                option.text += " (default)";
                this.select.insertBefore(option, this.select.firstElementChild);
            }
            else {
                this.select.appendChild(option);
            }
        }
        if (this.allowUnknown) {
            var other = document.createElement('option');
            other.value = "other";
            other.text = "Other...";
            this.select.appendChild(other);
            this.select.addEventListener('change', function () {
                var _a;
                if (_this.select.selectedIndex === _this.select.options.length - 1) {
                    _this.buildInput();
                    (_a = _this.onChange) === null || _a === void 0 ? void 0 : _a.call(_this, _this.input.value);
                }
            });
        }
        this.group.appendChild(this.select);
        (_a = this.onChange) === null || _a === void 0 ? void 0 : _a.call(this, ((_b = this.select.firstChild) === null || _b === void 0 ? void 0 : _b.textContent) || '');
    };
    ImageControl.prototype.showImageList = function () {
        var _a;
        this.buildSelect();
        (_a = this.onChange) === null || _a === void 0 ? void 0 : _a.call(this, this.select.value);
    };
    ImageControl.prototype.buildInput = function () {
        var _this = this;
        this.clear();
        this.input = document.createElement('input');
        this.input.type = "text";
        this.input.className = this.uiOptions.textbox_class;
        this.input.id = this.controlId;
        this.input.addEventListener('change', function () {
            var _a;
            (_a = _this.onChange) === null || _a === void 0 ? void 0 : _a.call(_this, _this.input.value);
        });
        this.group.appendChild(this.input);
        if (this.images && this.images.length > 0) {
            var more = document.createElement('a');
            more.className = this.uiOptions.link_label_class;
            more.tabIndex = 0;
            more.textContent = "Show list";
            more.addEventListener('click', this.showImageList.bind(this));
            more.addEventListener('keydown', function (ev) {
                if (ev.key === "Enter") {
                    _this.showImageList();
                }
            });
            this.group.appendChild(more);
        }
        else {
            if (this.defaultImage) {
                this.input.placeholder = this.defaultImage;
            }
            else {
                this.input.placeholder = "Default";
            }
        }
    };
    ImageControl.prototype.buildFixed = function () {
        var fixed = document.createElement('p');
        fixed.id = this.controlId;
        if (this.defaultImage) {
            this.fixed = this.defaultImage;
            fixed.textContent = this.defaultImage;
        }
        else {
            this.fixed = "";
            fixed.textContent = "Default";
        }
        this.group.appendChild(fixed);
    };
    ImageControl.prototype.value = function () {
        if (this.select)
            return this.select.options[this.select.selectedIndex].value;
        else if (this.input) {
            if (this.input.value.length == 0 &&
                this.input.placeholder.length != 0) {
                return this.input.placeholder;
            }
            return this.input.value.trim();
        }
        else if (this.fixed)
            return this.fixed;
        return "";
    };
    ImageControl.prototype.set = function (value, add) {
        var _a;
        if (this.select) {
            var found = false;
            for (var i = 0; i < this.select.options.length; i++) {
                if (this.select.options[i].value === value) {
                    this.select.selectedIndex = i;
                    this.select.options[i].text += " (current)";
                    found = true;
                    break;
                }
            }
            if (!found && add) {
                var option = document.createElement('option');
                option.value = value;
                option.text = value + " (current)";
                this.select.prepend(option);
                this.select.selectedIndex = 0;
            }
        }
        else if (this.input && add) {
            this.input.value = value;
        }
        (_a = this.onChange) === null || _a === void 0 ? void 0 : _a.call(this, value);
    };
    ImageControl.prototype.label = function () {
        return "Image";
    };
    ImageControl.prototype.clear = function () {
        this.group.innerHTML = "";
        this.select = null;
        this.input = null;
    };
    return ImageControl;
}(LauncherControl));
var ShowClusterType;
(function (ShowClusterType) {
    ShowClusterType["All"] = "all";
    ShowClusterType["Interactive"] = "interactive";
    ShowClusterType["NonInteractive"] = "non-interactive";
})(ShowClusterType || (ShowClusterType = {}));
var LimitInput = (function () {
    function LimitInput(input, hint, uiOptions, limit, units) {
        var _this = this;
        this.input = input;
        this.hint = hint;
        this.uiOptions = uiOptions;
        this.limit = limit;
        this.units = units;
        if (typeof this.limit.defaultValue === "string") {
            this.input.value = this.formatNumber(this.limit.defaultValue);
            this.input.placeholder = this.formatNumber(this.limit.defaultValue) + " " + units;
        }
        else {
            this.input.placeholder = "Default";
        }
        this.input.addEventListener("blur", function () {
            _this.validateInput();
        });
        this.clearHint();
    }
    LimitInput.prototype.formatNumber = function (num) {
        try {
            return parseFloat(num).toString();
        }
        catch (_a) {
            return num;
        }
    };
    LimitInput.prototype.clearHint = function () {
        this.input.className = this.uiOptions.textbox_class;
        this.hint.className = this.uiOptions.input_hint_class;
        if (typeof this.limit.maxValue === "string") {
            this.hint.innerText = "Maximum " + this.formatNumber(this.limit.maxValue) + " " + this.units;
        }
        else {
            this.hint.style.display = "none";
        }
    };
    LimitInput.prototype.showError = function (error) {
        this.input.className = this.uiOptions.textbox_error_class;
        this.hint.className = this.uiOptions.input_hint_error_class;
        this.hint.style.display = "";
        this.hint.innerText = error;
    };
    LimitInput.prototype.validateInput = function () {
        var value = this.input.value.trim();
        if (value === "") {
            this.clearHint();
            return true;
        }
        var num = parseFloat(value);
        if (isNaN(num)) {
            this.showError("Enter a number.");
            return false;
        }
        var allowZero = false;
        switch (this.limit.type) {
            case "cpuCount":
            case "cpuTime":
            case "memory":
            case "memorySwap":
                allowZero = false;
                break;
            default:
                allowZero = true;
                break;
        }
        if (num < 0) {
            this.showError("Enter a positive number.");
            return false;
        }
        if (!allowZero && num == 0) {
            this.showError("Enter a number greater than 0.");
            return false;
        }
        if (typeof this.limit.maxValue === "string") {
            var max = parseFloat(this.limit.maxValue);
            if (!isNaN(max) && num > max) {
                this.showError("Enter a maximum of " + max + " " + this.units + ".");
                return false;
            }
        }
        this.clearHint();
        return true;
    };
    LimitInput.prototype.resourceLimit = function () {
        return this.limit;
    };
    LimitInput.prototype.value = function () {
        return this.input.value.trim();
    };
    LimitInput.prototype.set = function (value) {
        this.input.value = value;
    };
    return LimitInput;
}());
var QueueControl = (function (_super) {
    __extends(QueueControl, _super);
    function QueueControl(queues) {
        var _this = _super.call(this) || this;
        _this.queues = queues;
        return _this;
    }
    QueueControl.prototype.create = function (column, group) {
        this.select = document.createElement('select');
        this.select.className = this.uiOptions.select_class;
        this.select.id = this.controlId;
        for (var _i = 0, _a = this.queues; _i < _a.length; _i++) {
            var val = _a[_i];
            var option = document.createElement('option');
            option.value = val;
            option.text = val;
            this.select.add(option);
        }
        group.appendChild(this.select);
    };
    QueueControl.prototype.value = function () {
        return this.select.options[this.select.selectedIndex].value;
    };
    QueueControl.prototype.set = function (value) {
        for (var i = 0; i < this.select.options.length; i++) {
            if (this.select.options[i].value === value) {
                this.select.selectedIndex = i;
                break;
            }
        }
    };
    QueueControl.prototype.label = function () {
        return "Queue";
    };
    return QueueControl;
}(LauncherControl));
var PlacementControl = (function (_super) {
    __extends(PlacementControl, _super);
    function PlacementControl(name, values) {
        var _this = _super.call(this) || this;
        _this.name = name;
        _this.values = values;
        _this.select = null;
        _this.input = null;
        return _this;
    }
    PlacementControl.prototype.label = function () {
        return this.name.slice(0, 1).toUpperCase() + this.name.slice(1);
    };
    PlacementControl.prototype.create = function (column, group) {
        var _this = this;
        if (this.values.length > 0) {
            var select_1 = document.createElement('select');
            select_1.className = this.uiOptions.select_class;
            select_1.id = this.controlId;
            var defaultVal = document.createElement('option');
            defaultVal.value = "";
            defaultVal.text = "Default";
            select_1.add(defaultVal);
            for (var _i = 0, _a = this.values; _i < _a.length; _i++) {
                var val = _a[_i];
                var option = document.createElement('option');
                option.value = val;
                option.text = val;
                select_1.add(option);
            }
            select_1.addEventListener('change', function () {
                var _a;
                (_a = _this.onChange) === null || _a === void 0 ? void 0 : _a.call(_this, select_1.value);
            });
            this.select = select_1;
            group.appendChild(select_1);
        }
        else {
            this.input = document.createElement('input');
            this.input.type = "text";
            this.input.className = this.uiOptions.textbox_class;
            this.input.id = this.controlId;
            this.input.addEventListener('change', function () {
                var _a;
                (_a = _this.onChange) === null || _a === void 0 ? void 0 : _a.call(_this, _this.input.value);
            });
            group.appendChild(this.input);
        }
    };
    PlacementControl.prototype.constraint = function () {
        var val = "";
        if (this.input !== null)
            val = this.input.value.trim();
        else if (this.select !== null)
            val = this.select.options[this.select.selectedIndex].value;
        if (val === "")
            return null;
        return {
            name: this.name,
            value: val
        };
    };
    PlacementControl.prototype.set = function (value) {
        if (this.input !== null) {
            this.input.value = value;
        }
        else if (this.select !== null) {
            for (var i = 0; i < this.select.options.length; i++) {
                if (this.select.options[i].value === value) {
                    this.select.selectedIndex = i;
                    break;
                }
            }
        }
    };
    return PlacementControl;
}(LauncherControl));
var ResourceControl = (function (_super) {
    __extends(ResourceControl, _super);
    function ResourceControl(limit) {
        var _this = _super.call(this) || this;
        _this.limit = limit;
        return _this;
    }
    ResourceControl.prototype.resourceUnits = function (limitType) {
        var units = "";
        switch (limitType) {
            case "cpuCount":
                units = "CPUs";
                break;
            case "memory":
            case "memorySwap":
                units = "MB";
                break;
        }
        return units;
    };
    ResourceControl.prototype.label = function () {
        var description = "";
        switch (this.limit.type) {
            case "cpuCount":
                description = "CPUs";
                break;
            case "cpuTime":
                description = "CPU Time";
                break;
            case "memory":
                description = "Memory";
                break;
            case "memorySwap":
                description = "Swap";
                break;
            default:
                description = this.limit.type;
                break;
        }
        return description;
    };
    ResourceControl.prototype.create = function (column, group) {
        var _this = this;
        var units = this.resourceUnits(this.limit.type);
        var controlParent = group;
        var groupTable;
        var groupTableRow;
        if (this.uiOptions.table_layout) {
            groupTable = document.createElement('table');
            groupTable.setAttribute("role", "presentation");
            groupTable.style.setProperty("cellspacing", "0");
            groupTable.style.setProperty("cellpadding", "0");
            groupTable.createTFoot();
            groupTableRow = groupTable.createTBody().insertRow();
            controlParent = groupTableRow.insertCell();
        }
        var input = document.createElement('input');
        input.type = "text";
        input.className = this.uiOptions.textbox_class;
        input.id = this.controlId;
        controlParent.appendChild(input);
        if (units !== "") {
            if (this.uiOptions.table_layout) {
                controlParent = groupTableRow.insertCell();
            }
            var unitLabel = document.createElement('div');
            unitLabel.innerText = units;
            unitLabel.className = this.uiOptions.input_addon_class;
            controlParent.appendChild(unitLabel);
        }
        if (this.uiOptions.table_layout) {
            group.appendChild(groupTable);
        }
        var hint = document.createElement('small');
        column.appendChild(hint);
        this.input = new LimitInput(input, hint, this.uiOptions, this.limit, units);
        input.addEventListener('blur', function () {
            var _a;
            if (!_this.input.validateInput()) {
                return;
            }
            (_a = _this.onChange) === null || _a === void 0 ? void 0 : _a.call(_this, _this.input.value());
        });
    };
    ResourceControl.prototype.value = function () {
        if (this.input.value() === "") {
            return null;
        }
        return {
            type: this.limit.type,
            value: this.input.value()
        };
    };
    ResourceControl.prototype.set = function (value) {
        this.input.set(value);
    };
    return ResourceControl;
}(LauncherControl));
var LabeledFormControl = (function () {
    function LabeledFormControl(uiOptions, labelText) {
        this.uiOptions = uiOptions;
        this.host = document.createElement('div');
        this.host.className = uiOptions.form_group_class;
        this.host.id = LabeledFormControl.idFromLabel(labelText).replace('rstudio_label_', 'rstudio_group_');
        this.controlParent = this.host;
        this.controlId = LabeledFormControl.idFromLabel(labelText);
        var label = document.createElement('label');
        label.innerText = labelText;
        label.className = uiOptions.label_class;
        label.htmlFor = this.controlId;
        label.style.wordWrap = "break-word";
        if (uiOptions.table_layout) {
            this.groupTable = document.createElement('table');
            this.groupTable.setAttribute("role", "presentation");
            this.groupTable.style.setProperty("cellspacing", "0");
            this.groupTable.style.setProperty("cellpadding", "0");
            this.groupTable.createTFoot();
            this.row = this.groupTable.createTBody().insertRow();
            this.controlParent = this.row.insertCell();
        }
        this.controlParent.appendChild(label);
    }
    LabeledFormControl.prototype.addControl = function (controlElement) {
        if (this.controlParent === null) {
            console.log("Assertion failure: incorrect usage of LabeledFormControl");
            return;
        }
        if (this.uiOptions.table_layout) {
            this.controlParent = this.row.insertCell();
        }
        this.controlParent.appendChild(controlElement);
        if (this.uiOptions.table_layout) {
            this.host.appendChild(this.groupTable);
        }
        this.controlParent = null;
    };
    LabeledFormControl.idSafeString = function (text) {
        var id = text.replace(/[^a-zA-Z0-9]/g, "_");
        id = id.replace(/_+/g, "_");
        id = id.replace(/^_+/g, "");
        id = id.replace(/_+$/g, "");
        return id.toLowerCase();
    };
    LabeledFormControl.idFromLabel = function (label) {
        return "rstudio_label_" + LabeledFormControl.idSafeString(label);
    };
    return LabeledFormControl;
}());
var ResourceProfileControl = (function (_super) {
    __extends(ResourceProfileControl, _super);
    function ResourceProfileControl(profiles) {
        var _this = _super.call(this) || this;
        _this.profiles = profiles;
        _this.select = null;
        return _this;
    }
    ResourceProfileControl.prototype.label = function () {
        return 'Resource Profile';
    };
    ResourceProfileControl.prototype.create = function (column, group) {
        var _this = this;
        var _a;
        var prettifyName = function (p) { return p.replace(/[-_]/g, ' ').
            replace(/(^|\s)\S/g, function (t) { return t.toUpperCase(); }); };
        var select = document.createElement('select');
        select.className = this.uiOptions.select_class;
        select.id = this.controlId;
        for (var _i = 0, _b = this.profiles; _i < _b.length; _i++) {
            var profile = _b[_i];
            var option = document.createElement('option');
            option.text = (_a = profile.displayName) !== null && _a !== void 0 ? _a : prettifyName(profile.name);
            option.value = profile.name;
            select.add(option);
        }
        select.addEventListener('change', function () {
            var _a;
            (_a = _this.onChange) === null || _a === void 0 ? void 0 : _a.call(_this, select.value);
        });
        this.select = select;
        group.appendChild(select);
    };
    ResourceProfileControl.prototype.isCustom = function () {
        var _a, _b;
        return (_b = ((_a = this.select) === null || _a === void 0 ? void 0 : _a.options[this.select.selectedIndex].value) === 'custom') !== null && _b !== void 0 ? _b : false;
    };
    ResourceProfileControl.prototype.profile = function () {
        var _a;
        return (_a = this.select) === null || _a === void 0 ? void 0 : _a.options[this.select.selectedIndex].value;
    };
    ResourceProfileControl.prototype.limits = function () {
        var current = this.profile();
        for (var _i = 0, _a = this.profiles; _i < _a.length; _i++) {
            var profile = _a[_i];
            if (current == profile.name) {
                return profile.limits;
            }
        }
        return new Array();
    };
    ResourceProfileControl.prototype.set = function (value) {
        if (value === null) {
            return;
        }
        if (this.select !== null) {
            for (var i = 0; i < this.select.options.length; i++) {
                if (this.select.options[i].value === value) {
                    this.select.selectedIndex = i;
                    break;
                }
            }
        }
    };
    return ResourceProfileControl;
}(LauncherControl));
var LauncherUI = (function () {
    function LauncherUI(host, rpcUrlPrefix, input, uiOptions) {
        this.host = host;
        this.rpcUrlPrefix = rpcUrlPrefix;
        this.input = input;
        this.uiOptions = uiOptions;
        this.canStartSession = true;
    }
    LauncherUI.prototype.initialize = function () {
        var _a;
        return __awaiter(this, void 0, void 0, function () {
            var metas, csrfToken, i, val, resultText, result, xhr;
            var _this = this;
            return __generator(this, function (_b) {
                switch (_b.label) {
                    case 0:
                        this.host.textContent = "Loading...";
                        this.availableClusters = [];
                        this.uiOptions = __assign({ fieldset_class: "", form_group_class: "form-group", input_addon_class: "input-group-addon", input_hint_class: "form-text text-muted", input_hint_error_class: "form-text text-muted input-error", job_name_label: "Session Name", job_name_placeholder: "New Session", label_class: "col-sm-3 control-label", link_label_class: "", select_class: "form-control", show_legend: true, table_layout: false, textbox_class: "form-control", textbox_error_class: "form-control input-error" }, this.uiOptions);
                        metas = document.getElementsByTagName("meta");
                        csrfToken = "";
                        for (i = 0; i < metas.length; i++) {
                            if (metas[i].getAttribute("name") === "rs-csrf-token") {
                                val = metas[i].getAttribute("content");
                                if (val != null) {
                                    csrfToken = val;
                                }
                            }
                        }
                        if (!(typeof this.rpcUrlPrefix === 'function')) return [3, 2];
                        return [4, this.rpcUrlPrefix()];
                    case 1:
                        resultText = _b.sent();
                        result = null;
                        try {
                            result = JSON.parse(resultText);
                        }
                        catch (e) {
                            this.host.textContent = "Failed to parse result: " + resultText;
                            console.error(e);
                            return [2];
                        }
                        try {
                            this.renderUI(result, this.uiOptions);
                            (_a = this.onLaunchSpecModified) === null || _a === void 0 ? void 0 : _a.call(this, this.getLaunchSpec());
                        }
                        catch (e) {
                            this.host.textContent = "Failed to render UI from server result: " + JSON.stringify(result, null, 2);
                            console.error(e);
                        }
                        return [2];
                    case 2:
                        xhr = new XMLHttpRequest();
                        xhr.open('post', this.rpcUrlPrefix + '/job_launcher_rpc/get_info');
                        xhr.setRequestHeader('Content-Type', 'application/json');
                        xhr.timeout = 5000;
                        if (csrfToken !== "") {
                            xhr.setRequestHeader('X-RS-CSRF-Token', csrfToken);
                        }
                        xhr.onload = function () {
                            var _a;
                            var result = null;
                            try {
                                result = JSON.parse(xhr.responseText);
                            }
                            catch (e) {
                                _this.host.textContent = "Failed to parse result: " + xhr.responseText;
                                return;
                            }
                            if (result.hasOwnProperty("error")) {
                                console.log("Failed to execute job_launcher_rpc/get_info");
                                console.log(result);
                                _this.renderError(result.error);
                                return;
                            }
                            try {
                                _this.renderUI(result, _this.uiOptions);
                                (_a = _this.onLaunchSpecModified) === null || _a === void 0 ? void 0 : _a.call(_this, _this.getLaunchSpec());
                            }
                            catch (e) {
                                _this.host.textContent = "Failed to render UI from server result: " + xhr.responseText;
                            }
                        };
                        xhr.onerror = function () {
                            _this.host.textContent = xhr.statusText;
                        };
                        xhr.send(JSON.stringify({ method: "get_info" }));
                        return [2];
                }
            });
        });
    };
    LauncherUI.prototype.setOnLaunchSpecModified = function (value) {
        this.onLaunchSpecModified = value;
    };
    LauncherUI.prototype.setOnUiRender = function (value) {
        this.onUiRender = value;
    };
    LauncherUI.prototype.renderError = function (error) {
        this.host.innerHTML = "";
        var bar = document.createElement('div');
        bar.className = "alert alert-danger";
        bar.textContent = "Error " + error.code + ": " + error.message;
        this.host.appendChild(bar);
        var msg = document.createElement('p');
        msg.textContent = error.error.category + " error " + error.error.code + ": " +
            error.error.message;
        this.host.appendChild(msg);
    };
    LauncherUI.prototype.renderUI = function (info, uiOptions) {
        var _this = this;
        var _a;
        this.info = info;
        this.host.innerHTML = "";
        var form = document.createElement('form');
        form.className = "form-horizontal";
        var nameControl = new LabeledFormControl(this.uiOptions, uiOptions.job_name_label);
        var nameHost = document.createElement('div');
        nameHost.className = "col-sm-6 input-group";
        var nameInput = document.createElement('input');
        nameInput.type = "text";
        nameInput.placeholder = uiOptions.job_name_placeholder;
        nameInput.maxLength = 30;
        nameInput.className = this.uiOptions.textbox_class;
        nameInput.id = nameControl.controlId;
        nameHost.appendChild(nameInput);
        this.name = nameInput;
        nameControl.addControl(nameHost);
        form.appendChild(nameControl.host);
        var dirty = false;
        nameInput.addEventListener("change", function () {
            dirty = true;
        });
        var workbenchControl = new LabeledFormControl(this.uiOptions, "Editor");
        var workbenchHost = document.createElement('div');
        workbenchHost.className = "col-sm-6 input-group";
        this.workbench = document.createElement('select');
        this.workbench.id = workbenchControl.controlId;
        if (!this.input.show_workbenches) {
            workbenchControl.host.style.display = "none";
        }
        var allWorkbenches = Object.keys(info.workbenches);
        var filteredWorkbenches = this.input.workbenches.filter(function (workbench) { return allWorkbenches.indexOf(workbench) !== -1; });
        this.input.workbenches = filteredWorkbenches;
        this.workbench.className = this.uiOptions.select_class;
        for (var _i = 0, filteredWorkbenches_1 = filteredWorkbenches; _i < filteredWorkbenches_1.length; _i++) {
            var workbench = filteredWorkbenches_1[_i];
            var option = document.createElement('option');
            option.value = workbench;
            option.text = workbench;
            this.workbench.add(option);
        }
        nameInput.value = this.input.default_names[0];
        this.workbench.addEventListener("change", function (evt) {
            var _a;
            var target = evt.target;
            if (!dirty) {
                nameInput.value = _this.input.default_names[target.selectedIndex] || _this.input.default_names[0];
            }
            _this.populateAvailableClusters(filteredWorkbenches[target.selectedIndex]);
            _this.showClusterOptions(_this.cluster.selectedIndex);
            (_a = _this.onLaunchSpecModified) === null || _a === void 0 ? void 0 : _a.call(_this, _this.getLaunchSpec());
        });
        this.workbench.selectedIndex = 0;
        var workbenchName = this.input.workbenches[0];
        workbenchHost.appendChild(this.workbench);
        workbenchControl.addControl(workbenchHost);
        form.appendChild(workbenchControl.host);
        var clusterControl = new LabeledFormControl(this.uiOptions, "Cluster");
        var clusterHost = document.createElement('div');
        clusterHost.className = "col-sm-6 input-group";
        this.cluster = document.createElement('select');
        this.cluster.id = clusterControl.controlId;
        this.cluster.className = this.uiOptions.select_class;
        this.populateAvailableClusters(workbenchName);
        this.cluster.addEventListener("change", function () {
            var _a;
            _this.showClusterOptions(_this.cluster.selectedIndex);
            (_a = _this.onLaunchSpecModified) === null || _a === void 0 ? void 0 : _a.call(_this, _this.getLaunchSpec());
        });
        clusterHost.appendChild(this.cluster);
        clusterControl.addControl(clusterHost);
        form.appendChild(clusterControl.host);
        if (this.input.aws_roles && this.input.aws_roles.length > 0) {
            var awsRoleControl_1 = new LabeledFormControl(this.uiOptions, 'AWS Role');
            this.awsRole = document.createElement('select');
            this.awsRole.id = awsRoleControl_1.controlId;
            this.awsRole.className = this.uiOptions.select_class;
            this.awsRole.addEventListener('change', function () {
                var _a;
                (_a = _this.onLaunchSpecModified) === null || _a === void 0 ? void 0 : _a.call(_this, _this.getLaunchSpec());
            });
            for (var _b = 0, _c = this.input.aws_roles; _b < _c.length; _b++) {
                var role = _c[_b];
                var option = document.createElement('option');
                option.value = role;
                option.text = role;
                if (this.input.default_aws_role === role) {
                    option.selected = true;
                }
                if (this.resuming() && this.input.launch_spec.aws_role) {
                    if (role === this.input.launch_spec.aws_role) {
                        option.selected = true;
                    }
                }
                this.awsRole.add(option);
            }
            var awsRoleHost = document.createElement('div');
            awsRoleHost.className = "col-sm-6 input-group";
            awsRoleHost.appendChild(this.awsRole);
            awsRoleControl_1.addControl(awsRoleHost);
            form.appendChild(awsRoleControl_1.host);
            var controlVisibility = function () {
                var workbench = _this.input.workbenches[_this.workbench.selectedIndex];
                var hide = workbench !== 'RStudio';
                awsRoleControl_1.host.style.display = hide ? 'none' : '';
                awsRoleControl_1.host.ariaHidden = "".concat(hide);
            };
            this.workbench.addEventListener("change", controlVisibility);
        }
        this.options = document.createElement('fieldset');
        if (uiOptions.fieldset_class.length > 0)
            this.options.className = this.uiOptions.fieldset_class;
        form.appendChild(this.options);
        this.host.appendChild(form);
        this.showClusterOptions(this.cluster.selectedIndex);
        (_a = this.onUiRender) === null || _a === void 0 ? void 0 : _a.call(this, info, uiOptions);
    };
    LauncherUI.prototype.hasCollection = function (collection) {
        return typeof collection !== "undefined" &&
            collection !== null &&
            collection.length > 0;
    };
    LauncherUI.prototype.populateAvailableClusters = function (workbench) {
        for (var i = this.cluster.options.length - 1; i >= 0; i--) {
            this.cluster.remove(i);
        }
        var filterFunc = function (property, item) {
            var workbenchInfo = item.workbenches[workbench];
            if (workbenchInfo) {
                return workbenchInfo[property];
            }
            return false;
        };
        switch (this.input.show_clusters) {
            case ShowClusterType.Interactive:
                this.availableClusters = this.info.clusters.filter(filterFunc.bind(this, "supports_interactive_sessions"));
                break;
            case ShowClusterType.NonInteractive:
                this.availableClusters = this.info.clusters.filter(filterFunc.bind(this, "supports_adhoc_jobs"));
                break;
            case ShowClusterType.All:
            default:
                var sessionClusters = this.info.clusters.filter(filterFunc.bind(this, "supports_interactive_sessions"));
                var adhocClusters = this.info.clusters.filter(filterFunc.bind(this, "supports_adhoc_jobs"));
                this.availableClusters = sessionClusters.concat(adhocClusters);
                break;
        }
        this.availableClusters.sort(function (a, b) { return a.name.localeCompare(b.name); });
        var workbenchObj = this.info.workbenches[workbench];
        var defaultCluster = "";
        if (workbenchObj)
            defaultCluster = workbenchObj.default_cluster;
        for (var _i = 0, _a = this.availableClusters; _i < _a.length; _i++) {
            var cluster = _a[_i];
            var option = document.createElement('option');
            option.value = cluster.name;
            option.text = cluster.name;
            if (this.resuming()) {
                if (cluster.name === this.input.launch_spec.cluster) {
                    option.selected = true;
                }
            }
            else {
                if (cluster.name === defaultCluster) {
                    option.selected = true;
                }
            }
            this.cluster.add(option);
        }
    };
    LauncherUI.prototype.showClusterOptions = function (index) {
        var _this = this;
        var _a, _b;
        this.options.innerHTML = "";
        this.image = null;
        this.limits = new Array();
        this.constraints = new Array();
        var cluster = this.availableClusters[index];
        if (!cluster) {
            return;
        }
        var workbench = this.input.workbenches[this.workbench.selectedIndex];
        var workbenchObj = this.info.workbenches[workbench];
        this.canStartSession = (_b = (_a = workbenchObj.lang) === null || _a === void 0 ? void 0 : _a.available) !== null && _b !== void 0 ? _b : true;
        if (!this.canStartSession && workbenchObj.lang) {
            var sessionName = workbench;
            if (sessionName === "RStudio") {
                sessionName += " Pro";
            }
            var lang = workbenchObj.lang.name;
            var url = "";
            if (lang === "Jupyter") {
                url = "https://docs.posit.co/rsw/integration/jupyter-standalone/";
            }
            else if (lang === "R") {
                url = "https://docs.posit.co/resources/install-r/";
            }
            else if (lang === "code-server") {
                url = "https://docs.posit.co/ide/server-pro/vscode_sessions/installation.html";
            }
            this.options.innerHTML = "\n        </br>\n        <p>\n        ".concat(sessionName, " Sessions cannot be started because a necessary dependency is not installed: ").concat(lang, ".\n          Please contact your system administrator for assistance.\n          </p>\n        </br>\n        <p>\n        More details about installing ").concat(lang, " can be found <a href=\"").concat(url, "\" target=\"_blank\">here</a>.\n          </p>");
            return;
        }
        var filterFunc = function (property, item) {
            var workbenchInfo = item.workbenches[workbench];
            if (workbenchInfo) {
                return workbenchInfo[property];
            }
            return false;
        };
        var availableImages = [];
        switch (this.input.show_clusters) {
            case ShowClusterType.Interactive:
                availableImages = cluster.images.filter(filterFunc.bind(this, "supports_interactive_sessions"));
                break;
            case ShowClusterType.NonInteractive:
                availableImages = cluster.images.filter(filterFunc.bind(this, "supports_adhoc_jobs"));
                break;
            case ShowClusterType.All:
            default:
                var sessionImages = cluster.images.filter(filterFunc.bind(this, "supports_interactive_sessions"));
                var adhocImages = cluster.images.filter(filterFunc.bind(this, "supports_adhoc_jobs"));
                availableImages = sessionImages.concat(adhocImages);
                break;
        }
        if (!this.hasCollection(cluster.resourceLimits) &&
            !this.hasCollection(cluster.resourceProfiles) &&
            !this.hasCollection(cluster.placementConstraints) &&
            !this.hasCollection(cluster.queues) &&
            !this.hasCollection(availableImages)) {
            return;
        }
        if (this.uiOptions.show_legend) {
            var legend = document.createElement('legend');
            legend.textContent = 'Cluster Options';
            legend.className = 'options';
            this.options.appendChild(legend);
        }
        if (this.hasCollection(cluster.resourceProfiles) && cluster.resourceProfiles.length > 0) {
            var control_1 = new ResourceProfileControl(cluster.resourceProfiles);
            control_1.onChange = function () {
                var _a;
                if (control_1.isCustom()) {
                    for (var _i = 0, _b = _this.limitElements; _i < _b.length; _i++) {
                        var elem = _b[_i];
                        elem.input.disabled = false;
                    }
                }
                else {
                    for (var _c = 0, _d = _this.limitElements; _c < _d.length; _c++) {
                        var elem = _d[_c];
                        elem.input.disabled = true;
                        for (var _e = 0, _f = control_1.limits(); _e < _f.length; _e++) {
                            var plimit = _f[_e];
                            if (elem.limit.type == plimit.type) {
                                elem.set(plimit.value);
                            }
                        }
                    }
                }
                (_a = _this.onLaunchSpecModified) === null || _a === void 0 ? void 0 : _a.call(_this, _this.getLaunchSpec());
            };
            this.resourceProfile = control_1;
            this.options.appendChild(control_1.make(this.uiOptions));
            if (this.resuming()) {
                if (this.input.launch_spec.resource_profile) {
                    control_1.set(this.input.launch_spec.resource_profile);
                }
                else if (this.input.launch_spec.resource_limits.length > 0) {
                    control_1.set("custom");
                }
            }
        }
        if (this.hasCollection(cluster.resourceLimits)) {
            this.limitElements = new Array();
            for (var _i = 0, _c = cluster.resourceLimits; _i < _c.length; _i++) {
                var limit = _c[_i];
                if (limit.type == "CPU Request" || limit.type == "Memory Request") {
                    continue;
                }
                var control = new ResourceControl(limit);
                control.onChange = function () {
                    var _a;
                    (_a = _this.onLaunchSpecModified) === null || _a === void 0 ? void 0 : _a.call(_this, _this.getLaunchSpec());
                };
                this.limits.push(control);
                this.options.appendChild(control.make(this.uiOptions));
                if (this.resourceProfile && !this.resourceProfile.isCustom()) {
                    control.input.input.disabled = true;
                    for (var _d = 0, _e = this.resourceProfile.limits(); _d < _e.length; _d++) {
                        var plimit = _e[_d];
                        if (limit.type == plimit.type) {
                            control.set(plimit.value);
                        }
                    }
                }
                this.limitElements.push(control.input);
                if (this.resuming()) {
                    for (var _f = 0, _g = this.input.launch_spec.resource_limits; _f < _g.length; _f++) {
                        var l = _g[_f];
                        if (l.type === limit.type) {
                            control.set(l.value);
                            break;
                        }
                    }
                }
            }
        }
        if (this.hasCollection(cluster.placementConstraints)) {
            var constraints = {};
            for (var _h = 0, _j = cluster.placementConstraints; _h < _j.length; _h++) {
                var constraint = _j[_h];
                if (typeof constraints[constraint.name] === "undefined") {
                    constraints[constraint.name] = new Array();
                }
                if (typeof constraint.value === "string") {
                    constraints[constraint.name].push(constraint.value);
                }
            }
            for (var constraint in constraints) {
                var control = new PlacementControl(constraint, constraints[constraint]);
                control.onChange = function () {
                    var _a;
                    (_a = _this.onLaunchSpecModified) === null || _a === void 0 ? void 0 : _a.call(_this, _this.getLaunchSpec());
                };
                this.constraints.push(control);
                this.options.appendChild(control.make(this.uiOptions));
                if (this.resuming()) {
                    for (var _k = 0, _l = this.input.launch_spec.placement_constraints; _k < _l.length; _k++) {
                        var p = _l[_k];
                        if (p.name === constraint) {
                            control.set(p.value);
                            break;
                        }
                    }
                }
            }
        }
        if (this.hasCollection(cluster.queues)) {
            var control = new QueueControl(cluster.queues);
            this.queue = control;
            this.options.appendChild(control.make(this.uiOptions));
            if (this.resuming() && this.hasCollection(this.input.launch_spec.queues)) {
                control.set(this.input.launch_spec.queues[0]);
            }
        }
        var defaultImage = "";
        if (workbenchObj)
            defaultImage = workbenchObj.default_image;
        if (cluster.supportsContainers &&
            (this.hasCollection(availableImages) || cluster.allowUnknownImages || cluster.defaultImage || defaultImage)) {
            if (!defaultImage && cluster.defaultImage) {
                defaultImage = cluster.defaultImage;
            }
            var control = new ImageControl(availableImages, defaultImage, cluster.allowUnknownImages);
            this.image = control;
            this.image.onChange = function () {
                var _a;
                (_a = _this.onLaunchSpecModified) === null || _a === void 0 ? void 0 : _a.call(_this, _this.getLaunchSpec());
            };
            this.options.appendChild(control.make(this.uiOptions));
            if (this.resuming()) {
                control.set(this.input.launch_spec.container_image, cluster.allowUnknownImages);
            }
        }
    };
    LauncherUI.prototype.getLaunchSpec = function () {
        var spec = {};
        spec.name = this.name.value;
        var selected = this.cluster.options[this.cluster.selectedIndex];
        spec.cluster = (selected === null || selected === void 0 ? void 0 : selected.value) || '';
        var ok = true;
        for (var _i = 0, _a = this.limits; _i < _a.length; _i++) {
            var limit = _a[_i];
            if (!limit.input.validateInput())
                ok = false;
        }
        if (!ok) {
            return null;
        }
        spec.placement_constraints = new Array();
        for (var _b = 0, _c = this.constraints; _b < _c.length; _b++) {
            var constraint = _c[_b];
            var placement = constraint.constraint();
            if (placement !== null) {
                spec.placement_constraints.push(placement);
            }
        }
        spec.resource_limits = new Array();
        for (var _d = 0, _e = this.limits; _d < _e.length; _d++) {
            var limit = _e[_d];
            var value = limit.value();
            if (value === null) {
                continue;
            }
            spec.resource_limits.push(value);
        }
        spec.queues = [];
        if (this.queue) {
            spec.queues.push(this.queue.value());
        }
        if (this.image) {
            spec.container_image = this.image.value();
            spec.default_image = this.image.defaultImage;
            spec.container_images = this.image.images.map(function (img) { return img.image; });
        }
        else {
            spec.container_image = "";
            spec.default_image = "";
            spec.container_images = [""];
        }
        if (this.awsRole && this.awsRole.value !== "None") {
            spec.aws_role = this.awsRole.value;
        }
        if (this.resourceProfile) {
            spec.resource_profile = this.resourceProfile.profile();
            if (!this.resourceProfile.isCustom()) {
                spec.resource_limits = new Array();
            }
        }
        return spec;
    };
    LauncherUI.prototype.getWorkbench = function () {
        return this.workbench.value;
    };
    LauncherUI.prototype.setJobName = function (name) {
        this.name.value = name;
    };
    LauncherUI.prototype.getJobName = function () {
        return this.name.value;
    };
    LauncherUI.prototype.resuming = function () {
        return typeof (this.input.launch_spec) !== "undefined" &&
            this.input.launch_spec !== null;
    };
    return LauncherUI;
}());
function launcherUi(host, rpcUrlPrefix, input, uiOptions) {
    var ui = new LauncherUI(host, rpcUrlPrefix, input, uiOptions);
    ui.initialize();
    return ui;
}
