"use strict";
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");
const clime_1 = require("clime");
class Repo {
    constructor(root) {
        this.root = root;
        try {
            this.config = this.loadConfig();
        }
        catch (e) {
            this.config = new config_1.ModelNestConfig();
        }
    }
    init(modelNestDirectory) {
        if (modelNestDirectory) {
            this.config.nest = modelNestDirectory;
        }
        this.writeConfig(false);
        fs_extra_1.ensureDirSync(this.modelNestDirectory);
    }
    get dot() {
        return path.join(this.root, '.nest');
    }
    get modelNestDirectory() {
        return path.join(this.root, this.config.nest);
    }
    get package() {
        return path.join(this.root, Repo.CONFIG_NAME);
    }
    get exists() {
        return fs.existsSync(this.package);
    }
    static findRepo(startDir) {
        let currentDir = startDir || process.cwd();
        while (currentDir != path.sep) {
            let repo = new Repo(currentDir);
            if (repo.exists) {
                ts_log_debug_1.$log.debug(`Found repo ${currentDir}`);
                return repo;
            }
            else {
                currentDir = path.dirname(currentDir);
            }
        }
        throw new clime_1.ExpectedError('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.ModelNestConfig, configString);
        return config;
    }
    writeConfig(overwrite = true) {
        this.writeToRoot(this.config, Repo.CONFIG_NAME);
    }
    async add(packageVersion) {
        ts_log_debug_1.$log.debug(`Adding asset "${packageVersion.name}' version "${packageVersion.version}"`);
        return this.downloadAsset(packageVersion);
    }
    async downloadAsset(packageVersion) {
        const remote = new remote_1.default();
        const version = await remote.getAssetVersion(packageVersion);
        if (version) {
            const oldVersion = this.readAssetVersion(packageVersion.name);
            if (oldVersion) {
                this.deleteAssetVersionContents(packageVersion, oldVersion);
            }
            await remote.downloadAsset(this.modelNestDirectory, packageVersion, version);
            this.writeAssetVersion(packageVersion.name, version);
            this.loadConfig();
            const packageConfig = this.config;
            packageConfig.assets[packageVersion.name] = version.version;
            this.writeConfig();
            return version;
        }
        else {
            return null;
        }
    }
    deleteAssetVersionContents(packageVersion, version) {
        for (const format of version.formats) {
            this.deleteAssetFile(packageVersion, format.root);
            for (const resource of format.resources) {
                this.deleteAssetFile(packageVersion, resource);
            }
        }
    }
    deleteAssetFile(packageVersion, assetFile) {
        const filePath = path.join(this.modelNestDirectory, packageVersion.name, assetFile.sourcePath);
        fs_extra_1.removeSync(filePath);
    }
    writeToRoot(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.writeFileSync(writePath, jsonData);
    }
    readAssetVersion(assetName) {
        const readPath = path_1.join(this.modelNestDirectory, assetName, 'version.json');
        if (fs.existsSync(readPath)) {
            const configString = fs.readFileSync(readPath, 'utf8');
            const assetFileRef = JSON.parse(configString);
            return assetFileRef;
        }
        return null;
    }
    writeAssetVersion(assetName, obj, overwrite = true) {
        const writePath = path_1.join(this.modelNestDirectory, 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);
        });
    }
    async status() {
        const remote = new remote_1.default();
        var assetStatuses = [];
        const workspaceConfig = this.config;
        for (const asset of Object.keys(workspaceConfig.assets)) {
            const currentVersion = workspaceConfig.assets[asset];
            const latestVersion = await remote.getAssetVersion({ version: 'latest', name: asset });
            if (latestVersion) {
                assetStatuses.push(new asset_file_status_1.AssetFileStatus({
                    name: asset,
                    version: currentVersion,
                }, {
                    name: asset,
                    version: latestVersion.version,
                }));
            }
        }
        return assetStatuses;
    }
    async update(asset) {
        ts_log_debug_1.$log.debug(`Updated ${asset}`);
        var newVersions = [];
        if (asset) {
            const version = await this.downloadAsset({
                name: asset,
                version: 'latest',
            });
            if (version)
                newVersions.push(new asset_file_status_1.AssetFileStatus({
                    name: asset,
                    version: version.version,
                }));
        }
        else {
            for (const asset of Object.keys(this.config.assets)) {
                const version = await this.downloadAsset({
                    name: asset,
                    version: 'latest',
                });
                if (version)
                    newVersions.push(new asset_file_status_1.AssetFileStatus({
                        name: asset,
                        version: version.version,
                    }));
            }
        }
        return newVersions;
    }
    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.MODEL_NEST_DIRECTORY = 'nest_models';
exports.default = Repo;
//# sourceMappingURL=repo.js.map