"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SerdeOptions = exports.PropertyMap = exports.Stage = void 0;
const case_1 = require("./case");
const utils_1 = require("./utils");
exports.Stage = Object.freeze({
    Serialize: 0,
    Deserialize: 1
});
class PropertyMap extends Map {
    constructor(options, iterable) {
        super(iterable);
        Object.defineProperty(this, "options", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: void 0
        });
        Object.defineProperty(this, "aliases", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: new Map()
        });
        this.options = options;
        this.buildAliasMap();
    }
    setAliasesFromOptions(key, options) {
        this.aliases.set(key, key);
        if (options.alias != null) {
            this.addAlias(options.alias, key);
        }
        if ((0, utils_1.isString)(options.rename)) {
            this.aliases.set(options.rename, key);
        }
        else if ((0, utils_1.isNumber)(this.options.container.renameAll)) {
            this.aliases.set(this.options.applyCaseConvention(exports.Stage.Deserialize, key), key);
        }
    }
    set(key, value) {
        super.set(key, value);
        this.setAliasesFromOptions(key, value);
        return this;
    }
    addAlias(alias, key) {
        if ((0, utils_1.isString)(alias)) {
            this.aliases.set(alias, key);
        }
        else if ((0, utils_1.isIterable)(alias)) {
            for (const a of alias) {
                this.addAlias(a, key);
            }
        }
    }
    getFieldFromAlias(alias) {
        return this.aliases.get(alias);
    }
    buildAliasMap() {
        for (const [key, value] of this.entries()) {
            if (value.alias != null) {
                this.addAlias(value.alias, key);
            }
        }
    }
}
exports.PropertyMap = PropertyMap;
class SerdeOptions {
    constructor(target, container = {}, properties = new PropertyMap(this)) {
        Object.defineProperty(this, "target", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: void 0
        });
        Object.defineProperty(this, "container", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: void 0
        });
        Object.defineProperty(this, "properties", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: void 0
        });
        this.target = target;
        this.container = container;
        this.properties = properties;
    }
    getClassName(stage, defaultName) {
        var _a, _b, _c, _d;
        if (defaultName === void 0) { defaultName = (_b = (_a = this.target) === null || _a === void 0 ? void 0 : _a.constructor) === null || _b === void 0 ? void 0 : _b.name; }
        if ((0, utils_1.isString)(this.container.rename)) {
            return this.container.rename;
        }
        else if (stage === exports.Stage.Serialize && (0, utils_1.isString)((_c = this.container.rename) === null || _c === void 0 ? void 0 : _c.serialize)) {
            return this.container.rename.serialize;
        }
        else if (stage === exports.Stage.Deserialize && (0, utils_1.isString)((_d = this.container.rename) === null || _d === void 0 ? void 0 : _d.deserialize)) {
            return this.container.rename.serialize;
        }
        else {
            return defaultName;
        }
    }
    getSerializedClassName(defaultName) {
        var _a, _b;
        if (defaultName === void 0) { defaultName = (_b = (_a = this.target) === null || _a === void 0 ? void 0 : _a.constructor) === null || _b === void 0 ? void 0 : _b.name; }
        return this.getClassName(exports.Stage.Serialize, defaultName);
    }
    getDeserializedClassName(defaultName) {
        var _a, _b;
        if (defaultName === void 0) { defaultName = (_b = (_a = this.target) === null || _a === void 0 ? void 0 : _a.constructor) === null || _b === void 0 ? void 0 : _b.name; }
        return this.getClassName(exports.Stage.Deserialize, defaultName);
    }
    getCaseConvention(stage) {
        var _a, _b;
        if ((0, utils_1.isNumber)(this.container.renameAll)) {
            if (stage === exports.Stage.Serialize) {
                return this.container.renameAll;
            }
            else {
                return case_1.CaseConvention.CamelCase;
            }
        }
        else if (stage === exports.Stage.Serialize && (0, utils_1.isNumber)((_a = this.container.renameAll) === null || _a === void 0 ? void 0 : _a.serialize)) {
            return this.container.renameAll.serialize;
        }
        else if (stage === exports.Stage.Deserialize && (0, utils_1.isNumber)((_b = this.container.renameAll) === null || _b === void 0 ? void 0 : _b.deserialize)) {
            return this.container.renameAll.deserialize;
        }
    }
    applyCaseConvention(stage, property) {
        const convention = this.getCaseConvention(stage);
        return convention != null ? (0, case_1.convertCase)(property, convention) : property;
    }
    getPropertyRename(stage, property) {
        var _a, _b;
        const options = this.properties.get(property);
        if (options == null) {
            return;
        }
        else if ((0, utils_1.isString)(options.rename)) {
            return options.rename;
        }
        else if (stage == exports.Stage.Serialize && (0, utils_1.isString)((_a = options.rename) === null || _a === void 0 ? void 0 : _a.serialize)) {
            return options.rename.serialize;
        }
        else if (stage == exports.Stage.Deserialize && (0, utils_1.isString)((_b = options.rename) === null || _b === void 0 ? void 0 : _b.deserialize)) {
            return options.rename.deserialize;
        }
    }
    getSerializationPropertyName(property) {
        return this.getPropertyRename(exports.Stage.Serialize, property) ||
            this.applyCaseConvention(exports.Stage.Serialize, property);
    }
    getNameFromAlias(alias) {
        return this.properties.getFieldFromAlias(alias);
    }
    getDeserializationPropertyName(property) {
        return this.getNameFromAlias(property) ||
            this.applyCaseConvention(exports.Stage.Deserialize, property);
    }
    shouldSkip(stage, property, value) {
        var _a, _b, _c, _d;
        const options = this.properties.get(property);
        if (options == null) {
            return false;
        }
        else if (typeof options.skip === 'boolean') {
            return options.skip;
        }
        else if ((0, utils_1.isFunction)(options.skip)) {
            return options.skip(value);
        }
        else if (stage === exports.Stage.Serialize && typeof ((_a = options.skip) === null || _a === void 0 ? void 0 : _a.serialize) === 'boolean') {
            return options.skip.serialize;
        }
        else if (stage === exports.Stage.Serialize && (0, utils_1.isFunction)((_b = options.skip) === null || _b === void 0 ? void 0 : _b.serialize)) {
            return options.skip.serialize(value);
        }
        else if (stage === exports.Stage.Deserialize && typeof ((_c = options.skip) === null || _c === void 0 ? void 0 : _c.deserialize) === 'boolean') {
            return options.skip.deserialize;
        }
        else if (stage === exports.Stage.Deserialize && (0, utils_1.isFunction)((_d = options.skip) === null || _d === void 0 ? void 0 : _d.deserialize)) {
            return options.skip.deserialize(value);
        }
        else {
            return false;
        }
    }
    shouldSkipSerialization(property, value) {
        return this.shouldSkip(exports.Stage.Serialize, property, value);
    }
    shouldSkipDeserialization(property, value) {
        return this.shouldSkip(exports.Stage.Deserialize, property, value);
    }
    defaultFor(property) {
        const options = this.properties.get(property);
        if (options != null && (0, utils_1.isFunction)(options.default)) {
            return options.default();
        }
        else if ((0, utils_1.isFunction)(this.container.default)) {
            return this.container.default();
        }
    }
    hasCustomSerializer(property) {
        var _a;
        const options = this.properties.get(property);
        return (0, utils_1.isFunction)((_a = options === null || options === void 0 ? void 0 : options.with) === null || _a === void 0 ? void 0 : _a.serialize);
    }
    hasCustomDeserializer(property) {
        var _a;
        const options = this.properties.get(property);
        return (0, utils_1.isFunction)((_a = options === null || options === void 0 ? void 0 : options.with) === null || _a === void 0 ? void 0 : _a.deserialize);
    }
    useCustomSerializer(serializer, property, value) {
        var _a, _b;
        const options = this.properties.get(property);
        return (_b = (_a = options === null || options === void 0 ? void 0 : options.with) === null || _a === void 0 ? void 0 : _a.serialize) === null || _b === void 0 ? void 0 : _b.call(_a, value, serializer);
    }
    useCustomDeserializer(deserializer, property) {
        var _a, _b;
        const options = this.properties.get(property);
        return (_b = (_a = options === null || options === void 0 ? void 0 : options.with) === null || _a === void 0 ? void 0 : _a.deserialize) === null || _b === void 0 ? void 0 : _b.call(_a, deserializer);
    }
}
exports.SerdeOptions = SerdeOptions;