///<reference path="/Web/Js/TESCO.js" />
///<reference path="/Web/Js/system/event.js" />
///<reference path="/Web/Js/system/event.manager.js" />
///<reference path="/Web/Js/system/exception.js" />
///<reference path="/Web/Js/system/DOM.node.js" />
///<reference path="/Web/Js/UI/position.js" />
///<reference path="inputs.js" />
///<reference path="dialogue.js" />
///<reference path="flyout.js" />
///<reference path="/Web/Js/system/connection/XMLHTTP.js" />
///<reference path="/Web/Js/system/connection/ajax.js" />
///<reference path="/Web/Js/UI/effects.js" />
///<reference path="entities.js" />

TESCO.$("sites.retail.UI").Product = (function() {

    //	private static
    //#region
    var NODE = TESCO.system.DOM.node;
    var EVENT = TESCO.system.event;
    var PRODUCT = TESCO.UI.entities.Product;
    var LOCALE;

    var _quantChanged = 0;
    var _validExitLink = false;
    var _productIdFormat = /^p-[a-zA-Z_-]*([0-9]{1,10})(@([a-zA-Z0-9]{1,10}))*(@([A-Z][0-9]{1,10})-promo)*(-)*[0-9]{0,3}(-)*(flyout)*$/;
    var _registary = [];
    var _list;
    var _pending = [];
    var _pendingDialogue;
    var _productRows = [];

    function _setProductAddQtyBtn(node, incBtn, enabled) {
        var _className = (incBtn) ? "piDisabled" : "pdDisabled";
        var _el = NODE.getElementsByClassAndTagName(node, (incBtn) ? "pi" : "pd", "div");
        if (enabled) {
            NODE.removeClassName(_el[0], _className);
        } else {
            NODE.addClassName(_el[0], _className);
        }
    }

    function _getProductAddQty(node) {
        var _el = NODE.getElementsByClassAndTagName(node, "pq", "input");
        return (!_el || !(/^[0-9]*(\.[0-9]{1,3})?$/).test(_el[0].value)) ? 0 : parseFloat(_el[0].value);
    }

    function _adjustAddQty(product, shift, node) {
        // Increase or decease add quantity by shift
        product.incDecQty(shift, TESCO.sites.Configuration.activeBasket.id);
    }

    function _adjustPendingProducts(e) {
        if (_pending.size() > 0 && _validExitLink == false) {
            var _target = e.target;
            e.prevent();
            _pendingDialogue = new TESCO.sites.retail.UI.Dialogue.Ajax(new TESCO.sites.retail.UI.Dialogue.Request("PendingChanges"));

            function __redirect() {
                var _redirectTo = _target.href;
                if (_target.tagName.toUpperCase() == "IMG") {
                    _redirectTo = _target.parentNode.href;
                }
                document.location.href = _redirectTo;
            }

            function __confirmed() {
                __clean();
                EVENT.attach(PRODUCT.event, "quantityupdateend", __redirect);
                EVENT.attach(PRODUCT.event, "quantityupdateerror", __clean);
                for (var key in _pending) {
                    if (_pending.hasOwnProperty(key)) {
                        _pending[key].updateBasketQuantity(PRODUCT.steps.add, TESCO.sites.Configuration.activeBasket, null);
                    }
                }
                _pendingDialogue.hide();
            }

            function __cancelled() {
                __clean();
                __redirect();
            }

            function __clean() {
                _pendingDialogue.removeEventListener("confirm", __confirmed);
                _pendingDialogue.removeEventListener("cancel", __cancelled);
                _pendingDialogue.removeEventListener("error", __clean);
                EVENT.detach(PRODUCT.event, "quantityupdateend", __redirect);
                EVENT.detach(PRODUCT.event, "quantityupdateerror", __clean);
            }

            _pendingDialogue.addEventListener("confirm", __confirmed);
            _pendingDialogue.addEventListener("cancel", __cancelled);
            _pendingDialogue.addEventListener("error", __clean);

            _pendingDialogue.show();
        }
    }
    //#endregion

    //	private instance
    //#region
    function _lock(product, node) {
        var _btn = NODE.getElementsByClassAndTagName(node, "pa", "input")[0];
        if (_btn) {
            _btn.disabled = true;
            _btn.src = LOCALE.imageDisabledAddButton.src;
            
            if (NODE.hasClassName(_btn, "paEnabled")) {
                NODE.replaceClassName(_btn, "paEnabled", "paDisabled");
            } else {
                NODE.addClassName(_btn, "paDisabled");
            }    
        }
    }

    function _update(product, callback) {
        // update all the nodes with new product information 
        var _p;
        if (_p = _registary[product.getId()]) {	//	is it registered?
            for (var i = 0, L = _p.length; i < L; i++) {
                callback.call(this, product, _p[i]);
            }
        }
    }

    function _unlock(product, node) {
        var _btn = NODE.getElementsByClassAndTagName(node, "pa", "input")[0];
        if (_btn && !product.atCurrentMaxQty(TESCO.sites.Configuration.activeBasket.id)) {
            _btn.disabled = false;
            _btn.src = LOCALE.imageAddButton.src;
            if (NODE.hasClassName(_btn, "paDisabled")) {
                NODE.replaceClassName(_btn, "paDisabled", "paEnabled");
            } else {
                NODE.addClassName(_btn, "paEnabled");
            }
        }
        this.update(product, node);
    }
    
    function _roundOffAndUpdateQuantity(input) {
        var _control = this.getControl(input);
        var _product;
        if (_control && !(input.value == "")) {
            _product = PRODUCT.getProductById(_control.productId);
            if (_control.action === "qty") { // add quantity has been changed
                _product.setQuantity(input.value, TESCO.sites.Configuration.activeBasket.id, input);
            }
            this.setPendingProducts(_product);
        }
        return {
            "control": _control,
            "product": _product
        }
    }

    //#endregion

    //	constructor
    function _constructor() {
        //	events
        //#region
        var _self = this;
        EVENT.attach(PRODUCT.event, "updateerror",
            function(input) {
                if (!input.colour) {
                    input.colour = new TESCO.UI.effects.Colour(input);
                }
                input.warn();
            }
        );
        EVENT.attach(PRODUCT.event, "update",
			function(e) {
			    _update.call(_self, e, _self.update);
			}
		);
        EVENT.attach(PRODUCT.event, "quantityupdatestart",
			function(e) {
			    _update.call(_self, e, _self.update);
			}
		);
        EVENT.attach(PRODUCT.event, "quantityupdatesend",
			function(e) {
			    for (var i = 0, L = e.baskets.length; i < L; i++) {
			        for (var ii = 0, LL = e.baskets[i].products.length; ii < LL; ii++) {
			            _update.call(_self, e.baskets[i].products[ii], _lock);
			        }
			    }
			}
		);
        EVENT.attach(PRODUCT.event, "quantityupdateend",
			function(e) {
			    _update.call(_self, e, _unlock);
			}
		);
        EVENT.attach(PRODUCT.event, "quantityupdateerror",
			function(e) {
			    _update.call(_self, e, _unlock);
			}
		);
        //	wait for the body
        EVENT.document.addEventListener("beforeload",
			function() {
			    LOCALE = TESCO.locale.product;
			    EVENT.attach(document.body, "click",
					function(e) {
					    _self.click(e);
					    if (!e.prevented) {
							if ((e.target.tagName.toUpperCase() == "A") || 
								(e.target.tagName.toUpperCase() == "IMG" && e.target.parentNode.tagName.toUpperCase() == "A")) {
								_adjustPendingProducts(e);
							}
						}
					}
				);
			}
		);

        //	after body loaded cache existing product controls and initialise alt product flyout
        EVENT.document.addEventListener("load",
			function() {
				_self.registerList(document.body);
			}
		);
        //#endregion
        return this;
    }

    //	public instance
    //#region

    _constructor.prototype.NAME = "TESCO.sites.retail.UI.Product";

    _constructor.prototype.actions = [
		{ val: "locked", className: "locked", depth: 2 },
		{ val: "qtyInc", className: "pi", depth: 2 },
		{ val: "qtyDec", className: "pd", depth: 2 },
		{ val: "qty", className: "pq" },
		{ val: "addToBasket", className: "pa" }
	];

    _constructor.prototype.update = function(product, node, containerName) {
        // redraw the screen product controls based on the entity
        if (node) {
            var _container = NODE.getElementsByClassAndTagName(node, "addToBasket", containerName || "fieldset")[0];
            if (_container) {
                var _el;
                if (_el = NODE.getElementsByClassAndTagName(node, "pq", "input")) {
                    _el[0].value = product.getQuantity();
                }
                _setProductAddQtyBtn(node, true, !product.atMaxQty(TESCO.sites.Configuration.activeBasket.id));
                _setProductAddQtyBtn(node, false, !product.atMinQty());
                // build 'xx in basket' & max quantity messages
                NODE.removeClassName(_container, "inBasket");
                NODE.removeClassName(_container, "addToUpdate");
                var _msg = null;
                if (!product.atMinQty()) {
                    _msg = LOCALE.addToUpdateValue;
                    NODE.addClassName(_container, "addToUpdate");
                } else if (product.atCurrentMaxQty(TESCO.sites.Configuration.activeBasket.id)) {
                    _msg = LOCALE.maxQuantityValue;
                    NODE.addClassName(_container, "inBasket");
                } else if (product.isInBasket(TESCO.sites.Configuration.activeBasket.id)) {
                    NODE.addClassName(_container, "inBasket");
                    var _qty = product.getFormattedQty(TESCO.sites.Configuration.activeBasket.id);
                    _msg = LOCALE.inBasketValue.format(_qty, (_qty.toString() !== "1" ? TESCO.locale.plural : ""));
                }
                NODE.removeElementsByClassName(_container.parentNode, "basketInfo");
                if (_msg) {
                    var _p = NODE.create("p", _msg);
                    NODE.addClassName(_p, "basketInfo");
                    _container.appendChild(_p);
                }
            }
        }
        return node;
    }

    _constructor.prototype.change = function(e) {
        return _roundOffAndUpdateQuantity.call(this, e.target);
    }

    _constructor.prototype.setPendingProducts = function(product) {
        if (!(product.atMinQty()) && !(_pending['p-' + product.getId()])) {
            _pending['p-' + product.getId()] = product;
        } else if (product.atMinQty()) {
            delete _pending['p-' + product.getId()];
        }
    }

    _constructor.prototype.getControl = function(target) {
        var _node, _action;
        if (_node = NODE.getAncestorByAttributeRegExp(target, "id", _productIdFormat)) {
            if (_action = NODE.getAction(this.actions, target) || "refresh") {
                var _match = _productIdFormat.exec(_node.id);
                if (_match) {
                    return {
                        "node": _node,
                        "action": _action,
                        "productId": parseInt(_match[1], 10),
                        "promoId": _match[3],
                        "addQty": _getProductAddQty(_node)
                    }
                }
            }
        }
        return null;
    }

    _constructor.prototype.registerList = function(container,isSpecFlyout) {
        var _fs = NODE.getElementsByClassAndTagName(container, "addToBasket", "fieldset");
        if (_fs) {
            for (var i = 0; i < _fs.length; i++) {
                this.register(_fs[i], isSpecFlyout);
            }
        }
    }

    _constructor.prototype.register = function(target, isSpecFlyout) { //,isSpecFlyout) {
        var _self = this;
        var _control;
        if (_control = this.getControl(target)) {
            var _p;
            if ((isSpecFlyout == true) && (_p = _registary[_control.productId])){           
                _registary[_control.productId] = [];
            }            
            if (_p = _registary[_control.productId]) {	//	exists in _registary
                var i, L;
                for (i = 0, L = _p.length; i < L; i++) {
                    if (_p[i] == _control.node)
                        break;
                }
                _p[i] = _control.node;
            } else {
                _registary[_control.productId] = [_control.node];  // create an array so we can add more later
            }           
            
            EVENT.attach(target.getElementsByTagName('input')[0], "blur",
                function(e) {
                    _self.change(e);
                }
            );
        }
    }
    
    _constructor.prototype.getRegisteredProductsById = function(id) {
        return _registary[id];
    }
    
    _constructor.prototype.getRegisteredProducts = function() {
        return _registary;
    }

    _constructor.prototype.click = function(e) {       
        var _control = this.getControl(e.target);
        var _stopped = true;
        var _product;
        if (_control) {
            _product = PRODUCT.getProductById(_control.productId);
            switch (_control.action) {
                case "locked":
                    e.prevent();
                    break;
                case "addToBasket":
                    NODE.addClassName(_control.node, 'productAdding');                    
                    var _quantityField = TESCO.system.DOM.node.getSibling(e.target, 'input', 'pq');
                    if (!(NODE.hasClassName(e.target, "paDisabled"))) {
                        _roundOffAndUpdateQuantity.call(this, _quantityField);
                        _product.updateBasketQuantity(PRODUCT.steps.add, TESCO.sites.Configuration.activeBasket, this.getLocation(e.target));
                    }                      
                    e.prevent();
                    _validExitLink = true;
                    break;
                case "qtyInc":
                    if (!(NODE.hasClassName(e.target, "piDisabled"))) {
                        _adjustAddQty(_product, 1, _control.node);
                    }
                    this.setPendingProducts(_product);
                    e.prevent();
                    break;
                case "qtyDec":
                    if (!(NODE.hasClassName(e.target, "piDisabled"))) {
                        _adjustAddQty(_product, -1, _control.node);
                    }
                    this.setPendingProducts(_product);
                    e.prevent();
                    break;
                default:
                    _stopped = false;
            }
        } else {
            if ((!e.prevented) && (e.target.tagName.toUpperCase() == "A") || 
            (e.target.tagName.toUpperCase() == "IMG" && e.target.parentNode.tagName.toUpperCase() == "A")) {
				_adjustPendingProducts(e);
			}
        }       
        return {
            "control": _control,
            "product": _product,
            "stopped": _stopped
        }
    }
    //#endregion

    //	return _constructor as function pointer
    return _constructor;
})();

