"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    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) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
    result["default"] = mod;
    return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const ts_log_debug_1 = require("ts-log-debug");
const remote_1 = __importDefault(require("./remote"));
const config_1 = require("./config");
const class_transformer_1 = require("class-transformer");
const fs_extra_1 = require("fs-extra");
const asset_file_status_1 = require("./asset-file-status");
const repo_error_1 = require("./repo-error");
const path_1 = require("path");
class Repo {
    constructor(root) {
        this.root = root;
        try {
            this.config = this.loadConfig();
        }
        catch (e) {
            this.config = new config_1.Config();
        }
    }
    init() {
        if (!fs.existsSync(this.dot)) {
            fs.mkdirSync(this.dot);
        }
        this.writeConfig(false);
    }
    get objectsPath() {
        return path.join(this.dot, 'objects');
    }
    get refsPath() {
        return path.join(this.dot, 'refs');
    }
    get dot() {
        return path.join(this.root, '.nest');
    }
    get exists() {
        return fs.existsSync(this.dot);
    }
    static findRepo(startDir) {
        let currentDir = startDir || process.cwd();
        while (currentDir != path.sep) {
            try {
                let repo = new Repo(currentDir);
                ts_log_debug_1.$log.debug(`Found repo ${currentDir}`);
                return repo;
            }
            catch (_a) {
                currentDir = path.dirname(currentDir);
            }
        }
        throw new Repo('Not a model nest repo');
    }
    loadConfig() {
        const readpath = path.join(this.root, Repo.CONFIG_NAME);
        if (!fs.existsSync(readpath)) {
            throw new repo_error_1.RepoError('Not a model nest repo');
        }
        const configString = fs.readFileSync(readpath, 'utf8');
        const config = class_transformer_1.deserialize(config_1.Config, configString);
        return config;
    }
    writeConfig(overwrite = true) {
        this.jsonToRoot(this.config, Repo.CONFIG_NAME);
    }
    add(workspace, packageVersion) {
        return __awaiter(this, void 0, void 0, function* () {
            ts_log_debug_1.$log.debug(`Adding asset "${packageVersion.name}' version "${packageVersion.version}" to "${workspace}"`);
            return this.downloadAsset(workspace, packageVersion);
        });
    }
    downloadAsset(workspace, packageVersion) {
        return __awaiter(this, void 0, void 0, function* () {
            const remote = new remote_1.default();
            const version = yield remote.getAssetVersion(packageVersion);
            if (version) {
                const workspacePath = this.config.workspaces[workspace];
                const workspaceDirectory = path.join(this.root, workspacePath);
                const oldVersion = this.readAssetVersion(workspace, packageVersion.name);
                if (oldVersion) {
                    this.deleteAssetVersionContents(workspaceDirectory, packageVersion, oldVersion);
                }
                remote.downloadAsset(workspaceDirectory, packageVersion, version);
                this.writeAssetVersion(workspace, packageVersion.name, version);
                const workspaceConfig = this.readWorkspace(workspace);
                workspaceConfig.assets[packageVersion.name] = version.version;
                this.writeWorkspaceConfig(workspace, workspaceConfig);
                return version;
            }
            else {
                return null;
            }
        });
    }
    deleteAssetVersionContents(workspacePath, packageVersion, version) {
        for (const format of version.formats) {
            this.deleteAssetFile(workspacePath, packageVersion, format.root);
            for (const resource of format.resources) {
                this.deleteAssetFile(workspacePath, packageVersion, resource);
            }
        }
    }
    deleteAssetFile(workspacePath, packageVersion, assetFile) {
        const filePath = path.join(workspacePath, packageVersion.name, assetFile.sourcePath);
        fs_extra_1.removeSync(filePath);
    }
    jsonToRoot(obj, fileName, overwrite = true) {
        const writePath = path.join(this.root, fileName);
        if (!overwrite && fs.existsSync(writePath)) {
            return;
        }
        fs_extra_1.ensureDir(path.dirname(writePath));
        const jsonData = JSON.stringify(obj, null, 2);
        fs.writeFile(writePath, jsonData, err => {
            if (err)
                ts_log_debug_1.$log.error(err);
        });
    }
    writeWorkspaceConfig(alias, obj, overwrite = true) {
        const workspacePath = this.config.workspaces[alias];
        const writePath = path.join(this.root, workspacePath, Repo.WORKSPACE_CONFIG_NAME);
        if (!overwrite && fs.existsSync(writePath)) {
            return;
        }
        fs_extra_1.ensureDirSync(path.dirname(writePath));
        const jsonData = JSON.stringify(obj, null, 2);
        fs.writeFile(writePath, jsonData, err => {
            if (err)
                ts_log_debug_1.$log.error(err);
        });
    }
    readAssetVersion(alias, assetName) {
        const workspacePath = this.config.workspaces[alias];
        const readPath = path_1.join(this.root, workspacePath, assetName, 'version.json');
        if (fs.existsSync(readPath)) {
            const configString = fs.readFileSync(readPath, 'utf8');
            const assetFileRef = JSON.parse(configString);
            return assetFileRef;
        }
        return null;
    }
    writeAssetVersion(alias, assetName, obj, overwrite = true) {
        const workspacePath = this.config.workspaces[alias];
        const writePath = path_1.join(this.root, workspacePath, assetName, 'version.json');
        if (!overwrite && fs.existsSync(writePath)) {
            return;
        }
        fs_extra_1.ensureDirSync(path.dirname(writePath));
        const jsonData = JSON.stringify(obj, null, 2);
        fs.writeFile(writePath, jsonData, err => {
            if (err)
                ts_log_debug_1.$log.error(err);
        });
    }
    status() {
        return __awaiter(this, void 0, void 0, function* () {
            const remote = new remote_1.default();
            var assetStatuses = [];
            for (const workspace of Object.keys(this.config.workspaces)) {
                const workspaceConfig = this.readWorkspace(workspace);
                for (const asset of Object.keys(workspaceConfig.assets)) {
                    const currentVersion = workspaceConfig.assets[asset];
                    const latestVersion = yield remote.getAssetVersion({ version: 'latest', name: asset });
                    if (latestVersion) {
                        assetStatuses.push(new asset_file_status_1.AssetFileStatus(workspace, {
                            name: asset,
                            version: currentVersion,
                        }, {
                            name: asset,
                            version: latestVersion.version,
                        }));
                    }
                }
            }
            return assetStatuses;
        });
    }
    update(workspace, asset) {
        return __awaiter(this, void 0, void 0, function* () {
            ts_log_debug_1.$log.debug(`Updated ${asset}`);
            var newVersions = [];
            if (workspace && asset) {
                const version = yield this.downloadAsset(workspace, {
                    name: asset,
                    version: 'latest',
                });
                if (version)
                    newVersions.push(new asset_file_status_1.AssetFileStatus(workspace, {
                        name: asset,
                        version: version.version,
                    }));
            }
            else {
                for (const workspace of Object.keys(this.config.workspaces)) {
                    const workspaceConfig = this.readWorkspace(workspace);
                    for (const asset of Object.keys(workspaceConfig.assets)) {
                        const version = yield this.downloadAsset(workspace, {
                            name: asset,
                            version: 'latest',
                        });
                        if (version)
                            newVersions.push(new asset_file_status_1.AssetFileStatus(workspace, {
                                name: asset,
                                version: version.version,
                            }));
                    }
                }
            }
            return newVersions;
        });
    }
    readWorkspace(workspace) {
        const path = this.config.workspaces[workspace];
        const readpath = path_1.join(path_1.join(this.root, path), Repo.WORKSPACE_CONFIG_NAME);
        if (!fs.existsSync(readpath)) {
            throw new repo_error_1.RepoError('Not a model nest repo');
        }
        const configString = fs.readFileSync(readpath, 'utf8');
        const config = class_transformer_1.deserialize(config_1.WorkspaceConfig, configString);
        return config;
    }
    createWorkspace(alias, path) {
        const abspath = path_1.resolve(path_1.join(path, Repo.WORKSPACE_DIRECTORY_NAME));
        const projRelative = path_1.relative(this.root, abspath);
        this.config.workspaces[alias] = projRelative;
        fs_extra_1.ensureDir(abspath);
        this.writeWorkspaceConfig(alias, new config_1.WorkspaceConfig());
        this.writeConfig();
    }
    static splitPackageVersion(modelId) {
        let m;
        let packageName = '';
        let version = 'latest';
        let parts = modelId.split('@');
        if (parts.length > 0) {
            packageName = parts[0];
        }
        if (parts.length == 2) {
            version = parts[1];
        }
        return { name: packageName, version };
    }
}
Repo.PACKAGE_NAME_RE = /(@?\w+\/?\w+\/?\w+)@?(.*)/gm;
Repo.CONFIG_NAME = 'modelnest.json';
Repo.WORKSPACE_CONFIG_NAME = 'nest-workspace.json';
Repo.WORKSPACE_DIRECTORY_NAME = 'nest_models';
exports.default = Repo;
//# sourceMappingURL=repo.js.map