/// <reference path="./event/EventProcessor.ts" />
/// <reference path="./macro/IMacroDefinition.ts" />
/// <reference path="./tag/ITagDefinition.ts" />
/// <reference path="./macro/reader/Reader.ts" />
/// <reference path="./macro/filter/Filter.ts" />
/// <reference path="./Matcher.ts" />
/// <reference path="./tag/MacroProcessor.ts" />
/// <reference path="./tag/injector/Injector.ts" />
/// <reference path="../collection/List.ts" />
var econda;
(function (econda) {
    var tagmanager;
    (function (tagmanager) {
        var MacroReader = econda.tagmanager.macro.reader.Reader;
        var Filter = econda.tagmanager.macro.filter.Filter;
        var List = econda.collection.List;
        var MacroProcessor = econda.tagmanager.tag.MacroProcessor;
        var TagInjector = econda.tagmanager.tag.injector.Injector;
        /**
         * Tag Manager container.
         * @class econda.tagmanager.Container
         */
        var Container = (function () {
            function Container(cfg) {
                /**
                 * Containers must be available as global variables (window object). We need this to allow tags access to container functions.
                 * @private
                 * @property {String} _varName
                 */
                this._varName = null;
                this._dataLayer = {};
                this._events = {};
                this._tagDefinitions = null;
                this._macroDefinitions = null;
                this._macroNameToIdMap = {};
                this._macroReader = null;
                this._filter = null;
                this._tagMacroProcessor = null;
                this._tagInjector = null;
                // register as global variable.
                window[cfg.containerVarName] = this;
                // setup data
                this._varName = cfg.containerVarName;
                this._dataLayer = cfg.dataLayer;
                this._events = cfg.events;
                this._tagDefinitions = new List({
                    idProperty: 'id',
                    items: cfg.tagDefinitions
                });
                this._macroDefinitions = new List({
                    idProperty: 'id',
                    items: cfg.macroDefinitions
                });
                // initialize
                // macro readers uses specialized readers to read values from specified source
                this._macroReader = new MacroReader({
                    dataLayer: this._dataLayer,
                    globalVariableParent: window,
                    container: this
                });
                // filter returned values (extract sub strings, read special properties, ...)
                this._filter = new Filter();
                // responsible for replacing macro placeholders in tags
                this._tagMacroProcessor = new MacroProcessor({
                    containerVarName: this._varName
                });
                // responsible for injecting tags in DOM
                this._tagInjector = new TagInjector();
            }
            //noinspection JSValidateJSDoc
            /**
             * Returns current value of macro with given id
             * @param {String} macroId
             * @param currentEvent
             * @returns {Mixed}
             */
            Container.prototype.getValue = function (macroId, currentEvent) {
                if (currentEvent === void 0) { currentEvent = null; }
                var macroDefinition = this._macroDefinitions.getItemById(macroId);
                var ret = this._macroReader.readValue(macroDefinition, currentEvent);
                if (ret.success) {
                    return this._filter.getFilteredValue(macroDefinition, ret.value);
                }
                else {
                    return null;
                }
            };
            //noinspection JSValidateJSDoc
            /**
             * Get macro value by macro name.
             * @param {String} macroName
             * @param currentEvent
             * @returns {Mixed}
             */
            Container.prototype.getValueByName = function (macroName, currentEvent) {
                if (currentEvent === void 0) { currentEvent = null; }
                macroName = String(macroName).replace(/^\s+|\s+$/g, '');
                if (typeof this._macroNameToIdMap[macroName] === 'undefined') {
                    this._updateMacroNameToIdMapping();
                    if (typeof this._macroNameToIdMap[macroName] === 'undefined') {
                        return null;
                    }
                }
                return this.getValue(this._macroNameToIdMap[macroName], currentEvent);
            };
            /**
             * Update hashmap that maps macro names to macro ids
             * @private
             */
            Container.prototype._updateMacroNameToIdMapping = function () {
                var _this = this;
                this._macroDefinitions.forEach(function (md) { return _this._macroNameToIdMap[md.name] = String(md.id); });
            };
            /**
             * Check constraints. True if constraint matches
             * @param {String} macroId
             * @param eventData
             * @returns {Boolean}
             */
            Container.prototype.isTrue = function (macroId, eventData) {
                if (eventData === void 0) { eventData = null; }
                var macroValue = this.getValue(macroId, eventData);
                return (macroValue != undefined && macroValue != null);
            };
            /**
             * Apply matching tags on document ready
             */
            Container.prototype.executeDocumentReady = function () {
                var _this = this;
                var matcher = new econda.tagmanager.Matcher({
                    checkConstraintCallback: function (macroId) { return _this.isTrue(macroId); }
                });
                var tagsWithMatchingConstraints = this._tagDefinitions.getFilteredItems(matcher);
                for (var n = 0; n < tagsWithMatchingConstraints.length; n++) {
                    var tagDefinition = tagsWithMatchingConstraints[n];
                    this._executeTag(tagDefinition);
                }
            };
            /**
             * Apply tag of given event
             */
            Container.prototype.executeEvent = function (currentEvent) {
                var _this = this;
                if (currentEvent === void 0) { currentEvent = null; }
                var matcher = new econda.tagmanager.Matcher({
                    currentEvent: currentEvent,
                    checkConstraintCallback: function (macroId, eventData) {
                        if (eventData === void 0) { eventData = null; }
                        return _this.isTrue(macroId, eventData);
                    }
                });
                var tagsWithMatchingConstraints = this._tagDefinitions.getFilteredItems(matcher);
                for (var n = 0; n < tagsWithMatchingConstraints.length; n++) {
                    var tagDefinition = tagsWithMatchingConstraints[n];
                    this._executeTag(tagDefinition);
                }
            };
            Container.prototype._executeTag = function (eventTag) {
                var tagCodeWithMacroValues = this._tagMacroProcessor.replaceMacroPlaceholders(eventTag.code);
                this._tagInjector.inject(eventTag, tagCodeWithMacroValues);
            };
            Container.prototype.init = function () {
                var eventProcessor = new econda.tagmanager.event.EventProcessor(this, this._events);
                eventProcessor.overwritePushMethod();
            };
            return Container;
        }());
        tagmanager.Container = Container;
    })(tagmanager = econda.tagmanager || (econda.tagmanager = {}));
})(econda || (econda = {}));