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="../../util/BaseContext.ts"/>
/// <reference path="../history/VisitorHistory.ts" />
/// <reference path="../../data.ts" />
/// <reference path="../../debug.ts" />
/// <reference path="IContextConfigOptions.ts" />
/// <reference path="IProductReferenceConfigOptions.ts" />
/// <reference path="ProductReference.ts" />
/// <reference path="CategoryReference.ts" />
var econda;
(function (econda) {
    var recengine;
    (function (recengine) {
        var context;
        (function (context) {
            var CategoryReference = econda.recengine.context.CategoryReference;
            var ProductReference = econda.recengine.context.ProductReference;
            var VisitorHistory = econda.recengine.history.VisitorHistory;
            /**
             * Request context, e.g. the product we want to get recommendations for.
             * @class econda.recengine.context.Context
             * @extends econda.base.BaseClass
             *
             * <h3>Setting the Context of a Widget or Request</h3>
             * <p>Examples are <strong>incomplete</strong> and will not work without additional configuration. All the following examples are identical.</p>
             *
             * <h4>Just pass the context configuration to the widget</h4>
             * <p>This is the preferred way.</p>
             *     var widget = new econda.recengine.Widget({
             *         ...
             *         context: {
             *             products: [{id: 'prodId1'}, {id: 'prodId2'}],
             *         }
             *     });
             *
             *
             * <h4>Use context object in widget configuration</h4>
             *     var widget = new econda.recengine.Widget({
             *         ...
             *         context: new econda.recengine.Context({
             *             products: [{id: 'prodId1'}, {id: 'prodId2'}],
             *         })
             *     });
             *
             * <h4>Create context object first</h4>
             *     var context = new econda.recengine.Context({
             * 	       products: {id: 'prodId1'}
             *     });
             *     context.addProducts({id: 'prodId2'});
             *     var widget = new econda.recengine.Widget({
             *         context: context
             *     });
             *
             * <h3>Example Context Configurations</h3>
             * <p>Examples are <strong>incomplete</strong> and will not work without additional configuration.</p>
             *
             * <h4>Widget on Product Detail Pages: "other customers bought..."</h4>
             *     var widget = new econda.recengine.Widget({
             *         ...
             *         id: 6,
             *         context: {
             *             products: {id: 'article number of product'},
             *         }
             *     });
             *
             * <h4>Widget on Category Page: "top sellers in this category"</h4>
             *     var widget = new econda.recengine.Widget({
             *         ...
             *         id: 7,
             *         context: {
             *             categories: {
             *                 type: "productcategory",
             *                 path: "T-Shirts"
             *             },
             *         }
             *     });
             *
             * <h4>Widget on Checkout Pages</h4>
             *     var widget = new econda.recengine.Widget({
             *         ...
             *         id: 8,
             *         context: {
             *             products: ['prodIdInCart1', 'prodIdInCart2', 'prodIdInCart3'],
             *         }
             *     });
             */
            var Context = (function (_super) {
                __extends(Context, _super);
                function Context(cfg) {
                    _super.call(this);
                    /**
                     * List of product references in context
                     * @cfg {econda.recengine.context.ProductReference[]} products
                     * @accessor
                     */
                    this.products = [];
                    this.visitorHistory = null;
                    /**
                     * List of categories in context
                     * @cfg {econda.recengine.context.CategoryReference[]} categories
                     * @accessor
                     */
                    this.categories = [];
                    /**
                     * Context attributes
                     *     var ctx = new econda.recengine.context.Context({
                     *         attributes: {
                     *             myattribute: "myvalue"
                     *         }
                     *     });
                     *
                     * @cfg {Object} attributes
                     * @accessor
                     */
                    this.attributes = {};
                    /**
                     * @cfg {econda.recengine.context.ProductReference[]} productsExcluded
                     * Products to exclude from response. This items will be passed to cross sell server. Limits will work correctly.
                     */
                    this.productsExcluded = [];
                    /**
                     * True to auto append visitor data from current visitor profile
                     * @cfg {Boolean} appendVisitorData
                     */
                    this._appendVisitorData = null;
                    var cfg = cfg || {};
                    if (cfg instanceof Context) {
                        return cfg;
                    }
                    else {
                        if (typeof cfg['appendVisitorData'] != 'undefined') {
                            this._appendVisitorData = cfg['appendVisitorData'] === true;
                            delete cfg['appendVisitorData'];
                        }
                        this.initConfig(cfg);
                    }
                    if (this._appendVisitorData === true
                        || this._appendVisitorData === null && (typeof econdaConfig.crosssellAppendVisitorData === 'undefined' || econdaConfig.crosssellAppendVisitorData === true)) {
                        this._doAppendVisitorData();
                    }
                }
                Context.prototype.getProducts = function () {
                    return this.products;
                };
                Context.prototype.setProducts = function (products) {
                    this.products = [];
                    this.addProducts(products);
                    return this;
                };
                /**
                 * adds a list of products to context
                 * @method
                 * @param {Object[]/econda.recengine.context.ProductReference[]} products
                 */
                Context.prototype.addProducts = function (products) {
                    return this.addArray('products', products, ProductReference, { itemFilter: this._productReferenceInputFilter });
                };
                /**
                 * Adds a single product
                 * @method
                 * @param {Object} product
                 * @chainable
                 */
                Context.prototype.addProduct = function (product) {
                    return this.addProducts(product);
                };
                Context.prototype.getVisitorHistory = function () {
                    return this.visitorHistory;
                };
                Context.prototype.setVisitorHistory = function (visitorHistory) {
                    this.visitorHistory = new VisitorHistory(visitorHistory);
                };
                Context.prototype.getCategories = function () {
                    return this.categories;
                };
                /**
                 * Set multiple categories references
                 *
                 *     // set one or multiple category references
                 *     context.setCategories([{ type: 'brand', path: 'econda' }, { type: 'productcategory', path: 'accessories'}]);
                 *
                 * @param {econda.recengine.context.CategoryReference[]} categories
                 */
                Context.prototype.setCategories = function (categories) {
                    return this.setArray('categories', categories, CategoryReference);
                };
                /**
                 * Add multiple category references
                 *
                 *     // add one or multiple category references
                 *     context.addCategories([{ type: 'brand', path: 'econda' }, { type: 'productcategory', path: 'accessories'}]);
                 *
                 * @param {econda.recengine.context.CategoryReference[]} categories
                 */
                Context.prototype.addCategories = function (categories) {
                    return this.addArray('categories', categories, CategoryReference);
                };
                /**
                 * Adds a single category reference
                 *
                 *     // add one category reference
                 *     context.addCategory({ type: 'brand', path: 'econda' });
                 *
                 * @param {econda.recengine.context.CategoryReference} category
                 */
                Context.prototype.addCategory = function (category) {
                    return this.addCategories(category);
                };
                Context.prototype.getAttributes = function () {
                    return this.attributes;
                };
                Context.prototype.setAttributes = function (attributes, value) {
                    if (value === void 0) { value = null; }
                    this.attributes = {};
                    return this.addAttributes(attributes, value);
                };
                /**
                 * Add attributes to context
                 *
                 *     // add one or multiple attributes
                 *     context.addAttributes({ myattr: "myvalue"});
                 *
                 *     // add single attribute
                 *     context.addAttributes('myattr', 'myvalue');
                 *
                 * @param {String/Object} attributes
                 * @param {String/Number} value
                 */
                Context.prototype.addAttributes = function (attributes, value) {
                    if (value === void 0) { value = null; }
                    if (typeof attributes == 'string') {
                        this.attributes[attributes] = value;
                    }
                    else {
                        for (var property in attributes) {
                            this.attributes[property] = attributes[property];
                        }
                    }
                    return this;
                };
                Context.prototype.getProductsExcluded = function () {
                    return this.productsExcluded;
                };
                Context.prototype.setProductsExcluded = function (products) {
                    return this.setArray('productsExcluded', products, ProductReference, { itemFilter: this._productReferenceInputFilter });
                };
                Context.prototype.addProductsExcluded = function (products) {
                    return this.addArray('productsExcluded', products, ProductReference, { itemFilter: this._productReferenceInputFilter });
                };
                Context.prototype._productReferenceInputFilter = function (product) {
                    if (product instanceof ProductReference) {
                        return product;
                    }
                    else {
                        return {
                            id: product.id || null,
                            sku: product.sku || null
                        };
                    }
                };
                Context.prototype.addToRequest = function (params) {
                    var categories = this.getCategories();
                    if (categories.length > 0) {
                        for (var i = 0; i < categories.length; i++) {
                            var cat = categories[i];
                            var prefix = 'ctxcat';
                            if (i > 0) {
                                prefix = prefix + i;
                            }
                            var typeParam = prefix + '.ct';
                            params[typeParam] = cat.getType();
                            if (cat.getId()) {
                                var byIdParam = prefix + '.cid';
                                params[byIdParam] = cat.getId();
                            }
                            if (cat.getPath()) {
                                var pathAsArrayParam = prefix + '.paa';
                                params[pathAsArrayParam] = cat.getPath();
                            }
                            if (cat.getVariant()) {
                                var variantParam = prefix + '.pv';
                                params[variantParam] = cat.getVariant();
                            }
                        }
                    }
                    // handle custom attributes
                    var attributes = this.getAttributes();
                    for (var name in attributes) {
                        switch (attributes[name]) {
                            case null:
                                params['ctxcustom.' + name] = '';
                                break;
                            default:
                                params['ctxcustom.' + name] = '' + attributes[name];
                        }
                    }
                    _super.prototype.addToRequest.call(this, params);
                };
                Context.prototype._doAppendVisitorData = function () {
                    try {
                        var visitorProfile = econda.data.visitor;
                        this.setVisitorId(visitorProfile.getVisitorId());
                        this.setSessionId(visitorProfile.getSessionId());
                        this.setCustomerId(visitorProfile.getCustomerId());
                        this.setUserId(visitorProfile.getUserId());
                        this.setRecipientId(visitorProfile.getRecipientId());
                        this.setEmail(visitorProfile.getEmail());
                        this.setEmailHash(visitorProfile.getEmailHash());
                        this.setProfileProperties(visitorProfile.getProperties());
                        this.setVisitorHistory(visitorProfile.getHistory());
                    }
                    catch (e) {
                        econda.debug.error('Could not append visitor profile data to cross sell request due to an internal exception: ' + e);
                    }
                };
                return Context;
            }(econda.base.BaseContext));
            context.Context = Context; // end of class
        })(context = recengine.context || (recengine.context = {}));
    })(recengine = econda.recengine || (econda.recengine = {}));
})(econda || (econda = {})); // end of module