"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SerdeOptions = exports.Stage = void 0;
const case_1 = require("./case");
const utils_1 = require("./utils");
const registry_1 = require("./registry");
exports.Stage = Object.freeze({
    Serialize: 0,
    Deserialize: 1
});
class SerdeOptions {
    get registry() {
        return this.options.registry || registry_1.GlobalRegistry;
    }
    constructor(target, options = {}, properties = new Map()) {
        Object.defineProperty(this, "target", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: void 0
        });
        Object.defineProperty(this, "options", {
            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.options = options;
        this.properties = properties;
    }
    static from(target) {
        return new this(target);
    }
    getClassName(stage) {
        var _a, _b;
        if ((0, utils_1.isString)(this.options.rename)) {
            return this.options.rename;
        }
        else if (stage === exports.Stage.Serialize && (0, utils_1.isString)((_a = this.options.rename) === null || _a === void 0 ? void 0 : _a.serialize)) {
            return this.options.rename.serialize;
        }
        else if (stage === exports.Stage.Deserialize && (0, utils_1.isString)((_b = this.options.rename) === null || _b === void 0 ? void 0 : _b.deserialize)) {
            return this.options.rename.deserialize;
        }
        else {
            return this.target.constructor.name;
        }
    }
    getPropertyRename(property, stage, options) {
        var _a, _b;
        if (options != null) {
            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;
            }
        }
        return property;
    }
    getPropertyCase(name, stage) {
        var _a, _b;
        if ((0, utils_1.isNumber)(this.options.renameAll)) {
            return (0, case_1.convertCase)(name, this.options.renameAll);
        }
        else if (stage === exports.Stage.Serialize && (0, utils_1.isNumber)((_a = this.options.renameAll) === null || _a === void 0 ? void 0 : _a.serialize)) {
            return (0, case_1.convertCase)(name, this.options.renameAll.serialize);
        }
        else if (stage === exports.Stage.Deserialize && (0, utils_1.isNumber)((_b = this.options.renameAll) === null || _b === void 0 ? void 0 : _b.deserialize)) {
            return (0, case_1.convertCase)(name, this.options.renameAll.deserialize);
        }
        else {
            return name;
        }
    }
    getPropertyName(property, stage) {
        const options = this.properties.get(property);
        const name = options != null ? this.getPropertyRename(property, stage, options) : property;
        return this.getPropertyCase(name, stage);
    }
    getSerializationName(property) {
        return this.getPropertyName(property, exports.Stage.Serialize);
    }
    getDeserializationName(property) {
        return this.getPropertyName(property, exports.Stage.Deserialize);
    }
    getDefault(property) {
        const options = this.properties.get(property);
        if (options && (0, utils_1.isFunction)(options.default)) {
            return options.default();
        }
        else if ((0, utils_1.isFunction)(this.options.default)) {
            return this.options.default();
        }
    }
    //getCustomImpl(property: string, stage: Stage) {
    //  const options = this.properties.get(property)
    //  if (options != null) {
    //    if (stage === Stage.Serialize && isFunction(options.serializeWith)) {
    //      return options.serializeWith
    //    } else if (stage === Stage.Deserialize && isFunction(options.deserializeWith)) {
    //      return options.deserializeWith
    //    }
    //  }
    //}
    //getSerializer(property: string): Nullable<CustomSerializer> {
    //  return this.getCustomImpl(property, Stage.Serialize) as CustomSerializer
    //}
    //getDeserializer(property: string): Nullable<CustomDeserializer> {
    //  return this.getCustomImpl(property, Stage.Deserialize) as CustomDeserializer
    //}
    isConditionalSkip(skip) {
        return 'if' in skip && (0, utils_1.isFunction)(skip.if);
    }
    shouldSkip(property, value, stage) {
        const options = this.properties.get(property);
        if (options != null && options.skip != null) {
            if (typeof options.skip === 'boolean') {
                return options.skip;
            }
            else if (this.isConditionalSkip(options.skip)) {
                return options.skip.if(value);
            }
            else if (stage === exports.Stage.Serialize && typeof options.skip.serializing === 'boolean') {
                return options.skip.serializing;
            }
            else if (stage === exports.Stage.Serialize && this.isConditionalSkip(options.skip.serializing)) {
                return options.skip.serializing.if(value);
            }
            else if (stage === exports.Stage.Deserialize && typeof options.skip.deserializing === 'boolean') {
                return options.skip.deserializing;
            }
            else if (stage === exports.Stage.Deserialize && this.isConditionalSkip(options.skip.deserializing)) {
                return options.skip.deserializing.if(value);
            }
        }
        return false;
    }
    shouldSkipSerializing(property, value) {
        return this.shouldSkip(property, value, exports.Stage.Serialize);
    }
    shouldSkipDeserializing(property, value) {
        return this.shouldSkip(property, value, exports.Stage.Deserialize);
    }
}
exports.SerdeOptions = SerdeOptions;