"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
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 (_) 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 __values = (this && this.__values) || function(o) {
    var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
    if (m) return m.call(o);
    if (o && typeof o.length === "number") return {
        next: function () {
            if (o && i >= o.length) o = void 0;
            return { value: o && o[i++], done: !o };
        }
    };
    throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ExamplesServiceImpl = void 0;
var inversify_1 = require("inversify");
var path_1 = require("path");
var fs = require("fs");
var util_1 = require("util");
var file_uri_1 = require("@theia/core/lib/node/file-uri");
var objects_1 = require("@theia/core/lib/common/objects");
var sketches_service_impl_1 = require("./sketches-service-impl");
var protocol_1 = require("../common/protocol");
var config_service_impl_1 = require("./config-service-impl");
var ExamplesServiceImpl = /** @class */ (function () {
    function ExamplesServiceImpl() {
    }
    ExamplesServiceImpl.prototype.init = function () {
        this.builtIns();
    };
    ExamplesServiceImpl.prototype.builtIns = function () {
        return __awaiter(this, void 0, void 0, function () {
            var exampleRootPath, exampleNames, _a;
            var _this = this;
            return __generator(this, function (_b) {
                switch (_b.label) {
                    case 0:
                        if (this._all) {
                            return [2 /*return*/, this._all];
                        }
                        exampleRootPath = path_1.join(__dirname, '..', '..', 'Examples');
                        return [4 /*yield*/, util_1.promisify(fs.readdir)(exampleRootPath)];
                    case 1:
                        exampleNames = _b.sent();
                        _a = this;
                        return [4 /*yield*/, Promise.all(exampleNames.map(function (name) { return path_1.join(exampleRootPath, name); }).map(function (path) { return _this.load(path); }))];
                    case 2:
                        _a._all = _b.sent();
                        return [2 /*return*/, this._all];
                }
            });
        });
    };
    // TODO: decide whether it makes sense to cache them. Keys should be: `fqbn` + version of containing core/library.
    ExamplesServiceImpl.prototype.installed = function (_a) {
        var fqbn = _a.fqbn;
        return __awaiter(this, void 0, void 0, function () {
            var user, current, any, packages, packages_1, packages_1_1, pkg, container, location_1, e_1_1;
            var e_1, _b;
            return __generator(this, function (_c) {
                switch (_c.label) {
                    case 0:
                        user = [];
                        current = [];
                        any = [];
                        if (!fqbn) return [3 /*break*/, 9];
                        return [4 /*yield*/, this.libraryService.list({ fqbn: fqbn })];
                    case 1:
                        packages = _c.sent();
                        _c.label = 2;
                    case 2:
                        _c.trys.push([2, 7, 8, 9]);
                        packages_1 = __values(packages), packages_1_1 = packages_1.next();
                        _c.label = 3;
                    case 3:
                        if (!!packages_1_1.done) return [3 /*break*/, 6];
                        pkg = packages_1_1.value;
                        return [4 /*yield*/, this.tryGroupExamples(pkg)];
                    case 4:
                        container = _c.sent();
                        location_1 = pkg.location;
                        if (location_1 === protocol_1.LibraryLocation.USER) {
                            user.push(container);
                        }
                        else if (location_1 === protocol_1.LibraryLocation.PLATFORM_BUILTIN || protocol_1.LibraryLocation.REFERENCED_PLATFORM_BUILTIN) {
                            current.push(container);
                        }
                        else {
                            any.push(container);
                        }
                        _c.label = 5;
                    case 5:
                        packages_1_1 = packages_1.next();
                        return [3 /*break*/, 3];
                    case 6: return [3 /*break*/, 9];
                    case 7:
                        e_1_1 = _c.sent();
                        e_1 = { error: e_1_1 };
                        return [3 /*break*/, 9];
                    case 8:
                        try {
                            if (packages_1_1 && !packages_1_1.done && (_b = packages_1.return)) _b.call(packages_1);
                        }
                        finally { if (e_1) throw e_1.error; }
                        return [7 /*endfinally*/];
                    case 9: return [2 /*return*/, { user: user, current: current, any: any }];
                }
            });
        });
    };
    /**
     * The CLI provides direct FS paths to the examples so that menus and menu groups cannot be built for the UI by traversing the
     * folder hierarchy. This method tries to workaround it by falling back to the `installDirUri` and manually creating the
     * location of the examples. Otherwise it creates the example container from the direct examples FS paths.
     */
    ExamplesServiceImpl.prototype.tryGroupExamples = function (_a) {
        var label = _a.label, exampleUris = _a.exampleUris, installDirUri = _a.installDirUri;
        return __awaiter(this, void 0, void 0, function () {
            var paths, _b, _c, example, examplesPath, exists, isDir, _d, fileNames, children, sketches_1, fileNames_1, fileNames_1_1, fileName, subPath, subIsDir, sketch, container, e_2_1, e_3_1, sketches;
            var e_3, _e, e_2, _f;
            var _this = this;
            return __generator(this, function (_g) {
                switch (_g.label) {
                    case 0:
                        paths = exampleUris.map(function (uri) { return file_uri_1.FileUri.fsPath(uri); });
                        if (!installDirUri) return [3 /*break*/, 22];
                        _g.label = 1;
                    case 1:
                        _g.trys.push([1, 20, 21, 22]);
                        _b = __values(['example', 'Example', 'EXAMPLE', 'examples', 'Examples', 'EXAMPLES']), _c = _b.next();
                        _g.label = 2;
                    case 2:
                        if (!!_c.done) return [3 /*break*/, 19];
                        example = _c.value;
                        examplesPath = path_1.join(file_uri_1.FileUri.fsPath(installDirUri), example);
                        return [4 /*yield*/, util_1.promisify(fs.exists)(examplesPath)];
                    case 3:
                        exists = _g.sent();
                        _d = exists;
                        if (!_d) return [3 /*break*/, 5];
                        return [4 /*yield*/, util_1.promisify(fs.lstat)(examplesPath)];
                    case 4:
                        _d = (_g.sent()).isDirectory();
                        _g.label = 5;
                    case 5:
                        isDir = _d;
                        if (!isDir) return [3 /*break*/, 18];
                        return [4 /*yield*/, util_1.promisify(fs.readdir)(examplesPath)];
                    case 6:
                        fileNames = _g.sent();
                        children = [];
                        sketches_1 = [];
                        _g.label = 7;
                    case 7:
                        _g.trys.push([7, 15, 16, 17]);
                        fileNames_1 = (e_2 = void 0, __values(fileNames)), fileNames_1_1 = fileNames_1.next();
                        _g.label = 8;
                    case 8:
                        if (!!fileNames_1_1.done) return [3 /*break*/, 14];
                        fileName = fileNames_1_1.value;
                        subPath = path_1.join(examplesPath, fileName);
                        return [4 /*yield*/, util_1.promisify(fs.lstat)(subPath)];
                    case 9:
                        subIsDir = (_g.sent()).isDirectory();
                        if (!subIsDir) return [3 /*break*/, 13];
                        return [4 /*yield*/, this.tryLoadSketch(subPath)];
                    case 10:
                        sketch = _g.sent();
                        if (!!sketch) return [3 /*break*/, 12];
                        return [4 /*yield*/, this.load(subPath)];
                    case 11:
                        container = _g.sent();
                        if (container.children.length || container.sketches.length) {
                            children.push(container);
                        }
                        return [3 /*break*/, 13];
                    case 12:
                        sketches_1.push(sketch);
                        _g.label = 13;
                    case 13:
                        fileNames_1_1 = fileNames_1.next();
                        return [3 /*break*/, 8];
                    case 14: return [3 /*break*/, 17];
                    case 15:
                        e_2_1 = _g.sent();
                        e_2 = { error: e_2_1 };
                        return [3 /*break*/, 17];
                    case 16:
                        try {
                            if (fileNames_1_1 && !fileNames_1_1.done && (_f = fileNames_1.return)) _f.call(fileNames_1);
                        }
                        finally { if (e_2) throw e_2.error; }
                        return [7 /*endfinally*/];
                    case 17: return [2 /*return*/, {
                            label: label,
                            children: children,
                            sketches: sketches_1
                        }];
                    case 18:
                        _c = _b.next();
                        return [3 /*break*/, 2];
                    case 19: return [3 /*break*/, 22];
                    case 20:
                        e_3_1 = _g.sent();
                        e_3 = { error: e_3_1 };
                        return [3 /*break*/, 22];
                    case 21:
                        try {
                            if (_c && !_c.done && (_e = _b.return)) _e.call(_b);
                        }
                        finally { if (e_3) throw e_3.error; }
                        return [7 /*endfinally*/];
                    case 22: return [4 /*yield*/, Promise.all(paths.map(function (path) { return _this.tryLoadSketch(path); }))];
                    case 23:
                        sketches = _g.sent();
                        return [2 /*return*/, {
                                label: label,
                                children: [],
                                sketches: sketches.filter(objects_1.notEmpty)
                            }];
                }
            });
        });
    };
    // Built-ins are included inside the IDE.
    ExamplesServiceImpl.prototype.load = function (path) {
        return __awaiter(this, void 0, void 0, function () {
            var stat, names, sketches, children, _a, _b, p, stat_1, sketch, child, e_4_1, label;
            var e_4, _c;
            return __generator(this, function (_d) {
                switch (_d.label) {
                    case 0: return [4 /*yield*/, util_1.promisify(fs.exists)(path)];
                    case 1:
                        if (!(_d.sent())) {
                            throw new Error('Examples are not available');
                        }
                        return [4 /*yield*/, util_1.promisify(fs.stat)(path)];
                    case 2:
                        stat = _d.sent();
                        if (!stat.isDirectory) {
                            throw new Error(path + " is not a directory.");
                        }
                        return [4 /*yield*/, util_1.promisify(fs.readdir)(path)];
                    case 3:
                        names = _d.sent();
                        sketches = [];
                        children = [];
                        _d.label = 4;
                    case 4:
                        _d.trys.push([4, 12, 13, 14]);
                        _a = __values(names.map(function (name) { return path_1.join(path, name); })), _b = _a.next();
                        _d.label = 5;
                    case 5:
                        if (!!_b.done) return [3 /*break*/, 11];
                        p = _b.value;
                        return [4 /*yield*/, util_1.promisify(fs.stat)(p)];
                    case 6:
                        stat_1 = _d.sent();
                        if (!stat_1.isDirectory()) return [3 /*break*/, 10];
                        return [4 /*yield*/, this.tryLoadSketch(p)];
                    case 7:
                        sketch = _d.sent();
                        if (!sketch) return [3 /*break*/, 8];
                        sketches.push(sketch);
                        return [3 /*break*/, 10];
                    case 8: return [4 /*yield*/, this.load(p)];
                    case 9:
                        child = _d.sent();
                        children.push(child);
                        _d.label = 10;
                    case 10:
                        _b = _a.next();
                        return [3 /*break*/, 5];
                    case 11: return [3 /*break*/, 14];
                    case 12:
                        e_4_1 = _d.sent();
                        e_4 = { error: e_4_1 };
                        return [3 /*break*/, 14];
                    case 13:
                        try {
                            if (_b && !_b.done && (_c = _a.return)) _c.call(_a);
                        }
                        finally { if (e_4) throw e_4.error; }
                        return [7 /*endfinally*/];
                    case 14:
                        label = path_1.basename(path);
                        return [2 /*return*/, {
                                label: label,
                                children: children,
                                sketches: sketches
                            }];
                }
            });
        });
    };
    ExamplesServiceImpl.prototype.group = function (paths) {
        return __awaiter(this, void 0, void 0, function () {
            var map, paths_1, paths_1_1, path, stat, e_5_1;
            var e_5, _a;
            return __generator(this, function (_b) {
                switch (_b.label) {
                    case 0:
                        map = new Map();
                        _b.label = 1;
                    case 1:
                        _b.trys.push([1, 6, 7, 8]);
                        paths_1 = __values(paths), paths_1_1 = paths_1.next();
                        _b.label = 2;
                    case 2:
                        if (!!paths_1_1.done) return [3 /*break*/, 5];
                        path = paths_1_1.value;
                        return [4 /*yield*/, util_1.promisify(fs.stat)(path)];
                    case 3:
                        stat = _b.sent();
                        map.set(path, stat);
                        _b.label = 4;
                    case 4:
                        paths_1_1 = paths_1.next();
                        return [3 /*break*/, 2];
                    case 5: return [3 /*break*/, 8];
                    case 6:
                        e_5_1 = _b.sent();
                        e_5 = { error: e_5_1 };
                        return [3 /*break*/, 8];
                    case 7:
                        try {
                            if (paths_1_1 && !paths_1_1.done && (_a = paths_1.return)) _a.call(paths_1);
                        }
                        finally { if (e_5) throw e_5.error; }
                        return [7 /*endfinally*/];
                    case 8: return [2 /*return*/, map];
                }
            });
        });
    };
    ExamplesServiceImpl.prototype.tryLoadSketch = function (path) {
        return __awaiter(this, void 0, void 0, function () {
            var sketch, _a;
            return __generator(this, function (_b) {
                switch (_b.label) {
                    case 0:
                        _b.trys.push([0, 2, , 3]);
                        return [4 /*yield*/, this.sketchesService.loadSketch(file_uri_1.FileUri.create(path).toString())];
                    case 1:
                        sketch = _b.sent();
                        return [2 /*return*/, sketch];
                    case 2:
                        _a = _b.sent();
                        return [2 /*return*/, undefined];
                    case 3: return [2 /*return*/];
                }
            });
        });
    };
    __decorate([
        inversify_1.inject(sketches_service_impl_1.SketchesServiceImpl),
        __metadata("design:type", sketches_service_impl_1.SketchesServiceImpl)
    ], ExamplesServiceImpl.prototype, "sketchesService", void 0);
    __decorate([
        inversify_1.inject(protocol_1.LibraryService),
        __metadata("design:type", Object)
    ], ExamplesServiceImpl.prototype, "libraryService", void 0);
    __decorate([
        inversify_1.inject(config_service_impl_1.ConfigServiceImpl),
        __metadata("design:type", config_service_impl_1.ConfigServiceImpl)
    ], ExamplesServiceImpl.prototype, "configService", void 0);
    __decorate([
        inversify_1.postConstruct(),
        __metadata("design:type", Function),
        __metadata("design:paramtypes", []),
        __metadata("design:returntype", void 0)
    ], ExamplesServiceImpl.prototype, "init", null);
    ExamplesServiceImpl = __decorate([
        inversify_1.injectable()
    ], ExamplesServiceImpl);
    return ExamplesServiceImpl;
}());
exports.ExamplesServiceImpl = ExamplesServiceImpl;
//# sourceMappingURL=examples-service-impl.js.map