var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
/// <reference path="Request.ts" />
/// <reference path="widget/renderer/FunctionRenderer.ts" />
/// <reference path="widget/renderer/TemplateRenderer.ts" />
/// <reference path="widget/renderer/WebsaleRenderer.ts" />
/// <reference path="widget/IWidgetConfigOptions.ts" />
/// <reference path="../util/StringUtils.ts" />
/// <reference path="../util/DomHelper.ts" />
/// <reference path="recengine.d.ts" />
/// <reference path="../condition/ConditionContainer.ts" />
/// <reference path="../util/ArrayUtils.ts" />
/// <reference path="./widget/FallbackConfig.ts" />
/// <reference path="./widget/FallbackHandler.ts" />
var econda;
(function (econda) {
    var recengine;
    (function (recengine) {
        /**
         * Cross sell widget
         *
         * The following example shows a browser only implementation of a widget. If you are looking for a server side rendering, check #setRendererUri.
         *
         *
         * <h4>Render Template using an html template</h4>
         *     <div id="ecRecommendationsContainer">Loading...</div>
         *     <script type="text/javascript">
         *
         *     // Setup widget, load data and render using defined template
         *     var widget = new econda.recengine.Widget({
         *         element: document.getElementById('ecRecommendationsContainer'),
         *         renderer: {
         *             type: 'template',
         *             uri: '/path/to/my/template.html'
         *         },
         *         accountId: '00000cec-d98025a8-912b-46a4-a57d-7a691ba7a376-1',
         *         id: 6,
         *         context: {
         *             products: [{id: 'prodId1'}, {id:'prodId2'}],
         *             categories: [{
         *                 type: 'brand',
         *                 path: 'econda'
         *             }]
         *         }
         *     });
         *     widget.render();
         *
         *     </script>
         *
         * <h4>Render Widget using a Rendering Function</h4>
         *     var widget = new econda.recengine.Widget({
         *         element: document.getElementById('ecRecommendationsContainer'),
         *         renderer: {
         *             type: 'function',
         *             rendererFn: function(data, element, esc) { return 'rendered html'; }
         *         },
         *         accountId: '00000cec-d98025a8-912b-46a4-a57d-7a691ba7a376-1',
         *         id: 6
         *     });
         *     widget.render();
         *
         * @class econda.recengine.Widget
         * @extends econda.recengine.Request
         */
        var Widget = (function (_super) {
            __extends(Widget, _super);
            function Widget(cfg) {
                _super.call(this);
                /**
                 * HTML container element where we'll insert the widget HTML. Node reference, id or css selector (only if jQuery is present).
                 * Existing content will be removed.
                 * @cfg {String|HTMLElement} element
                 */
                this.element = null;
                /**
                 * Remove target {@link #cfg-element} if we have not enough products in response.
                 * @cfg {Boolean} removeIfEmpty
                 */
                this.removeIfEmpty = false;
                /**
                 * Callback if there are less recommendations than requested in response. Example: chunkSize = 4 but only 3 products in
                 * response => callback will be executed.
                 * @cfg {Function}
                 * @accessor
                 */
                this.empty = null;
                this.setEmpty = function (fn) {
                    this.empty = fn;
                    return this;
                };
                /**
                 * Any product list with less items than are defined as empty
                 * @cfg {Number} emptyThreshold
                 * @accessor
                 */
                this.emptyThreshold = null;
                /**
                 * Renderer configuration
                 * @cfg {String} renderer name or instance of a class that implements IRenderer interface
                 * @accessor
                 */
                this.renderer = null;
                /**
                 * Function to call after widget was rendered
                 * @cfg {Function} afterRender
                 * @accessor
                 */
                this.afterRender = null;
                /**
                 * If these conditions are not true, we'll not send any request but continue to fallback
                 * @cfg {econda.condition.ConditionContainer}
                 * @accessor
                 */
                this._preConditions = new econda.condition.ConditionContainer();
                this._fallback = null;
                if (cfg instanceof Widget) {
                    return cfg;
                }
                this.initConfig(cfg);
            }
            /**
             * Alias for {@link #widgetId}.
             * @cfg {Number} id
             * @accessor
             */
            Widget.prototype.getId = function () {
                return this.getWidgetId();
            };
            Widget.prototype.setId = function (id) {
                this.setWidgetId(id);
                return this;
            };
            Widget.prototype.getElement = function () {
                return this.element;
            };
            Widget.prototype.setElement = function (element) {
                this.element = element;
                return this;
            };
            Widget.prototype.getRemoveIfEmpty = function () {
                return this.removeIfEmpty;
            };
            Widget.prototype.setRemoveIfEmpty = function (removeIfEmpty) {
                this.removeIfEmpty = removeIfEmpty;
                return this;
            };
            Widget.prototype.getEmpty = function () {
                return this.empty;
            };
            Widget.prototype.getEmptyThreshold = function () {
                return (this.emptyThreshold != null)
                    ? this.emptyThreshold
                    : this.chunkSize;
            };
            Widget.prototype.setEmptyThreshold = function (itemCount) {
                this.emptyThreshold = itemCount;
                return this;
            };
            Widget.prototype.getRenderer = function () {
                return this.renderer;
            };
            Widget.prototype.setRenderer = function (renderer) {
                if (typeof renderer == 'string') {
                    this.renderer = this.createAndReturnRenderer(renderer);
                    return this;
                }
                if (renderer && renderer.type) {
                    this.renderer = this.createAndReturnRenderer(renderer.type, renderer);
                    return this;
                }
                this.renderer = renderer;
                return this;
            };
            Widget.prototype.setAfterRender = function (fn) {
                this.afterRender = fn;
                return this;
            };
            Widget.prototype.getAfterRender = function () {
                return this.afterRender;
            };
            Widget.prototype.setPreConditions = function (conditions) {
                this._preConditions.clear();
                this.addPreConditions(conditions);
                return this;
            };
            Widget.prototype.addPreConditions = function (conditions) {
                if (econda.util.ArrayUtils.isArray(conditions)) {
                    for (var n = 0; n < conditions.length; n++) {
                        this._preConditions.add(conditions[n]);
                    }
                }
                else {
                    this._preConditions.add(conditions);
                }
                return this;
            };
            Widget.prototype.setFallback = function (config) {
                this._fallback = new econda.recengine.widget.FallbackConfig(config);
                return this;
            };
            Widget.prototype.getFallback = function () {
                return this._fallback;
            };
            /**
             * Helper to create renderer instance
             * @private
             */
            Widget.prototype.createAndReturnRenderer = function (type, cfg) {
                if (cfg === void 0) { cfg = null; }
                var className = econda.util.StringUtils.ucFirst(type) + "Renderer";
                if (typeof econda.recengine.widget.renderer[className] == 'undefined') {
                    throw "Unknown renderer type: " + type;
                }
                if (typeof cfg.type != 'undefined') {
                    delete cfg.type;
                }
                return new econda.recengine.widget.renderer[className](cfg);
            };
            /**
             * Alias for {@link #render} function.
             */
            Widget.prototype.send = function () {
                _super.prototype.send.call(this);
            };
            /**
             * Request recommendations and render widget
             */
            Widget.prototype.render = function () {
                return this.send();
            };
            Widget.prototype.handleResponse = function (response) {
                // request will do things like calling success/error callback ...
                _super.prototype.handleResponse.call(this, response);
                // check if request was successfull
                if (response.getIsError() === true) {
                    this._onErrorResponse(response);
                    return;
                }
                // check if we got enough products in result
                if (response.products.length < this.getEmptyThreshold()) {
                    this._onEmptyResponse(response);
                    return;
                }
                this._onSuccessfulResponse(response);
            };
            // @private
            Widget.prototype._onSuccessfulResponse = function (response) {
                var _this = this;
                this.requestWasSuccessful = true;
                // render data with configured renderer
                if (this.renderer) {
                    var html = null;
                    this.renderer.setWidget(this);
                    html = this.renderer.render(response, function (html) {
                        if (html !== false) {
                            econda.util.DomHelper.update(_this.element, html);
                        }
                        if (typeof _this.afterRender == 'function') {
                            _this.afterRender.call(_this, _this.requestWasSuccessful);
                        }
                    });
                }
            };
            // @private
            Widget.prototype._onErrorResponse = function (response) {
                var cmp = this;
                this.requestWasSuccessful = false;
                var callbackAfterFallback = function () {
                    if (typeof this.afterRender == 'function') {
                        cmp.afterRender.call(cmp, cmp.requestWasSuccessful);
                    }
                };
                this._executeFallback(false, callbackAfterFallback);
            };
            // @private
            Widget.prototype._onEmptyResponse = function (response) {
                var cmp = this;
                this.requestWasSuccessful = false;
                var callbackAfterFallback = function () {
                    if (typeof cmp.afterRender == 'function') {
                        cmp.afterRender.call(cmp, cmp.requestWasSuccessful);
                    }
                    if (typeof cmp.empty == 'function') {
                        cmp.empty.call(cmp, response);
                    }
                };
                if (this.removeIfEmpty) {
                    econda.util.DomHelper.remove(this.element);
                    if (typeof this.empty == 'function') {
                        this.empty.call(this, response);
                    }
                }
                else {
                    this._executeFallback(true, callbackAfterFallback);
                }
            };
            /// @private
            Widget.prototype._executeFallback = function (allowCrossSellRequests, callback) {
                if (allowCrossSellRequests === void 0) { allowCrossSellRequests = true; }
                if (callback === void 0) { callback = null; }
                if (this._fallback !== null) {
                    var fallbackHandler = new econda.recengine.widget.FallbackHandler({
                        config: this._fallback,
                        element: this.element,
                        allowCrossSellRequests: allowCrossSellRequests,
                        callback: callback
                    });
                    fallbackHandler.execute();
                }
                else {
                    if (typeof callback == 'function') {
                        callback({ success: false });
                    }
                }
            };
            Widget.renderWidgetsFromConfigArray = function (configs) {
                for (var i = 0; i < configs.length; i++) {
                    var w = new Widget(configs[i]);
                    w.render();
                }
            };
            return Widget;
        }(recengine.Request));
        recengine.Widget = Widget; // end of class
        /// render widgets already defined in ecWidgets array
        var initEcWidgets = function () {
            if (typeof ecWidgets != 'undefined') {
                Widget.renderWidgetsFromConfigArray(ecWidgets);
            }
        };
        econda.util.DomHelper.isDocumentReady()
            ? initEcWidgets()
            : econda.util.DomHelper.documentReady(initEcWidgets);
    })(recengine = econda.recengine || (econda.recengine = {}));
})(econda || (econda = {})); // end of module