///<reference path="../TESCO.js" />
///<reference path="../event.js" />
///<reference path="../eventManager.js" />
///<reference path="../exception.js" />
///<reference path="../node.js" />
///<reference path="inputs.js" />
///<reference path="dialogue.js" />
///<reference path="flyout.js" />
///<reference path="../validation.js" />
///<reference path="../XMLHTTP.js" />
///<reference path="../ajax.js" />
///<reference path="../effects.js" />
///<reference path="entities.js" />

TESCO.$("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 _focus = null;
    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;

    function _getLocation(element) {
        //	Check if this product was from a productlist, productdetails, or featuredspace

        var _form = NODE.getAncestorByAttributeRegExp(element, "method", new RegExp('^post'));
        var _formID = _form.id.split("-")[0];
        var _trace = {};

        if (_formID === "fBrowse") {
            _trace.name = "productList&view=";
            _trace.name += document.body.id.split("_")[1];
            _trace.name += "&filter=";
            var _breadCrumbContainer = document.getElementById("breadcrumbNav");
            if (_breadCrumbContainer) {
                var _breadcrumbs = _breadCrumbContainer.getElementsByTagName("li");
                for (var b = 0; b < _breadcrumbs.length; b++) {
                    if (_breadcrumbs[b].className.indexOf("hide") == -1) {
                        _trace.name += NODE.getTextValue(_breadcrumbs[b]) + "/";
                    }
                }
            }
        } else if (_form.id.split("-")[2] === "alt") {
            _trace.name = "productDetailsAlternative";
            _trace.name += "&originalProductID=";
            var _div = NODE.getDescendantsByAttributeRegExp(document.getElementById("header"), "div", "id", new RegExp('^p-'));
            var _baseProductID = _div[0].id.split("-")[1];
            _trace.name += _baseProductID;
        } else if (_formID === "fDetails") {
            _trace.name = "productDetails";
        } else if (_formID === "fComplementary") {
            _trace.name = "complementaryProduct";
            _trace.name += "&originalProductID=";
            var _div = NODE.getDescendantsByAttributeRegExp(document.getElementById("header"), "div", "id", new RegExp('^p-'));
            var _baseProductID = _div[0].id.split("-")[1];
            _trace.name += _baseProductID;
        } else if (_formID === "fFeaturedSpace") {
            _trace.name = "featuredSpace";
            _trace.name += "&featuredSpaceID=";
            _trace.name += _form.id.split("-")[2];
            _trace.name += "&candidateID=";
            _trace.name += _form.id.split("-")[3];
        }
        return _trace;
    }

    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 _getProductRowById(id) {
        //	TODO: this should be checked from the start of the <ul> for the product list, not [document.body] for better performance
        //	TODO: cache found nodes in a local class variable to repeat this hit
        var _node = NODE.getDescendantsByAttributeRegExp(document.body, "li", "id", new RegExp('^p-' + id + '-([0-9]{1,3})$'));
        return (_node) ? _node[0] : null;
    }

    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.UI.Dialogue.Ajax(new TESCO.sites.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;
        }
    }
    
    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;
        }
        this.update(product, node);
    }
    //#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);
					}
				);
			}
		);

        //	after body loaded cache existing product controls and initialise alt product flyout
        EVENT.document.addEventListener("load",
			function() {
			    var _forms = document.getElementsByTagName("form");
			    var _prods;
			    for (var i = 0, L = _forms.length; i < L; i++) {
			        _prods = NODE.getDescendantsByAttributeRegExp(_forms[i], "*", "id", new RegExp('^p-'));
			        if (!_prods) {
			            var _parentProd = NODE.getAncestorByAttributeRegExp(_forms[i], "id", new RegExp('^p-'));
			            if (_parentProd) _prods = [_parentProd];
			        }
			        if (_prods && _prods.length) {
			            for (var ii = 0, LL = _prods.length; ii < LL; ii++) {
			                if (!NODE.hasClassName(_prods[ii], "unavailable")) {
			                    _self.register(_prods[ii].getElementsByTagName("fieldset")[0]);
			                } 
//		                    var _product = NODE.getElementsByClassAndTagName(_prods[ii], "addToBasket", "fieldset")[0];
//		                    EVENT.attach(_product.getElementsByTagName('input')[0], "blur",
//				                function(e) {
//				                    _self.change(e);
//				                }  
//			                );
			            }
			        }
			    }
			}
		);
        //#endregion
        return this;
    }

    //	public instance
    //#region
 
    _constructor.prototype.NAME = "TESCO.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) {
            node = _getProductRowById(product.getId());
        }
        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) {
        var _control = this.getControl(e.target);
        var _product;
        if (_control && !(e.target.value == "")) {
            _product = PRODUCT.getProductById(_control.productId);
            if (_control.action === "qty")	{ // add quantity has been changed
                _product.setQuantity(e.target.value, TESCO.sites.Configuration.activeBasket.id, e.target);
            }
           this.setPendingProducts(_product);
        }
        return {
            "control": _control,
            "product": _product
        }
    }
    
    _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) {
        var _fs = TESCO.system.DOM.node.getElementsByClassAndTagName(container, "addToBasket", "fieldset");
		if (_fs) {
		    for (var i=0;i<_fs.length;i++) {
			    this.register(_fs[i]);
			}
		}
    }

    _constructor.prototype.register = function(target) {
       _self= this;
        var _control;
        if (_control = this.getControl(target)) {
            var _p;
            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
            }
             var _product = NODE.getElementsByClassAndTagName(_control.node, "addToBasket", "fieldset")[0];
		                    EVENT.attach(_product.getElementsByTagName('input')[0], "blur",
				                function(e) {
				                    _self.change(e);
				                }  
			                );
            
        }
        /*
        Commented to stop JS doing 'in basket' messages over the top of XSL, 
        leaving incase it's required for weight radio btns in groceries
        if (product = PRODUCT.getProductById(control.productId))
        _updateProduct(product, control.node);
        */
    }

    _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":
                    _product.updateBasketQuantity(PRODUCT.steps.add, TESCO.sites.Configuration.activeBasket, _getLocation(e.target));
                    e.prevent();
                    _validExitLink = true;
                    break;
                case "qtyInc":
                    _adjustAddQty(_product, 1, _control.node);
                    this.setPendingProducts(_product);
                    e.prevent();
                    break;
                case "qtyDec":
                    _adjustAddQty(_product, -1, _control.node);
                    this.setPendingProducts(_product);
                    e.prevent();
                    break;
                default:
                    _stopped = false;
                    if ((!e.prevented) && (e.target.tagName.toUpperCase() == "A") || (e.target.tagName.toUpperCase() == "IMG" && e.target.parentNode.tagName.toUpperCase() == "A")) _adjustPendingProducts(e);
            }
        } 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;
})();