"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const log_1 = __importDefault(require("../log"));
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const crypto_1 = __importDefault(require("crypto"));
const config_1 = __importDefault(require("../config"));
class Storage {
    references;
    constructor() {
        this.references = new Map();
    }
    emptyDir() {
        // Ensures that a directory is empty.
        // Deletes directory contents if the directory is not empty.
        // If the directory does not exist, it is created.
        const dir = config_1.default.getStoragePath();
        let items;
        try {
            items = fs_1.default.readdirSync(dir);
        }
        catch (e) {
            fs_1.default.mkdirSync(dir, { recursive: true });
            return;
        }
        items.forEach((item) => {
            fs_1.default.rmSync(path_1.default.join(dir, item), { recursive: true, force: true });
        });
    }
    dereference(url) {
        const references = (this.references.get(url) || 0) - 1;
        if (references < 0) {
            return log_1.default.warn("Tried to dereference a file that has no references", url);
        }
        if (references > 0) {
            return this.references.set(url, references);
        }
        this.references.delete(url);
        // Drop "storage/" from url and join it with full storage path
        const filePath = path_1.default.join(config_1.default.getStoragePath(), url.substring(8));
        fs_1.default.unlink(filePath, (err) => {
            if (err) {
                log_1.default.error("Failed to delete stored file", err.message);
            }
        });
    }
    store(data, extension, callback) {
        const hash = crypto_1.default.createHash("sha256").update(data).digest("hex");
        const a = hash.substring(0, 2);
        const b = hash.substring(2, 4);
        const folder = path_1.default.join(config_1.default.getStoragePath(), a, b);
        const filePath = path_1.default.join(folder, `${hash.substring(4)}.${extension}`);
        const url = `storage/${a}/${b}/${hash.substring(4)}.${extension}`;
        this.references.set(url, 1 + (this.references.get(url) || 0));
        // If file with this name already exists, we don't need to write it again
        if (fs_1.default.existsSync(filePath)) {
            return callback(url);
        }
        fs_1.default.mkdir(folder, { recursive: true }, (mkdirErr) => {
            if (mkdirErr) {
                log_1.default.error("Failed to create storage folder", mkdirErr.message);
                return callback("");
            }
            fs_1.default.writeFile(filePath, data, (err) => {
                if (err) {
                    log_1.default.error("Failed to store a file", err.message);
                    return callback("");
                }
                callback(url);
            });
        });
    }
}
exports.default = new Storage();
