define(["require", "exports", "../constants/error_msgs", "../constants/metadata_keys"], function (require, exports, ERROR_MSGS, METADATA_KEY) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    function tagParameter(annotationTarget, propertyName, parameterIndex, metadata) {
        var metadataKey = METADATA_KEY.TAGGED;
        _tagParameterOrProperty(metadataKey, annotationTarget, propertyName, metadata, parameterIndex);
    }
    exports.tagParameter = tagParameter;
    function tagProperty(annotationTarget, propertyName, metadata) {
        var metadataKey = METADATA_KEY.TAGGED_PROP;
        _tagParameterOrProperty(metadataKey, annotationTarget.constructor, propertyName, metadata);
    }
    exports.tagProperty = tagProperty;
    function _tagParameterOrProperty(metadataKey, annotationTarget, propertyName, metadata, parameterIndex) {
        var paramsOrPropertiesMetadata = {};
        var isParameterDecorator = (typeof parameterIndex === "number");
        var key = (parameterIndex !== undefined && isParameterDecorator) ? parameterIndex.toString() : propertyName;
        if (isParameterDecorator && propertyName !== undefined) {
            throw new Error(ERROR_MSGS.INVALID_DECORATOR_OPERATION);
        }
        if (Reflect.hasOwnMetadata(metadataKey, annotationTarget)) {
            paramsOrPropertiesMetadata = Reflect.getMetadata(metadataKey, annotationTarget);
        }
        var paramOrPropertyMetadata = paramsOrPropertiesMetadata[key];
        if (!Array.isArray(paramOrPropertyMetadata)) {
            paramOrPropertyMetadata = [];
        }
        else {
            for (var _i = 0, paramOrPropertyMetadata_1 = paramOrPropertyMetadata; _i < paramOrPropertyMetadata_1.length; _i++) {
                var m = paramOrPropertyMetadata_1[_i];
                if (m.key === metadata.key) {
                    throw new Error(ERROR_MSGS.DUPLICATED_METADATA + " " + m.key.toString());
                }
            }
        }
        paramOrPropertyMetadata.push(metadata);
        paramsOrPropertiesMetadata[key] = paramOrPropertyMetadata;
        Reflect.defineMetadata(metadataKey, paramsOrPropertiesMetadata, annotationTarget);
    }
    function _decorate(decorators, target) {
        Reflect.decorate(decorators, target);
    }
    function _param(paramIndex, decorator) {
        return function (target, key) { decorator(target, key, paramIndex); };
    }
    function decorate(decorator, target, parameterIndex) {
        if (typeof parameterIndex === "number") {
            _decorate([_param(parameterIndex, decorator)], target);
        }
        else if (typeof parameterIndex === "string") {
            Reflect.decorate([decorator], target, parameterIndex);
        }
        else {
            _decorate([decorator], target);
        }
    }
    exports.decorate = decorate;
});
