/*
 * frontoffice-1.0.js
 *
 * Copyright 2009 bluecycle.com Ltd.
 */
var searchPanelEnhancer = new SearchPanelEnhancer();
var auctionsPreviewEnhancer = new AuctionsPreviewEnhancer();
var cometListener = new CometListener();
var cometUtils = new CometUtils();
var auctionDetailsEnhancer = new AuctionDetailsEnhancer();
var timerService = new TimerService();
var modalDialog = new ModalDialog();

var _systemCommandHandler = new _SystemCommandHandler();

var AUCTIONS_PER_PAGE = 10;
var CATEGORIES_PER_GROUP = 4;

function enhance() {
    searchPanelEnhancer.enhance();
    auctionsPreviewEnhancer.enhance();
}

function SearchPanelEnhancer() {
    this.isLogEnabled = true;

    this.enhance = function() {
        // skip search panel enhancement if comet is disabled
        var isCometEnabled = dojo.attr("cometConfig","content") == "true";
        if(!isCometEnabled) {
            return;
        }

        // when user clicks on 'Latest Auctions' menu items the search and filter options should be cleared.
        if (dojo.byId("category_selection") != null) { // true - only for search page
            dojo.connect(dojo.byId("latest-auction-link"), "onclick", function(e) {
                if (location.href.indexOf("bidwatch") == -1) { // ignore bidwatch page
                    e.preventDefault();
                    dojo.byId("quick_search").value = "";
                    var dropdown = dojo.byId("sort_dropdown");
                    var sortOption = dropdown.options[dropdown.selectedIndex].value;
                    var data = {command : 'refresh_auction_list', categories: "", sort: sortOption, quickSearch: ""};
                    cometUtils.sendCommand(data);
                }
            });
        }

        // enhance 'clear' button
        dojo.connect(dojo.byId("clear_button"), "onclick", function(e) {
            if (location.href.indexOf("bidwatch") == -1) { // ignore bidwatch page
                e.preventDefault();
                dojo.byId("quick_search").value = "";
                var dropdown = dojo.byId("sort_dropdown");
                var sortOption = dropdown.options[dropdown.selectedIndex].value;
                var data = {command : 'refresh_auction_list', categories: "", sort: sortOption, quickSearch: ""};
                cometUtils.sendCommand(data);

                dojo.addClass(dojo.byId("clear_button"), "disabled");
            }
        });

        // add behaviour to category checkboxes
        var categorySelectors = dojo.query("input[id^='_checkbox:']");
        dojo.forEach(categorySelectors, function(checkbox) {
            dojo.connect(checkbox, "onclick", function() {
                searchPanelEnhancer.handleCategorySelection();
                searchPanelEnhancer.unselectGroup(checkbox);
            });
        });

        // add behaviour to group checkboxes
        var groupSelectors = dojo.query("input[id^='group-checkbox-']");
        dojo.forEach(groupSelectors, function(checkbox) {
            var groupId = dojo.attr(checkbox, "id").replace("group-checkbox-", "");
            checkbox.checked = true;
            dojo.connect(checkbox, "onclick", function() {
                searchPanelEnhancer.selectGroupCategories(groupId);
            });
        });

        // add folding support
        var foldingLinks = dojo.query("a[id^='_fold:']");
        dojo.forEach(foldingLinks, function(link) {
            dojo.connect(link, "onclick", function(e) {
                e.preventDefault();

                var comAncestor = link.parentNode.parentNode.parentNode;
                var eleContainer = comAncestor.getElementsByTagName('div')[2];
                var extraOptions = eleContainer.getElementsByTagName('ul')[1];
                if (extraOptions) {
                    dojo.toggleClass(extraOptions, 'hide-container');
                    dojo.toggleClass(link, 'collapse');
                }

                if (dojo.hasClass(link, "collapse")) {
                	var text = dojo.attr(link, "innerHTML").replace("More", "Less");
                    dojo.attr(link, "innerHTML", text);
                } else {
                	var text = dojo.attr(link, "innerHTML").replace("Less", "More");
                    dojo.attr(link, "innerHTML", text);
                }
            });
        });

    };

    this.handleCategorySelection = function() {
        var checkboxes = dojo.query("input[id^='_checkbox:']");
        var selectedCategories = "";
        dojo.forEach(checkboxes, function(checkbox) {
            var id = dojo.attr(checkbox, "id").replace("_checkbox:", '');
            if (dojo.attr(checkbox, "checked")) {
                selectedCategories = selectedCategories + id + ';';
            }
        });
        var dropdown = dojo.byId("sort_dropdown");
        var index = dropdown.selectedIndex;
        var sortOption = dropdown.options[index].value;
        var quickSearch = dojo.byId("quick_search").value;

        var data = {command : 'refresh_auction_list', categories: selectedCategories, sort: sortOption, quickSearch: quickSearch};
        cometUtils.sendCommand(data);
    };

    this.unselectGroup = function(checkbox) {
        var name = dojo.attr(checkbox, "id");
        var groupCheckboxId = 'group-checkbox-' + name.substring(name.indexOf('#') + 1, name.indexOf('-'));
        if (!dojo.attr(checkbox, "checked")) {
            if (dojo.attr(groupCheckboxId, "checked")) {
                dojo.attr(groupCheckboxId, "checked", false);
            }
        }
    };

    this.selectGroupCategories = function(groupId) {
        var isGroupSelected = dojo.byId("group-checkbox-" + groupId).checked;
        var groupCheckboxes = dojo.query("input[id^='_checkbox:gid#" + groupId + "']");
        dojo.forEach(groupCheckboxes, function(checkbox) {
            checkbox.checked = isGroupSelected;
        });
        this.handleCategorySelection();
    };
}

function AuctionsPreviewEnhancer() {

    this.updaterId = null;
    this._waitingBidConfirmation = false;

	this._isWaitingBidConfirmation = function() {
		return this._waitingBidConfirmation;
	};

	this._setWaitingBidConfirmation = function(isWaiting) {
		this._waitingBidConfirmation = isWaiting;
	}; 

    this.enhance = function() {
        // update the closing time
        if (this.updaterId != null) {
            clearInterval(this.updaterId);
        }
        this.updaterId = setInterval("auctionsPreviewEnhancer.refreshRemainingTime()", 1000);
        
        // scroll page to last updated auction.
        if(dojo.byId('lua') && dojo.byId('lua').value != "") {
        	var panelId = 'preview_panel_' + dojo.byId('lua').value;
    		dojo.byId(panelId).scrollIntoView(true);       	
        }

        // skip auctions preview enhancement if comet is disabled
        var isCometEnabled = dojo.attr("cometConfig","content") == "true";
        if(!isCometEnabled) {
            return;
        }

        var bidwatchLinks = dojo.query("a[id^='bid_watch_link_']");
        dojo.forEach(bidwatchLinks, function(link) {
            dojo.attr(link, "href", "#null");
            //dojo.attr(link, "onclick", "return false");
            dojo.connect(link, "onclick", function(e) {
                e.preventDefault();
                auctionsPreviewEnhancer.addOrRemoveFromBidwatch(link);
            });
        });

        // show close icon for error message box
        var errorCloseIcons = dojo.query("a[id^='error_close_link_']");
        dojo.forEach(errorCloseIcons, function(link) {
            dojo.removeClass(link, "hide");
            dojo.connect(link, "onclick", function(e) {
                e.preventDefault();

                var auctionId = dojo.attr(link, "id").replace("error_close_link_", "");
                var parentBox = link.parentNode;
                /**
                 * When wicket is set to 'development' mode it inserts a 'wicket:panel' tag
                 * between 'error_panel' div and 'error_close_link' anchor so we have to
                 * make sure that 'error_close_link' will hide the right panel.
                 */
                while(dojo.attr(parentBox, "id") != "error_panel_" + auctionId) {
                	parentBox = parentBox.parentNode;
                }                
                dojo.style(parentBox, "display", "none");

                dojo.removeClass(dojo.byId("place_proxy_btn_" + auctionId).parentNode, "error");
                dojo.removeClass(dojo.byId("place_bid_btn_" + auctionId).parentNode, "error");
                dojo.removeClass("bid_panel_" + auctionId, "bid-error");
            });
        });

        // enhance 'place bid' button
        var placeBidButtons = dojo.query("input[id^='place_bid_btn_']");
        dojo.forEach(placeBidButtons, function(button) {

            dojo.connect(button, "onclick", function(e) {
                e.preventDefault();

                var auctionId = dojo.attr(button, "id").replace("place_bid_btn_", "");
                var bidAmount = dojo.byId("bid_value_" + auctionId).value;
                var errorKey = cometUtils.validateAmount(bidAmount, auctionId);
                if (errorKey) {
                    var message = dojo.i18n.getLocalization("bluecycle.auction", "bundle")[errorKey];
                    dojo.attr("error_message_" + auctionId, "innerHTML", message);
                    if (cometUtils.isBidwatchPage()) {
						dojo.style("error_message_" + auctionId, "width", "500px");
					}
                    dojo.addClass(button.parentNode, "error");                   
                    dojo.attr(dojo.byId("single_bid_label_" + auctionId), "bcindex:id", "D33P99R074_" + auctionId);                   
                    dojo.removeClass(dojo.byId("place_proxy_btn_" + auctionId).parentNode, "error");
                    dojo.addClass("bid_panel_" + auctionId, "bid-error");
                    dojo.style("error_panel_" + auctionId, "display", "block");
                } else {
                    dojo.style("error_panel_" + auctionId, "display", "none");
                    dojo.removeClass(button.parentNode, "error");
                    dojo.removeClass(dojo.byId("place_proxy_btn_" + auctionId).parentNode, "error");
                    dojo.removeClass("bid_panel_" + auctionId, "bid-error");
                    dojo.attr(dojo.byId("single_bid_label_" + auctionId), "bcindex:id", "D33P99R066_" + auctionId);                    
                    dojo.attr("conf_bid_msg_" + auctionId, "innerHTML", "Place a single bid of:");
                    dojo.attr("conf_bid_amount_" + auctionId, "innerHTML", dojo.currency.format(bidAmount, {currency: "GBP"}));
                    dojo.byId("conf_numeric_bid_amount_" + auctionId).value = bidAmount;
                    dojo.byId("bid_type_" + auctionId).value = "SINGLE_BID";

                    var confVatFiled = dojo.byId("conf_bid_inc_vat_" + auctionId);
                    var vatApplies = dojo.attr(dojo.byId("bid_inc_vat_" + auctionId), "innerHTML") != "";
                    if (vatApplies) {
                        var amountIncVat = parseFloat(bidAmount) + (parseFloat(bidAmount) * parseFloat(dojo.byId("vat_rate_"+auctionId).value) / 100.0);
                        dojo.attr(confVatFiled, "innerHTML", "($ inc VAT)".replace("$", dojo.currency.format(amountIncVat, {currency: "GBP"})));
                    } else {
                        dojo.attr(confVatFiled, "innerHTML", "&nbsp;");
                    }

                    cometUtils.disableControls();
                    dojo.style("bid_panel_" + auctionId, "display", "none");
                    dojo.style("confirm_panel_" + auctionId, "display", "block");
                    auctionsPreviewEnhancer._setWaitingBidConfirmation(true);
                }
            });
        });

        // enhance 'place proxy' button
        var placeProxyButtons = dojo.query("input[id^='place_proxy_btn_']");
        dojo.forEach(placeProxyButtons, function(button) {
            dojo.connect(button, "onclick", function(e) {
                e.preventDefault();

                var auctionId = dojo.attr(button, "id").replace("place_proxy_btn_", "");
                var proxyAmount = dojo.byId("proxy_value_" + auctionId).value;
                var errorKey = cometUtils.validateAmount(proxyAmount, auctionId);
                if (errorKey) {
                    var message = dojo.i18n.getLocalization("bluecycle.auction", "bundle")[errorKey];
                    dojo.attr("error_message_" + auctionId, "innerHTML", message);
                    if (cometUtils.isBidwatchPage()) {
						dojo.style("error_message_" + auctionId, "width", "500px");
					}
                    dojo.addClass(button.parentNode, "error");
                    dojo.removeClass(dojo.byId("place_bid_btn_" + auctionId).parentNode, "error");
                    dojo.attr(dojo.byId("proxy_label_" + auctionId), "bcindex:id", "D33P99R075_" + auctionId);  
                    dojo.addClass("bid_panel_" + auctionId, "bid-error");
                    dojo.style("error_panel_" + auctionId, "display", "block");
                } else {
                    dojo.style("error_panel_" + auctionId, "display", "none");
                    dojo.removeClass(button.parentNode, "error");
                    dojo.removeClass(dojo.byId("place_bid_btn_" + auctionId).parentNode, "error");
                    dojo.removeClass("bid_panel_" + auctionId, "bid-error");
                    dojo.attr(dojo.byId("proxy_label_" + auctionId), "bcindex:id", "D33P99R069_" + auctionId);  

                    dojo.attr("conf_bid_msg_" + auctionId, "innerHTML", "Place a proxy bid of:");
                    dojo.attr("conf_bid_amount_" + auctionId, "innerHTML", dojo.currency.format(proxyAmount, {currency: "GBP"}));
                    dojo.byId("conf_numeric_bid_amount_" + auctionId).value = proxyAmount;
                    dojo.byId("bid_type_" + auctionId).value = "PROXY_BID";

                    var confVatFiled = dojo.byId("conf_bid_inc_vat_" + auctionId);
                    var vatApplies = dojo.attr(dojo.byId("bid_inc_vat_" + auctionId), "innerHTML") != "";
                    if (vatApplies) {
                        var amountIncVat = parseFloat(proxyAmount) + (parseFloat(proxyAmount) * parseFloat(dojo.byId("vat_rate_"+auctionId).value) / 100.0);
                        dojo.attr(confVatFiled, "innerHTML", "($ inc VAT)".replace("$", dojo.currency.format(amountIncVat, {currency: "GBP"})));
                    } else {
                        dojo.attr(confVatFiled, "innerHTML", "&nbsp;");
                    }

                    dojo.style("bid_panel_" + auctionId, "display", "none");
                    cometUtils.disableControls();
                    dojo.style("confirm_panel_" + auctionId, "display", "block");
                    auctionsPreviewEnhancer._setWaitingBidConfirmation(true);
                }
            });
        });

        var confirmBidButtons = dojo.query("input[id^='conf_btn_']");
        dojo.forEach(confirmBidButtons, function(confirmButton) {
            dojo.connect(confirmButton, "onclick", function(e) {
                e.preventDefault();

                var auctionId = dojo.attr(confirmButton, "id").replace("conf_btn_", "");
                var bidType = dojo.byId("bid_type_" + auctionId).value;
                if (bidType == "SINGLE_BID") {
                    var bidData = { command : 'place_bid', bid_value : dojo.byId('conf_numeric_bid_amount_' + auctionId).value };
                    cometUtils.sendCommand(bidData, auctionId);
                } else if (bidType == "PROXY_BID") {
                    var proxyData = { command : 'place_proxy', proxy_value :dojo.byId('conf_numeric_bid_amount_' + auctionId).value };
                    cometUtils.sendCommand(proxyData, auctionId);
                }
                auctionsPreviewEnhancer.updateBidwatchLink(auctionId, "add");
                auctionsPreviewEnhancer._setWaitingBidConfirmation(false);
                cometUtils.enableControls();
                dojo.style("bid_panel_" + auctionId, "display", "block");
                dojo.style("confirm_panel_" + auctionId, "display", "none");
            });
        });

        var cancelBidButtons = dojo.query("input[id^='cancel_btn_']");
        dojo.forEach(cancelBidButtons, function(cancelButton) {
            dojo.connect(cancelButton, "onclick", function(e) {
                e.preventDefault();

                var auctionId = dojo.attr(cancelButton, "id").replace("cancel_btn_", "");
                auctionsPreviewEnhancer._setWaitingBidConfirmation(false);
                cometUtils.enableControls();
                dojo.style("bid_panel_" + auctionId, "display", "block");
                dojo.style("confirm_panel_" + auctionId, "display", "none");
            });
        });


        // enhance navigation links
        var goToFirst = dojo.byId("_go_to_first");
        dojo.attr(goToFirst, "href", "#null");
        dojo.connect(goToFirst, "onclick", function(e) {
            e.preventDefault();
            if (location.href.indexOf("bidwatch") != -1) { // bidwatch page
                auctionsPreviewEnhancer.handleBidwatchUpdate(goToFirst);
            } else {
                auctionsPreviewEnhancer.handleResultsNavigation(goToFirst);
            }
        });

        var goToPrevious = dojo.byId("_go_to_previous");
        dojo.attr(goToPrevious, "href", "#null");
        dojo.connect(goToPrevious, "onclick", function(e) {
            e.preventDefault();
            if (location.href.indexOf("bidwatch") != -1) { // bidwatch page
                auctionsPreviewEnhancer.handleBidwatchUpdate(goToPrevious);
            } else {
                auctionsPreviewEnhancer.handleResultsNavigation(goToPrevious);
            }
        });

        var goToNext = dojo.byId("_go_to_next");
        dojo.attr(goToNext, "href", "#null");
        dojo.connect(goToNext, "onclick", function(e) {
            e.preventDefault();
            if (location.href.indexOf("bidwatch") != -1) { // bidwatch page
                auctionsPreviewEnhancer.handleBidwatchUpdate(goToNext);
            } else {
                auctionsPreviewEnhancer.handleResultsNavigation(goToNext);
            }
        });

        var goToLast = dojo.byId("_go_to_last");
        dojo.attr(goToLast, "href", "#null");
        dojo.connect(goToLast, "onclick", function(e) {
            e.preventDefault();
            if (location.href.indexOf("bidwatch") != -1) { // bidwatch page
                auctionsPreviewEnhancer.handleBidwatchUpdate(goToLast);
            } else {
                auctionsPreviewEnhancer.handleResultsNavigation(goToLast);
            }
        });

        var goToButton = dojo.byId("_go_to");
        dojo.connect(goToButton, "onclick", function(e) {
            e.preventDefault();
            if (location.href.indexOf("bidwatch") != -1) { // bidwatch page
                auctionsPreviewEnhancer.handleBidwatchUpdate(goToButton);
            } else {
                auctionsPreviewEnhancer.handleResultsNavigation(goToButton);
            }
        });

        var sortDropdown = dojo.byId("sort_dropdown");
        dojo.connect(sortDropdown, "onchange", function(e) {
            e.preventDefault();
            if (location.href.indexOf("bidwatch") != -1) { // bidwatch page
                auctionsPreviewEnhancer.handleBidwatchUpdate();
            } else {
                auctionsPreviewEnhancer.handleResultsNavigation();
            }
        });

        var searchButton = dojo.byId("search_button");
        if (searchButton) {
            dojo.connect(searchButton, "onclick", function(e) {
                e.preventDefault();
                cometUtils.deselectSearchCategories();

                var quickSearch = "";
                if (dojo.byId("quick_search")) {
                    quickSearch = dojo.byId("quick_search").value;
                }
                // reset the sort option on quick searches
                if (cometUtils.trim(quickSearch) != "") {
                    var dropdown = dojo.byId("sort_dropdown");
                    for (var i = 0; i < dropdown.options.length; i++) {
                        if (dropdown.options[i].value == "closing-soonest") break;
                    }
                    dropdown.selectedIndex = i;
                }
                auctionsPreviewEnhancer.handleResultsNavigation();
            });
        }

        var postcodeConfirm = dojo.byId("postcode-confirm");
        if (postcodeConfirm) {
            dojo.connect(postcodeConfirm, "onclick", function(e) {
                e.preventDefault();

                var data = { command: 'update_postcode', postcode: dojo.byId("postocde").value };
                cometUtils.sendCommand(data);
            });
        }

        var postcodeCancel = dojo.byId("postcode-cancel");
        if (postcodeCancel) {
            dojo.connect(postcodeCancel, "onclick", function(e) {
                e.preventDefault();
                dijit.byId('dialog1').hide();
            });
        }

        var postcodeTxt = dojo.byId("postocde");
        if (postcodeTxt) {
			dojo.connect(postcodeTxt, "onkeypress", function(e) {
				if (e.keyCode == 13) {
					e.preventDefault();
					var data = {
						command : 'update_postcode',
						postcode : dojo.byId("postocde").value
					};
					cometUtils.sendCommand(data);
				}
			});
		}
        
        postcodeTxt.value = dojo.byId("user_postcode").value;

        var auctions = dojo.query("input[id^='auction_id_']");
        for (var i = 0; i < auctions.length; i++) {
            var auctionId = auctions[i].value;
            if (auctionId != "") {
                // console.info("SET TIMER --> INDEX(" + i + "), AUCTION_ID(" + auctionId + ")");
                timerService.setTimer(new ExtTimer(auctionId, i), i);
            }
        }

        /*
         * When using the 'go back' link the 'category_selection' value
         * contains the list of last selected categories, this list is
         * used to restore selected items from 'category filter' panel. 
         */
        var selection = dojo.byId("category_selection").value;        
        if (selection != "") {
        	cometUtils.selectFilterOptions(selection); 
        }
        
        var recoveryData = dojo.byId("filterSnapshot").value;
        var connRecovery = (recoveryData != "");        
        
        if(connRecovery) {
        	var data = dojo.fromJson(recoveryData);
        	var selectedCategories = data.filter;
        	var sort = data.sort;
        	var page = data.page;
        	var quickSearch = data.search;
        	
        	dojo.byId("sort_dropdown").value = sort;        	
        	dojo.byId("current_page").value = page;
        	dojo.byId("page_number").value = page;        	
			if (dojo.byId("quick_search")) {
				dojo.byId("quick_search").value = quickSearch;
			}
			
			if(cometUtils.isSearchPage()) {
				this.handleResultsNavigation(dojo.byId("_go_to"), selectedCategories);        	
			} else if(cometUtils.isBidwatchPage()) {
				this.handleBidwatchUpdate("_go_to");
			}
        }
        
        /*
		 * In case of connection recovery the auction subscription will be
		 * handled after restoring the search filter selections.
		 */
//        if (!connRecovery) {
//			/*
//			 * Unsubscribe from auctions that are no longer visible and
//			 * subscribe to recently selected auctions.
//			 */
//        	subscriptions.manageSubscriptions();
//		}
        
    };

    this.handleResultsNavigation = function(link, filterOptions) {
    	var selectedCategories = "";
    	
		/*
		 * If available use the provided filter options, otherwise extract the
		 * list of selected categories directly from filter panel.
		 */
		if (filterOptions != null) {
			selectedCategories = filterOptions;
		} else {
			var checkboxes = dojo.query("input[id^='_checkbox:']");
			dojo.forEach(checkboxes, function(checkbox) {
				var id = dojo.attr(checkbox, "id").replace("_checkbox:", '');
				if (dojo.attr(checkbox, "checked")) {
					selectedCategories = selectedCategories + id + ';';
				}
			});
		}

        var dropdown = dojo.byId("sort_dropdown");
        var index = dropdown.selectedIndex;
        var sortOption = dropdown.options[index].value;
        var quickSearch = "";
        if (dojo.byId("quick_search")) {
            quickSearch = dojo.byId("quick_search").value;
        }
        var navCommand = link != null ? dojo.attr(link, "name") : "";
        var currentPage = dojo.byId("current_page").value;
        var landingPage = dojo.byId("page_number").value;

        var data = {
            command : 'refresh_auction_list',
            categories: selectedCategories,
            sort: sortOption,
            quickSearch: quickSearch,
            navCommand: navCommand,
            currentPage: currentPage,
            landingPage: landingPage
        };
        cometUtils.sendCommand(data);    
    };

    this.handleBidwatchUpdate = function(link, removedAuctionId) {
        var dropdown = dojo.byId("sort_dropdown");
        var sortOption = dropdown.options[dropdown.selectedIndex].value;
        var navCommand = link != null ? dojo.attr(link, "name") : "";
        var currentPage = dojo.byId("current_page").value;
        var landingPage = dojo.byId("page_number").value;

        var data = {
            command : 'update_bidwatch',
            sort: sortOption,
            navCommand: navCommand,
            currentPage: currentPage,
            landingPage: landingPage,
            removedAuction : removedAuctionId
        };
        cometUtils.sendCommand(data);
    };

    this.refreshRemainingTime = function() {
        var remainingTimeNodes = dojo.query("span[id^='closing_in_']");
        var delayTime = parseInt(dojo.attr("auctionConfig", "content")) * 1000;;

        var serverTime = null;
        if (remainingTimeNodes.length > 0) {
            serverTime = auctionsPreviewEnhancer.getServerTime();
        }

        for (var index = 0; index < remainingTimeNodes.length; index++) {
            var remainingTimeSpan = remainingTimeNodes[index];
            var auctionId = dojo.attr(remainingTimeSpan, "id").replace("closing_in_", "");

            // the 'name' attribute contains the auction closing time in milliseconds
            var closeTimeStr = dojo.attr(remainingTimeSpan, "name");
            if (cometUtils.isNotBlank(closeTimeStr)) {
                var closeTime = parseInt(closeTimeStr);

                // if 'timediff' is negative this means auction should be closed.
                var timediff = closeTime - serverTime;
                var hasAuctionExpired = timediff < 0;
                var hasConfirmTimeExpired = timediff + delayTime <= 0;

                if (!hasAuctionExpired) {
                    var remainingTimeFmt1 = auctionsPreviewEnhancer.getRemainingTime(closeTime, serverTime);
                    dojo.attr(remainingTimeSpan, "innerHTML", "Closing in " + remainingTimeFmt1);
                    auctionsPreviewEnhancer.toggleAuctionControls(auctionId, true);
                } else {
                    var remainingTimeFmt2 = auctionsPreviewEnhancer.getRemainingTime(closeTime, closeTime);
                    dojo.attr(remainingTimeSpan, "innerHTML", "Closing in " + remainingTimeFmt2);
                    if (hasConfirmTimeExpired) {
                        dojo.attr(remainingTimeSpan, {name: "", innerHTML: "Auction Closed"});
                    }
                    auctionsPreviewEnhancer.toggleAuctionControls(auctionId, false);
                }

                // skip animations if comet is disabled
                if (!cometUtils.isCometEnabled()) continue;

                // start the animation when the auction closes in 20 seconds.
                if (timerService != null && timerService.getTimer(index) != null && !timerService.getTimer(index).isStarted) {
                    var remainingSeconds = Math.ceil((closeTime - serverTime) / 1000);
                    if (remainingSeconds <= 20) {
                        timerService.getTimer(index).startAt(remainingSeconds);
                    }
                }
            }
        }
    };

    this.getServerTime = function() {
        var DEBUG = false;
        var USE_TIMESYNCH = true;
        var refreshPeriod = 30;
        var serverTime = null;

        if (USE_TIMESYNCH && cometUtils.isCometEnabled()) {
            serverTime = dojox.cometd.timesync.getServerDate().getTime();
        } else {
            var timeNode = dojo.byId("server_time");
            var counterStr = dojo.attr(timeNode, "counter");
            if (cometUtils.isNotBlank(counterStr)) {
                var counter = parseInt(counterStr);
                if (counter < refreshPeriod) {
                    var serverTimeStr = dojo.attr(timeNode, "serverTime");
                    serverTime = parseInt(serverTimeStr) + 1000;
                    dojo.attr(timeNode, {counter: ++counter, serverTime: serverTime});
                    if (DEBUG) {
                        console.debug("CALCULATED SERVER TIME: " + serverTime + "; " + new Date(serverTime));
                        console.debug("UPDATED COUNTER: " + counter);
                    }
                } else {
                    serverTime = auctionsPreviewEnhancer.fetchServerTime();
                    dojo.attr(timeNode, {counter: 0, serverTime: serverTime});
                    if (DEBUG) {
                        console.debug("FETCHED SERVER TIME: " + serverTime + "; " + new Date(serverTime));
                    }
                }
            } else {
                serverTime = auctionsPreviewEnhancer.fetchServerTime();
                dojo.attr(timeNode, {counter: 0, serverTime: serverTime});
                if (DEBUG) {
                    console.debug("FETCHED SERVER TIME (INITIAL): " + serverTime + "; " + new Date(serverTime));
                }
            }
        }
        return serverTime;
    };

    this.fetchServerTime = function() {
        var xmlHttpReq;
        if (window.XMLHttpRequest) {
            xmlHttpReq = new XMLHttpRequest();
        } else {
            xmlHttpReq = new ActiveXObject("Microsoft.XMLHTTP");
        }
        try {
        	var url = "/timeservice";
            xmlHttpReq.open("GET", url, false);
            xmlHttpReq.send(null);
            return parseInt(xmlHttpReq.responseText);
        } catch (err) {
            console.error(err);
        }
    };
    
    this.toggleAuctionControls = function(auctionId, enableControls) {
        var isLoggedIn = !eval(dojo.byId("anonymous").value);
        // no controls are displayed for anonymous users
        if (!isLoggedIn) return;
        var disableControls = !enableControls;

        var areFieldsDisabled = dojo.hasAttr("bid_value_" + auctionId, "readonly")
                || dojo.hasAttr("proxy_value_" + auctionId, "readonly");
        var isWaitingBidConfirmation = auctionsPreviewEnhancer._isWaitingBidConfirmation();
        var isAuctionClosed = (dojo.attr("closing_in_" + auctionId, "name") === "");
        
        if (enableControls && areFieldsDisabled && !isWaitingBidConfirmation && !isAuctionClosed) {
            dojo.attr("bid_value_" + auctionId, "readonly", "");
            dojo.attr("proxy_value_" + auctionId, "readonly", "");
            dojo.byId("bid_value_" + auctionId).removeAttribute("readonly");
            dojo.byId("proxy_value_" + auctionId).removeAttribute("readonly");
            dojo.byId("place_bid_btn_" + auctionId).removeAttribute("disabled");
            dojo.byId("place_proxy_btn_" + auctionId).removeAttribute("disabled");

        } else if (disableControls && !areFieldsDisabled) {
            dojo.attr("bid_value_" + auctionId, "readonly", "readonly");
            dojo.attr("proxy_value_" + auctionId, "readonly", "readonly");
            dojo.attr("place_bid_btn_" + auctionId, "disabled", "disabled");
            dojo.attr("place_proxy_btn_" + auctionId, "disabled", "disabled");
        }    	
    };

    this.getFormattedRemainingTime = function(closeTime, serverTime) {
        var SEC = 1000;
        var MIN = 60 * SEC;
        var HOUR = 60 * MIN;

        var timediff = closeTime - serverTime;

        var hours = Math.floor(timediff / HOUR);
        timediff -= hours * HOUR;
        var mins = Math.floor(timediff / MIN);
        timediff -= mins * MIN;
        var secs = Math.floor(timediff / SEC);
        timediff -= secs * SEC;

        var hoursStr = dojo.number.format(hours, {pattern:"##"});
        var minsStr = dojo.number.format(mins, {pattern:"00"});
        var secsStr = dojo.number.format(secs, {pattern:"00"});

        return hoursStr + "/" + minsStr + "/" + secsStr;
    };

    this.getRemainingTime = function(closeTime, serverTime) {
        var SEC = 1000;
        var MIN = 60 * SEC;
        var HOUR = 60 * MIN;
        var DAY = 24 * HOUR;

        var amount = null;
        var remainingTime = null;
        var diff = Math.abs(closeTime - serverTime);

        if (diff <= MIN) {
            amount = Math.ceil(diff / SEC);
            remainingTime = amount + " ";
            if (amount != 1) {
                remainingTime += dojo.i18n.getLocalization("bluecycle.auction", "bundle")["SECONDS"];
            } else {
                remainingTime += dojo.i18n.getLocalization("bluecycle.auction", "bundle")["SECOND"];
            }
        } else if (diff >= MIN && diff <= (MIN * 2)) {
            amount = Math.ceil((diff - MIN) / SEC);
            remainingTime = dojo.i18n.getLocalization("bluecycle.auction", "bundle")["ONE_MINUTE_AND"];
            remainingTime = remainingTime + " " + amount + " ";
            if (amount != 1) {
            	remainingTime += dojo.i18n.getLocalization("bluecycle.auction", "bundle")["SECONDS"];
            } else {
            	remainingTime += dojo.i18n.getLocalization("bluecycle.auction", "bundle")["SECOND"];
            }
        } else if (diff <= HOUR) {
            amount = Math.ceil(diff / MIN);
            remainingTime = amount + " ";
            if (amount != 1) {
                remainingTime += dojo.i18n.getLocalization("bluecycle.auction", "bundle")["MINUTES"];
            } else {
                remainingTime += dojo.i18n.getLocalization("bluecycle.auction", "bundle")["MINUTE"];
            }
        } else if (diff <= DAY) {
            amount = Math.ceil(diff / HOUR);
            remainingTime = amount + " ";
            if (amount != 1) {
                remainingTime += dojo.i18n.getLocalization("bluecycle.auction", "bundle")["HOURS"];
            } else {
                remainingTime += dojo.i18n.getLocalization("bluecycle.auction", "bundle")["HOUR"];
            }
        } else {
            amount = Math.ceil(diff / DAY);
            remainingTime = amount + " ";
            if (amount != 1) {
                remainingTime += dojo.i18n.getLocalization("bluecycle.auction", "bundle")["DAYS"];
            } else {
                remainingTime += dojo.i18n.getLocalization("bluecycle.auction", "bundle")["DAY"];
            }
        }
        return remainingTime;
    };

    this.addOrRemoveFromBidwatch = function(link) {
        var name = dojo.attr(link, "name");
        var auctionId = dojo.attr(link, "id").replace("bid_watch_link_", "");
        if (name == "add") {
            dojo.attr(link, "name", "remove");
            dojo.attr(link, "innerHTML", "Remove from Bidwatch");
            var rmData = { command : 'add_to_bidwatch' };
            cometUtils.sendCommand(rmData, auctionId);
        } else if (name == "remove") {
            dojo.attr(link, "name", "add");
            dojo.attr(link, "innerHTML", "Add to Bidwatch");
            var addData = { command : 'remove_from_bidwatch' };
            cometUtils.sendCommand(addData, auctionId);
        }
        if (location.href.indexOf("bidwatch") != -1) {
            auctionsPreviewEnhancer.handleBidwatchUpdate(link, auctionId);
        }
    };

    this.updateBidwatchLink = function(auctionId, command) {
        var link = dojo.byId("bid_watch_link_" + auctionId);
        var name = null;
        if (arguments.length == 1) {
            name = dojo.attr(link, "name");
        } else if (arguments.length == 2) {
            name = command;
        }
        if (name == "add") {
            dojo.attr(link, "name", "remove");
            dojo.attr(link, "innerHTML", "Remove from Bidwatch");
        } else if (name == "remove") {
            dojo.attr(link, "name", "add");
            dojo.attr(link, "innerHTML", "Add to Bidwatch");
        }
    };

}

function CometUtils() {
	
	this.getPageAge = function() {
		var pageAge = -1;
		if (dojo.byId("page_age")) {
			pageAge = dojo.byId("page_age").value;
		}
		return pageAge;
	};

	this.sendCommand = function(data, auctionId) {
		data.age = cometUtils.getPageAge();
        if (arguments.length == 1) {
            dojox.cometd.publish("/service/cmd/#", data, { message_type : "sys_command" });
        } else if (arguments.length == 2) {
            dojox.cometd.publish("/service/cmd/" + auctionId, data, { message_type : "sys_command" });
        }
    };

    this.generateVehicleDescription = function(mainDiv, description, auctionId) {
        this.removeChildren(mainDiv);

        var titleDiv = dojo.create("div", null, mainDiv, 0);
        dojo.addClass(titleDiv, "mod-head");
        var descTitle = dojo.create("a", {href: "/car-salvage-auctions/" + auctionId,
            innerHTML: description.make + "&nbsp;" + description.model + " (" + description.year + ")"}, titleDiv, "first");
        dojo.attr(descTitle, "bcindex:id", "D33P99R036_" + auctionId);
        dojo.addClass(descTitle, "title");
        var descDiv = dojo.create("div", null, mainDiv, 1);
        dojo.addClass(descDiv, "mod-main");
        var descList = dojo.create("ul", null, descDiv, "first");
        dojo.addClass(descList, "list-block");
        var category = dojo.create("li", {innerHTML: "Category" + "&nbsp;" + description.category}, descList, 0);
        dojo.attr(category, "bcindex:id", "D33P99R037_" + auctionId);
        var location = dojo.create("li", {innerHTML: description.location}, descList, 1);
        dojo.attr(location, "bcindex:id", "D33P99R038_" + auctionId);
        var distance = dojo.create("li", {innerHTML: description.distance}, descList, 2);
        dojo.attr(distance, "bcindex:id", "D33P99R039_" + auctionId);
    };

    this.removeChildren = function(parent) {
        if (parent.hasChildNodes()) {
            while (parent.childNodes.length >= 1) {
                parent.removeChild(parent.firstChild);
            }
        }
    };

    this.replaceInputWithButton = function(submitInput) {
        var parent = submitInput.parentNode;
        parent.removeChild(submitInput);
        var input = dojo.create("input", {
            type: "button",
            id: dojo.attr(submitInput, "id"),
            // value: dojo.attr(submitInput, "v alue"),
            value: submitInput.value,
            name: dojo.attr(submitInput, "name")
        }, parent, "first");
        dojo.addClass(input, "submit");
        return input;
    };

    this.getCurrencySymbol = function(currencyCode) {
        if (currencyCode == 'GBP') {
            return '&pound;';
        } else if (currencyCode == 'EUR') {
            return '&euro;';
        } else if (currencyCode == 'USD') {
            return '&#36;';
        } else {
            return currencyCode;
        }
    };

    this.validateAmount = function(amount, auctionId) {
        var MILLION = 1000000;
        var isValid = amount.match("^[1-9]{1}[0-9]{0,6}$");
        if (!isValid) {
            return "NOT_AN_AMOUNT_OF_MONEY";
        } else {
            amount = parseInt(amount);
            var initialPrice = dojo.byId("starting_price_" + auctionId).value;
            if (amount < initialPrice) {
                return "MINIMUM_BID_NOT_MET";
            } else if (amount > MILLION) {
                return "TOO_HIGH_TO_BE_REGISTRED";
            }
        }
    };

    this.disableControls = function() {
        var placeBidButtons = dojo.query("input[id^='place_bid_btn_']");
        dojo.forEach(placeBidButtons, function(button) {
            dojo.attr(button, "disabled", "disabled");
        });
        var placeProxyButtons = dojo.query("input[id^='place_proxy_btn_']");
        dojo.forEach(placeProxyButtons, function(button) {
            dojo.attr(button, "disabled", "disabled");
        });
        var bidInput = dojo.query("input[id^='bid_value_']");
        dojo.forEach(bidInput, function(button) {
            dojo.attr(button, "readonly", "readonly");
        });
        var proxyInput = dojo.query("input[id^='proxy_value_']");
        dojo.forEach(proxyInput, function(button) {
            dojo.attr(button, "readonly", "readonly");
        });
    };

    this.enableControls = function() {
    	var remainingTimeNodes = dojo.query("span[id^='closing_in_']");
    	for (var index = 0; index < remainingTimeNodes.length; index++) {
    		var auctionId = dojo.attr(remainingTimeNodes[index], "id").replace("closing_in_", "");    		
    		var enableControls = true;
    		auctionsPreviewEnhancer.toggleAuctionControls(auctionId, enableControls);
    	}
    };

    this.deselectSearchCategories = function() {
        var checkboxes = dojo.query("input[id^='_checkbox:']");
        dojo.forEach(checkboxes, function(checkbox) {
            checkbox.checked = false;
        });
        checkboxes = dojo.query("input[id^='group-checkbox-']");
        dojo.forEach(checkboxes, function(checkbox) {
            checkbox.checked = false;
        });
    };

    this.updateClearButtonState = function() {
        var hasSearchTerms = false;
        var hasSelectedCategories = false;

        if (cometUtils.trim(dojo.byId("quick_search").value) != "") {
            hasSearchTerms = true;
        }

        var checkboxes = dojo.query("input[id^='_checkbox:']");
        dojo.forEach(checkboxes, function(checkbox) {
            if (dojo.attr(checkbox, "checked")) {
                hasSelectedCategories = true;
            }
        });

        var clearButton = dojo.byId("clear_button");
        if (hasSearchTerms || hasSelectedCategories) {
            dojo.removeClass(clearButton, "disabled");
            clearButton.removeAttribute("disabled");
        } else {
            dojo.addClass(clearButton, "disabled");
            clearButton.setAttribute("disabled", "disabled");
        }
    };
    
    this.selectFilterOptions = function(selection) {
		var categories = selection.split(";");
		for ( var t = 0; t < categories.length; t++) {
			if (categories[t] != "") {
				dojo.byId("_checkbox:" + categories[t]).checked = true;
			}
		}
		// check if all categories of a search group are selected
		// then select the checkbox for the search group.
		var groupCheckboxes = dojo.query("input[id^='group-checkbox-']");
		dojo.forEach(groupCheckboxes, function(checkbox) {
			var groupId = dojo.attr(checkbox, "id").replace("group-checkbox-",
					"");
			var categoryCheckboxes = dojo.query("input[id^='_checkbox:gid#"
					+ groupId + "']");
			var allSelected = true;
			dojo.forEach(categoryCheckboxes, function(input) {
				if (!input.checked)
					allSelected = false;
			});
			if (allSelected) {
				dojo.byId("group-checkbox-" + groupId).checked = true;
			}
		});
	};

    this.trim = function(s) {
        var l = 0;
        var r = s.length - 1;
        while (l < s.length && s[l] == ' ') {
            l++;
        }
        while (r > l && s[r] == ' ') {
            r -= 1;
        }
        return s.substring(l, r + 1);
    };
    
    this.isDetailsPage = function() {
    	return dojo.byId("latest_bids") != null;
    };
    
    this.isBidwatchPage = function() {
    	// check if the current page has a search filter
    	var node = dojo.query("input[id^='group-checkbox-']");
    	var hasSearchFilter = (node != null && node.length > 0);
    	
    	var searchPage = dojo.byId("category_selection") != null;
    	
    	/*
		 * The 'bidwatch' page has a 'category_selection' field (this
		 * distinguishes it from 'details page') but doesn't have a filter panel
		 * (this distinguishes it from search page)
		 */
    	var isBidwatchPage = searchPage && !hasSearchFilter; 
    	return isBidwatchPage;
    };
    
    this.isSearchPage = function() {
		// check if the current page has a search filter
		var node = dojo.query("input[id^='group-checkbox-']");
		var hasSearchFilter = (node != null && node.length > 0);

		var searchPage = dojo.byId("category_selection") != null;

		/*
		 * The 'search' page has a 'category_selection' field (this
		 * distinguishes it from 'details page') and a filter panel (this
		 * distinguishes it from 'bidwatch' page)
		 */
		var isSearchPage = searchPage && hasSearchFilter;
		return isSearchPage;
	};
	
	this.subscribeToServiceChannel = function() {
		return dojox.cometd.subscribe('/service/cmd', cometListener, 'handleSystemCommands');
	};
	
	this.isCometEnabled = function() {
		var isCometEnabled = dojo.attr("cometConfig", "content") == "true";
		return isCometEnabled;
	};
	
    this.isNotBlank = function(str) {
        return str != null && !(str === "");
    };	
    
}

function CometListener() {
	
	this.handleSystemCommands = function(message) {	
		var data = message.data;
		//console.log(dojo.toJson(message, true));
		var command = data.command;
				
		switch (command) {
			case "navigate":
				_systemCommandHandler._navigateToPage(data.location);
				break;
				
			case "reconnect":
				_systemCommandHandler._reconnectClient();
				break;
				
			case "disconnect":
				console.error("DISCONNECT");	
				_systemCommandHandler._disconnect();
				break;
				
			case "limit_connections":
				_systemCommandHandler._limitConnections(data.message);
				break;
				
			default:
				console.warn("Unknown system command: " + command);
		}
	};
	
    this.updateSearchResults = function(msg) {
        // console.log(dojo.toJson(msg, true));

    	// check if the current page has a search filter
    	var node = dojo.query("input[id^='group-checkbox-']");
    	var hasSearchFilter = (node != null && node.length > 0);    	
    	
        if (msg.data.searchFilter != null && hasSearchFilter) {
            this.updateSearchFilter(msg.data.searchFilter);
        }
        
        var clearButton = dojo.byId("clear_button");
        if(clearButton != null) {
        	cometUtils.updateClearButtonState();
        }

        // reset timers
        timerService.resetAll();

        // update current page
        var currentPage = msg.data.currentPage;
        dojo.byId("current_page").value = currentPage;
        dojo.byId("page_number").value = currentPage;
        var totalPages = msg.data.totalPages;
        dojo.attr("total_pages", "innerHTML", totalPages);

        // disable/enable navigation buttons
        dojo.removeClass("_go_to_first", "disable");
        dojo.removeClass("_go_to_previous", "disable");
        dojo.removeClass("_go_to_next", "disable");
        dojo.removeClass("_go_to_last", "disable");

        if (currentPage == 1) {
            dojo.addClass("_go_to_first", "disable");
            dojo.addClass("_go_to_previous", "disable");
        }
        if (currentPage == totalPages) {
            dojo.addClass("_go_to_next", "disable");
            dojo.addClass("_go_to_last", "disable");
        }

        var totalResults = msg.data.totalResults;
        if (dojo.byId("total_results")) {
            dojo.attr("total_results", "innerHTML", totalResults);
        }
        if (dojo.byId("watched_auctions")) {
            dojo.attr("watched_auctions", "innerHTML", totalResults);
        }

        var searchCriteriaText;
        if(totalResults == 1) {
        	searchCriteriaText = dojo.i18n.getLocalization("bluecycle.auction", "bundle")["SEARCH_CRITERIA_TEXT_SINGLE"];
        }else{
        	searchCriteriaText = dojo.i18n.getLocalization("bluecycle.auction", "bundle")["SEARCH_CRITERIA_TEXT"];
        }
    	if( dojo.byId("search_criteria_text") != null ) {
            dojo.attr("search_criteria_text", "innerHTML", searchCriteriaText);
    	}
        
        var searchCriteria = msg.data.searchCriteria;
        var searchDetails = dojo.fromJson(searchCriteria);

        var title = dojo.byId("title_id");
        if (location.href.indexOf("bidwatch") == -1) {
            if (searchDetails != null && searchDetails.length > 0) {
                if (title) dojo.attr(title, "innerHTML", "Search Results");
            } else {
                if (title) dojo.attr(title, "innerHTML", "Latest auctions");
            }
        }

        //update the search details container
        var detailsContainer = dojo.byId("details_container");
        if (detailsContainer) {
            var ul = detailsContainer.getElementsByTagName("ul")[0]; //get the "vehicles matching... " line
            var li = ul.getElementsByTagName("li")[0];
            cometUtils.removeChildren(ul); //remove the all text 
            dojo.place(li, ul, "first"); //add the "vehicles matching..." line back in
            var liTwo = dojo.create("li", null, ul, "last");
           
            var ulTwo = dojo.create("ul", null, liTwo, "first");
            dojo.attr(ulTwo, "style", "padding-top: 0px;");
            dojo.attr(ulTwo, "bcindex:id", "D33P99R034");
            

            dojo.forEach(searchDetails, function(item, index) {
                var list = dojo.create("li", null, ulTwo, "last");
                var span = dojo.create("span", {innerHTML: item}, list, "first");
                if (index + 1 < searchDetails.length) {
                    dojo.create("span", {innerHTML: "|"}, list, "last");
                }
            });
        }

        var isLoggedIn = !eval(dojo.byId("anonymous").value);
        var isCustomerService = eval(dojo.byId("customerService").value);
        var searchResults = msg.data.searchResults;

        var noResultsPanel = dojo.byId("no-results");
        var quickSearch = dojo.byId("quick_search") ? cometUtils.trim(dojo.byId("quick_search").value) : "";
        if (searchResults.length == 0 && quickSearch != "") {
            var noMatchMsg = dojo.i18n.getLocalization("bluecycle.auction", "bundle")["NO_MATCH"];
            dojo.attr(noResultsPanel.getElementsByTagName("span")[0], "innerHTML", noMatchMsg.replace("$1", dojo.byId("quick_search").value));
            dojo.style(dojo.byId("no-results"), "display", "block");
            
            //update the search details container if there are no results for the quick search
            if (detailsContainer) {
            	var ul = detailsContainer.getElementsByTagName("ul")[0];
	            var liTwo = ul.getElementsByTagName("li")[1];
	            var ulTwo = liTwo.getElementsByTagName("ul")[0];
	            cometUtils.removeChildren(ulTwo);
	            var list = dojo.create("li", null, ulTwo, "last");
	            dojo.create("span", {innerHTML: quickSearch}, list, "first");
            }
        } else if (searchResults.length == 0) {
            var noResultsMsg = dojo.i18n.getLocalization("bluecycle.auction", "bundle")["EMPTY_SEARCH_RESULTS"];
            if (location.href.indexOf("bidwatch") != -1) { // bidwatch page
                noResultsMsg = dojo.i18n.getLocalization("bluecycle.auction", "bundle")["EMPTY_BIDWATCH"];
            }
            dojo.attr(noResultsPanel.getElementsByTagName("span")[0], "innerHTML", noResultsMsg);
            dojo.style(dojo.byId("no-results"), "display", "block");
        } else {
            dojo.style(dojo.byId("no-results"), "display", "none");
        }

        var highestBidSpanList = dojo.query("dd[id^='highest_bid_']");
        var amountSpanList = dojo.query("dt[id^='amount_label_']");
        var vatFieldList = dojo.query("dd[id^='bid_inc_vat_']");
        var statusContainerList = dojo.query("dl[id^='status_container_']");
        var reservePriceList = dojo.query("span[id^='reserve_price_']");
        var bidwatchLinkList = dojo.query("a[id^='bid_watch_link_']");
        var biddingStatusSpanList = dojo.query("dd[id^='user_status_']");
        var statusLabelList = dojo.query("dt[id^='user_status_label']");
        var closeTimeSpanList = dojo.query("span[id^='close_time_']");
        var remainingTimeSpanList = dojo.query("span[id^='closing_in_']");
        var productImageList = dojo.query("img[id^='product_image_']");
        var detailsLinkList = dojo.query("a[id^='details_link_']");
        var descTBodyList = dojo.query("div[id^='desc_table_']");
        var bidPanelList = dojo.query("div[id^='bid_panel_']");
        var previewPanelList = dojo.query("div[id^='preview_panel_']");
        var auctionFieldList = dojo.query("input[id^='auction_id_']");
        var box0List = dojo.query("div[id^='box:0_']");
        var box1List = dojo.query("div[id^='box:1_']");
        var box2List = dojo.query("div[id^='box:2_']");
        var box3List = dojo.query("div[id^='box:3_']");
        var box4List = dojo.query("div[id^='box:4_']");
        var vatRateList = dojo.query("input[id^='vat_rate']");
        var confirmPanelList = dojo.query("div[id^='confirm_panel_']");
        var bidTypeFieldList = dojo.query("input[id^='bid_type_']");
        var confirmMessageList = dojo.query("dt[id^='conf_bid_msg_']");
        var confirmAmountList = dojo.query("dd[id^='conf_bid_amount_']");
        var confirmNumericAmountList = dojo.query("input[id^='conf_numeric_bid_amount_']");
        var bidIncVatList = dojo.query("dd[id^='conf_bid_inc_vat_']");
        var confirmBidBtnList = dojo.query("input[id^='conf_btn_']");
        var cancelBidButtonList = dojo.query("input[id^='cancel_btn_']");
        var errorPanelList = dojo.query("div[id^='error_panel_']");
        var errorMessageList = dojo.query("span[id^='error_message_']");
        var closeErrorLinkList = dojo.query("a[id^='error_close_link_']");        
        
        if (isLoggedIn && !isCustomerService) {
            var bidAmountInputList = dojo.query("input[id^='bid_value_']");
            var proxyValueList = dojo.query("input[id^='proxy_value_']");
            var singleBidLabelList = dojo.query("label[id^='single_bid_label_']");
            var proxyLabelList = dojo.query("label[id^='proxy_label_']");
        }
        if (isLoggedIn) {
            var placeBidBtnList = dojo.query("input[id^='place_bid_btn_']");
            var placeProxyBtnList = dojo.query("input[id^='place_proxy_btn_']");
            var startingPriceList = dojo.query("input[id^='starting_price_']");
            var incrementValueList = dojo.query("input[id^='increment_']");
        }
       
        for (var i = 0; i < searchResults.length; i++) {
            var result = searchResults[i];
            var auctionId = result.id;
            // console.log("RESULT AUCTION ID: " + auctionId);

            // update highest bids
            var highestBid = result.highestBid != null ? result.highestBid : result.startingPrice;
            var highestBidStr = dojo.currency.format(highestBid, {currency: "GBP"});
            var highestBidSpan = highestBidSpanList[i];
            dojo.attr(highestBidSpan, "innerHTML", highestBidStr);
            dojo.attr(highestBidSpan, "id", "highest_bid_" + auctionId);
            dojo.attr(highestBidSpan, "bcindex:id", "D33P99R061_" + auctionId);

            var highestBidLabel = result.highestBid != null ? "Highest Bid:" : "Starting Price:";
            var amountSpan = amountSpanList[i];
            dojo.attr(amountSpan, "innerHTML", highestBidLabel);
            dojo.attr(amountSpan, "id", "amount_label_" + auctionId);
            dojo.attr(amountSpan, "bcindex:id", "D33P99R060_" + auctionId);

            //If the vehicle is VAT qualifying then update the vatRate
            //hidden field.
            if (result.vatApplies) {
                var vatRate = vatRateList[i];
                dojo.attr(vatRate, "id", "vat_rate_" + auctionId);
                dojo.byId(vatRate).value = result.vatRate;
            }

            // update the bid amount including VAT (for 'vat applies' vehicles)
            var vatField = vatFieldList[i];
            dojo.attr(vatField, "id", "bid_inc_vat_" + auctionId);
            dojo.attr(vatField, "bcindex:id", "D05P01F083_" + auctionId);
            var vatApplies = result.vatApplies;
            if (vatApplies) {
                var vatCoef = parseFloat(dojo.byId("vat_rate_" + auctionId).value) / 100.0;
                var amountIncVat = highestBid + (highestBid * vatCoef);
                amountIncVat = dojo.currency.format(amountIncVat, {currency: "GBP"});
                dojo.attr(vatField, "innerHTML", "($ inc VAT)".replace("$", amountIncVat));
                dojo.style(vatField, "display", "block");
            } else {
                dojo.attr(vatField, "innerHTML", "");
                dojo.style(vatField, "display", "none");
            }

            if (isLoggedIn && !isCustomerService) {
                // update 'bid field' id and value
                var bidIncrement = result.bidIncrement;
                var nextBidAmount = parseFloat(highestBid);
                if (result.highestBid != null) {
                    nextBidAmount += parseFloat(bidIncrement);
                }
                var nextBidAmountStr = dojo.number.format(nextBidAmount, {pattern:"#.##"});
                var bidAmountInput = bidAmountInputList[i];
                dojo.byId(bidAmountInput).value = nextBidAmountStr;
                dojo.attr(bidAmountInput, "id", "bid_value_" + auctionId);
                dojo.attr(bidAmountInput, "bcindex:id", "D33P99R067_" + auctionId);
                /**
                 * AJW. Crazy workaround for IE to re-enable the bid input text box.
                 * Calling removeAttribute("readonly") doesn't seem to be enough!
                 * and IE needs to see the attribute value cleared.
                 */
                dojo.attr(bidAmountInput, "readonly", "");

                bidAmountInput.removeAttribute("readonly");

                // update 'proxy field' id
                var proxyValue = proxyValueList[i];
                dojo.attr(proxyValue, "id", "proxy_value_" + auctionId);
                dojo.attr(proxyValue, "bcindex:id", "D33P99R070_" + auctionId);
                /**
                 * AJW. Crazy workaround for IE to re-enable the bid input text box.
                 * Calling removeAttribute("readonly") doesn't seem to be enough!
                 * and IE needs to see the attribute value cleared.
                 */
                dojo.attr(proxyValue, "readonly", "");
                proxyValue.removeAttribute("readonly");

                // update 'single bid label' id
                var singleBidLabel = singleBidLabelList[i];
                dojo.attr(singleBidLabel, "id", "single_bid_label_" + auctionId);
                dojo.attr(singleBidLabel, "bcindex:id", "D33P99R066_" + auctionId);

                // update 'proxy bid label' id
                var proxyLabel = proxyLabelList[i];
                dojo.attr(proxyLabel, "id", "proxy_label_" + auctionId);
                dojo.attr(proxyLabel, "bcindex:id", "D33P99R069_" + auctionId);
            }

            // update status container id
            var statusContainer = statusContainerList[i];
            dojo.attr(statusContainer, "id", "status_container_" + auctionId);

            // update 'reserve price span' id
            var reservePrice = reservePriceList[i];
            dojo.attr(reservePrice, "id", "reserve_price_" + auctionId);
            dojo.attr(reservePrice, "bcindex:id", "D33P99R059_" + auctionId);

            // update 'add to bidwatch' link id
            var bidwatchLink = bidwatchLinkList[i];
            dojo.attr(bidwatchLink, "id", "bid_watch_link_" + auctionId);
            dojo.attr(bidwatchLink, "bcindex:id", "D33P99R040_" + auctionId);

            var isInBidwatch = eval(result.isInBidwatch);
            if (isInBidwatch) {
                dojo.attr(bidwatchLink, "innerHTML", "Remove from Bidwatch");
                dojo.attr(bidwatchLink, "name", "remove");
            } else {
                dojo.attr(bidwatchLink, "innerHTML", "Add to Bidwatch");
                dojo.attr(bidwatchLink, "name", "add");
            }

            var statusKey = result.biddingStatus;
            var status = dojo.i18n.getLocalization("bluecycle.auction", "bundle")[statusKey];
            var biddingStatusSpan = biddingStatusSpanList[i];
            dojo.attr(biddingStatusSpan, "innerHTML", status);
            dojo.attr(biddingStatusSpan, "id", "user_status_" + auctionId);
            dojo.attr(biddingStatusSpan, "bcindex:id", "D33P99R063_" + auctionId);

            var statusLabel = statusLabelList[i];
            dojo.attr(statusLabel, "bcindex:id", "D33P99R062_" + auctionId);


            var container = bidPanelList[i];
            if (statusKey == "NO_BID" || statusKey == "NO_BIDS") {
                dojo.removeClass(container, "bid-losing");
                dojo.removeClass(container, "bid-winning");
                dojo.addClass(container, "bid-nobids");
            } else if (statusKey == "WINNING") {
                dojo.removeClass(container, "bid-losing");
                dojo.removeClass(container, "bid-nobids");
                dojo.addClass(container, "bid-winning");
            } else if (statusKey == "LOSING") {
                dojo.removeClass(container, "bid-winning");
                dojo.removeClass(container, "bid-nobids");
                dojo.addClass(container, "bid-losing");
            }

            if (dojo.style(container, "display") === "none") {
                dojo.style(container, "display", "block");
            }

            var priceNotMet = "";
            var isReservePriceMet = eval(result.isReservePriceMet);
            if (!isReservePriceMet) {
                priceNotMet = "Reserve price has not been met";
            }
            dojo.attr(reservePriceList[i], "innerHTML", priceNotMet);

            var closeTime = new Date(result['closingTime']);
            var closingTimeStr = dojo.date.locale.format(closeTime, {datePattern:'dd MMMM', timePattern: 'hh:mm:ss aa'});
            var closeTimeSpan = closeTimeSpanList[i];
            dojo.attr(closeTimeSpan, "id", "close_time_" + auctionId);
            dojo.attr(closeTimeSpan, "bcindex:id", "D33P99R053_" + auctionId);
            dojo.attr(closeTimeSpan, "innerHTML", closingTimeStr);

            var serverTime = dojox.cometd.timesync.getServerDate();
            var remainingTimeStr = auctionsPreviewEnhancer.getRemainingTime(closeTime.getTime(), serverTime.getTime());
            var remainingTimeSpan = remainingTimeSpanList[i];
            dojo.attr(remainingTimeSpan, "id", "closing_in_" + auctionId);
            dojo.attr(remainingTimeSpan, "innerHTML", "Closing in " + remainingTimeStr);
            dojo.attr(remainingTimeSpan, "name", closeTime.getTime());
            dojo.attr(remainingTimeSpan, "bcindex:id", "D33P99R052_" + auctionId);

            var imageUrl = result.imageFilename;
            var productImage = productImageList[i];
            dojo.attr(productImage, "id", "product_image_" + auctionId);
            dojo.attr(productImage, "src", imageUrl);
            dojo.attr(productImage, "title", "Auction ID: " + auctionId);

            var detailsLink = detailsLinkList[i];
            dojo.attr(detailsLink, "id", "details_link_" + auctionId);
            dojo.attr(detailsLink, "bcindex:id", "D33P99R035_" + auctionId);
            dojo.attr(detailsLink, "title", "Auction ID:" + auctionId);
            dojo.attr(detailsLink, "href", "/car-salvage-auctions/" + auctionId);

            var description = result.description;
            var descTBody = descTBodyList[i];
            dojo.attr(descTBody, "id", "desc_table_" + auctionId);
            if (description.type == 'VEHICLE') {
                cometUtils.generateVehicleDescription(descTBody, description, auctionId);
            }

            /* update 'bid panel' id. This should be independent of user login status as this
             * break the push operation for search results / page navigations.
             */
            var bidPanel = bidPanelList[i];
            dojo.attr(bidPanel, "id", "bid_panel_" + auctionId);

            var previewPanel = previewPanelList[i];
            dojo.attr(previewPanel, "id", "preview_panel_" + auctionId);
            
            // update 'confirm panel' id
            var confirmPanel = confirmPanelList[i];
            dojo.attr(confirmPanel, "id", "confirm_panel_" + auctionId);

            // update 'bid type field' id
            var bidTypeField = bidTypeFieldList[i];
            dojo.attr(bidTypeField, "id", "bid_type_" + auctionId);

            // update 'confirm bid message' id
            var confirmMessage = confirmMessageList[i];
            dojo.attr(confirmMessage, "id", "conf_bid_msg_" + auctionId);

            // update 'confirm bid amount' id
            var confirmAmount = confirmAmountList[i];
            dojo.attr(confirmAmount, "id", "conf_bid_amount_" + auctionId);
                        
            // update 'confirm bid numeric amount' id
            var confirmNumericAmount = confirmNumericAmountList[i];
            dojo.attr(confirmNumericAmount, "id", "conf_numeric_bid_amount_" + auctionId);

            // update id for 'confim bid amount including VAT'
            var bidIncVat = bidIncVatList[i];
            dojo.attr(bidIncVat, "id", "conf_bid_inc_vat_" + auctionId);

            // update 'confirm bid button' id
            var confirmBidBtn = confirmBidBtnList[i];
            dojo.attr(confirmBidBtn, "id", "conf_btn_" + auctionId);

            // update 'cancel bid button' id
            var cancelBidButton = cancelBidButtonList[i];
            dojo.attr(cancelBidButton, "id", "cancel_btn_" + auctionId);

            // update 'error panel' id
            var errorPanel = errorPanelList[i];
            dojo.attr(errorPanel, "id", "error_panel_" + auctionId);
            dojo.attr(errorPanel, "bcindex:id", "D05P01F093_" + auctionId);

            // update 'error message' id
            var errorMessage = errorMessageList[i];
            dojo.attr(errorMessage, "id", "error_message_" + auctionId);
            dojo.attr(errorMessage, "bcindex:id", "D33P99R077_" + auctionId);

            // update close icon id from error message box
            var closeErrorLink = closeErrorLinkList[i];
            dojo.attr(closeErrorLink, "id", "error_close_link_" + auctionId);
            dojo.attr(closeErrorLink, "bcindex:id", "D33P99R078_" + auctionId);            

            if (isLoggedIn) {
                // update 'place bid button' id
                var placeBidBtn = placeBidBtnList[i];
                dojo.attr(placeBidBtn, "id", "place_bid_btn_" + auctionId);
                dojo.attr(placeBidBtn, "bcindex:id", "D33P99R068_" + auctionId);
                placeBidBtn.removeAttribute("disabled");

                // update 'place proxy button' id
                var placeProxyBtn = placeProxyBtnList[i];
                dojo.attr(placeProxyBtn, "id", "place_proxy_btn_" + auctionId);
                dojo.attr(placeProxyBtn, "bcindex:id", "D33P99R071_" + auctionId);
                placeProxyBtn.removeAttribute("disabled");

                // update the starting prices
                var startingPrice = startingPriceList[i];
                dojo.attr(startingPrice, "id", "starting_price_" + auctionId);
                dojo.byId(startingPrice).value = result.startingPrice;

                // update the auction increment
                var incrementValue = incrementValueList[i];
                dojo.attr(incrementValue, "id", "increment_" + auctionId);
                dojo.byId(incrementValue).value = result.bidIncrement;

                // remove validation error box and error styles
                dojo.removeClass(bidPanelList[i], "bid-error");
                dojo.removeClass(placeBidBtnList[i].parentNode, "error");
                dojo.removeClass(placeProxyBtnList[i].parentNode, "error");
                
                if (cometUtils.isSearchPage() || cometUtils.isBidwatchPage()) {
                    dojo.style(errorPanelList[i], "display", "none");
                } else if(cometUtils.isDetailsPage()) {
                    dojo.addClass(errorPanelList[i], "hide");
                }
            }
            
            // hide 'confirm panel' and 'error box'
            dojo.style(confirmPanel, "display", "none");
            auctionsPreviewEnhancer._setWaitingBidConfirmation(false);
            dojo.style(errorPanel, "display", "none");

            // update the id of 'auction id' hidden field
            var auctionField = auctionFieldList[i];
            dojo.attr(auctionField, "id", "auction_id_" + auctionId);
            dojo.byId(auctionField).value = auctionId;

            // update the auction animation boxes
            var box0 = box0List[i];
            dojo.attr(box0, "id", "box:0_" + auctionId);
            dojo.attr(box0, "bcindex:id", "D33P99R054_" + auctionId);
            var box1 = box1List[i];
            dojo.attr(box1, "id", "box:1_" + auctionId);
            dojo.attr(box1, "bcindex:id", "D33P99R055_" + auctionId);
            var box2 = box2List[i];
            dojo.attr(box2, "id", "box:2_" + auctionId);
            dojo.attr(box2, "bcindex:id", "D33P99R056_" + auctionId);
            var box3 = box3List[i];
            dojo.attr(box3, "id", "box:3_" + auctionId);
            dojo.attr(box3, "bcindex:id", "D33P99R057_" + auctionId);
            var box4 = box4List[i];
            dojo.attr(box4, "id", "box:4_" + auctionId);
            dojo.attr(box4, "bcindex:id", "D33P99R058_" + auctionId);

            var prevPanel = dojo.byId("auction_summary_" + i).getElementsByTagName('div')[0];
            if (i % 2 != 0) {
                dojo.removeClass(prevPanel, "odd");
                dojo.addClass(prevPanel, "even");
            }
            dojo.style(prevPanel, "display", "block");
        }

        var auctionIdFields = dojo.query("input[id^='auction_id_']");
        var closingInFileds = dojo.query("span[id^='closing_in_']");
        for (var j = searchResults.length; j < AUCTIONS_PER_PAGE; j++) {
            dojo.style(dojo.byId("auction_summary_" + j).getElementsByTagName('div')[0], "display", "none");
            dojo.byId(auctionIdFields[j]).value = "";
            dojo.attr(closingInFileds[j], "name", "");
        }

        var auctions = dojo.query("input[id^='auction_id_']");
        for (var k = 0; k < auctions.length; k++) {
            var aid = auctions[k].value;
            if (aid != "") {
                //console.info("SET TIMER --> INDEX(" + k + "), AUCTION_ID(" + aid + ")");
                timerService.setTimer(new ExtTimer(aid, k), k);
            }
        }
        
        connManager.manageAuctionConnections();
        
        /*
		 * After a forced client disconnection the input 'filterSnapshot'
		 * contains the selection status before connection break. The settings
		 * are represented as a JSON string; The property 'filter' contains the
		 * selected categories, which can be used to recover the filter state.
		 * The property 'search' contains the quick search string (if any).
		 */
		var snapshot = dojo.byId("filterSnapshot").value;

		if (snapshot != "") {
			var data = dojo.fromJson(snapshot);
			var quickSearch = data.search;
			/*
			 * No need to update the search filter panel if a quick 
			 * search string is available as this will be handled by
			 * 'updateSearchFilter' listener.
			 */
			if (quickSearch == "") {
				cometUtils.selectFilterOptions(data.filter);
			}

			// clear this input as it should be used only once.
			dojo.byId("filterSnapshot").value = "";
		}

    };

    this.updateSearchFilter = function(searchFilter) {
        // console.log(dojo.toJson(searchFilter, true));

        var searchGroups = searchFilter.searchGroups;
        for (var i = 0; i < searchGroups.length; i++) {
            var searchGroup = searchGroups[i];
            var groupId = searchGroup.id;
            var groupCheckbox = dojo.byId("group-checkbox-" + groupId);
            var groupLabel = groupCheckbox.parentNode.getElementsByTagName("label")[0];
            dojo.attr(groupLabel, "innerHTML", searchGroup.name + " (" + searchGroup.nrOfAuctions + ")");

            if (searchGroup.selectionStatus.status == "SELECTED") {
                dojo.attr(groupCheckbox, "checked", true);
                groupCheckbox.removeAttribute("disabled");
            } else if (searchGroup.selectionStatus.status == "UNSELECTED") {
                dojo.attr(groupCheckbox, "checked", false);
                groupCheckbox.removeAttribute("disabled");
            } else if (searchGroup.selectionStatus.status == "DISABLED") {
                dojo.attr(groupCheckbox, "checked", true);
                dojo.attr(groupCheckbox, "disabled", "disabled");
            }

            var categoryBox = dojo.byId("categ_box_" + groupId).getElementsByTagName("ul")[0];
            cometUtils.removeChildren(categoryBox);
            var extraCategoryBox = dojo.byId("categ_box_" + groupId).getElementsByTagName("ul")[1];
            cometUtils.removeChildren(extraCategoryBox);

            if (searchGroup.categories != null) {
                for (var j = 0; j < searchGroup.categories.length; j++) {
                    var searchCategory = searchGroup.categories[j];
                    var categoryId = searchCategory.id;
                    var container = dojo.create("li", null, j < CATEGORIES_PER_GROUP ? categoryBox : extraCategoryBox, j);
                    var categoryCheckbox = dojo.create("input", {id: "_checkbox:gid#" + groupId + "-cid#" + categoryId,
                        type: "checkbox", name: searchCategory.name}, container, "first");
                    dojo.addClass(categoryCheckbox, "checkbox");
                    dojo.connect(categoryCheckbox, "onclick", function(e) {
                        cometListener.handleSearchAndCategorySelection(e.target);
                    });
                    if (searchCategory.selectionStatus.status == "SELECTED") {
                        dojo.attr(categoryCheckbox, "checked", true);
                        categoryCheckbox.removeAttribute("disabled");
                    } else if (searchCategory.selectionStatus.status == "UNSELECTED") {
                        dojo.attr(categoryCheckbox, "checked", false);
                        categoryCheckbox.removeAttribute("disabled");
                    } else if (searchCategory.selectionStatus.status == "DISABLED") {
                        dojo.attr(categoryCheckbox, "checked", true);
                        dojo.attr(categoryCheckbox, "disabled", "disabled");
                    }
                    dojo.create("label", {innerHTML: searchCategory.name + " (" + searchCategory.nrOfAuctions + ")"}, container, "last");
                }
            }

        }
    };

    this.handleSearchAndCategorySelection = function(categoryCheckbox) {
        var checkboxes = dojo.query("input[id^='_checkbox:']");
        var selectedCategories = "";
        dojo.forEach(checkboxes, function(checkbox) {
            var id = dojo.attr(checkbox, "id").replace("_checkbox:", '');
            if (dojo.attr(checkbox, "checked")) {
                selectedCategories = selectedCategories + id + ';';
            }
        });
        var dropdown = dojo.byId("sort_dropdown");
        var sortOption = dropdown.options[dropdown.selectedIndex].value;
        var quickSearch = dojo.byId("quick_search").value;
        if (cometUtils.trim(quickSearch) != "") {
            dojo.byId("quick_search").value = quickSearch + " " + categoryCheckbox.name;
            quickSearch = dojo.byId("quick_search").value;
        }

        var data = {command : 'refresh_auction_list', categories: selectedCategories, sort: sortOption, quickSearch: quickSearch};
        cometUtils.sendCommand(data);
    };

    this.updateAuctionData = function(msg) {
        // console.log("BID UPDATE: " + dojo.toJson(msg, true));
        try {
            var messageType = msg.data.message_type;
            if (messageType == "public") {
                this.updatePublicAuctionData(msg);
            } else if (messageType == "private") {
                this.updatePrivateAuctionData(msg);
            } else if (messageType == "warn_message") {
                this.updateWarnMessage(msg);
            }
        } catch(err) {
            var message = dojo.toJson(msg, true);
            console.warn(err + ' ' + message);
            alert(err + ' ' + message);
        }
    };

    this.updatePublicAuctionData = function(msg) {
    	
    	//console.log("AUCTION UPDATE: " + dojo.toJson(msg, true));

        var auction = msg.data.auction;
        var auctionId = msg.data.auction_id;
        var isLoggedIn = !eval(dojo.byId("anonymous").value);

        // update close timer after extension
        if (auction.close_time > parseInt(dojo.attr("closing_in_" + auctionId, "name"))) {
            timerService.reset(auctionId);
            dojo.attr("closing_in_" + auctionId, "name", auction.close_time);
            var closingTimeStr = dojo.date.locale.format(new Date(auction.close_time), {datePattern:'dd MMMM', timePattern: 'hh:mm:ss aa'});
            dojo.attr("close_time_" + auctionId, "innerHTML", closingTimeStr);
        }

        if (auction.auction_status == "CANCELLED") {
			dojo.attr("bid_value_" + auctionId, "readonly", "readonly");
			dojo.attr("proxy_value_" + auctionId, "readonly", "readonly");
			dojo.attr("place_bid_btn_" + auctionId, "disabled", "disabled");
			dojo.attr("place_proxy_btn_" + auctionId, "disabled", "disabled");
			
            dojo.attr("closing_in_" + auctionId, {"name": new Date().getTime() - 60 * 1000, "innerHTML": "Auction Canceled"});
		}      
        
        
        var highestBid = auction.highest_bid;
        /**
         *  If there has been at least one bid, display
         * 'Highest Bid' rather than 'Starting Price'
         */
        if (highestBid != null) {
        	 var highestBidLabelText = dojo.i18n.getLocalization("bluecycle.auction", "bundle")["HIGHEST_BID"];
        	 dojo.attr("amount_label_" + auctionId, "innerHTML", highestBidLabelText);
        }
        
        // update highest bid 
        var highestBidStr = dojo.currency.format(highestBid, {currency: "GBP"});
        dojo.attr("highest_bid_" + auctionId, "innerHTML", highestBidStr);

        // update highest bid including VAT (if appliable)
        if (dojo.attr("bid_inc_vat_" + auctionId, "innerHTML") != "") {
            var vatCoef = parseFloat(dojo.byId("vat_rate_"+auctionId).value) / 100.0;
            var amountIncVat = highestBid + (highestBid * vatCoef);
            amountIncVat = dojo.currency.format(amountIncVat, {currency: "GBP"});
            dojo.attr("bid_inc_vat_" + auctionId, "innerHTML", "($ inc VAT)".replace("$", amountIncVat));
        }

        var isReservePriceMet = eval(auction.isReservePriceMet);
        if (!isReservePriceMet) {
            dojo.attr("reserve_price_" + auctionId, "innerHTML", "Reserve price has not been met");
        } else {
            dojo.attr("reserve_price_" + auctionId, "innerHTML", "");
        }

        if (dojo.byId("latest_bids")) {
            // console.log("UPDATE BIDS");
            var bids = auction.bids;
            for (var i = 0; i < bids.length; i++) {
                var bid = bids[i];
                dojo.attr("bid_amount_" + i, "innerHTML", dojo.currency.format(bid.amount, {currency: "GBP"}));
                dojo.attr("bid_note_" + i, "innerHTML", "");
                var bidDate = dojo.date.locale.format(new Date(bid.time_placed), {datePattern:"dd MMM,", timePattern: 'hh:mm:ss'});
                dojo.attr("bid_time_" + i, "innerHTML", bidDate + " GMT");
            }
        }
        if (isLoggedIn) { // update 'place bid text field' value
            var bidIncrement = auction.bid_increment;
            var nextBidAmount = parseFloat(highestBid) + parseFloat(bidIncrement);
            dojo.byId("bid_value_" + auctionId).value = dojo.number.format(nextBidAmount, {pattern:"#.##"});

            // clear any value from 'place proxy text field'
            dojo.byId("proxy_value_" + auctionId).value = "";
        }
    };


    this.updatePrivateAuctionData = function(msg) {
        var auctionId = msg.data.auction_id;
        var bids = msg.data.auction.bids;
        var POUND = cometUtils.getCurrencySymbol("GBP");

        if (dojo.byId("latest_bids")) {
            for (var i = 0; i < bids.length; i++) {
                var bid = bids[i];
                var isYours = eval(bid.isYours);
                if (isYours) {
                    dojo.addClass(dojo.byId("bid_amount_" + i).parentNode, "your-bid");
                } else {
                    dojo.removeClass(dojo.byId("bid_amount_" + i).parentNode, "your-bid");
                }

                if (i == 0) {
                    var cell = dojo.byId("bid_amount_" + i).parentNode;
                    dojo.removeClass(cell, "your-bid");
                    dojo.addClass(cell, "top-bid");
                    dojo.addClass(cell.parentNode.getElementsByTagName('td')[0], "top-bid");
                }

                var proxy = bid.proxy;
                if (isYours && proxy) {
                    var proxyBid = " (your proxy max " + POUND + proxy + ")";
                    dojo.attr("bid_note_" + i, "innerHTML", proxyBid);
                } else if (isYours) {
                    var singleBid = " (your single bid)";
                    dojo.attr("bid_note_" + i, "innerHTML", singleBid);
                }
            }
        }

        var status = msg.data.auction.user_status;
        
        if (status == "not_yet_bid") {
            dojo.attr("user_status_" + auctionId, "innerHTML", "No bid");
            dojo.removeClass("bid_panel_" + auctionId, "bid-losing");
            dojo.removeClass("bid_panel_" + auctionId, "bid-winning");
            dojo.addClass("bid_panel_" + auctionId, "bid-nobids");
        } else if (status == "winning") {
            dojo.attr("user_status_" + auctionId, "innerHTML", "Winning");
            dojo.removeClass("bid_panel_" + auctionId, "bid-nobids");
            dojo.removeClass("bid_panel_" + auctionId, "bid-losing");
            dojo.addClass("bid_panel_" + auctionId, "bid-winning");
        } else if (status == "losing") {
            dojo.attr("user_status_" + auctionId, "innerHTML", "Losing");
            dojo.removeClass("bid_panel_" + auctionId, "bid-winning");
            dojo.removeClass("bid_panel_" + auctionId, "bid-nobids");
            dojo.addClass("bid_panel_" + auctionId, "bid-losing");

            // if a user has been outbid since they placed their sequential bid the message
            // should disappear within 10 seconds of the user being outbid
            if (dojo.style("error_panel_" + auctionId, "display") != "none"
                    && dojo.attr("error_message_" + auctionId, "name") == "NOT_PERMITTED_TO_BID_AGAINST_YOURSELF") {
                // setInterval("auctionsPreviewEnhancer.refreshRemainingTime()", 1000);
            	dojo.attr(dojo.byId("single_bid_label_" + auctionId), "bcindex:id", "D33P99R074_" + auctionId);     
                setTimeout(function() {
                    if (dojo.byId("page_number") != null) { // search page
                        dojo.style("error_panel_" + auctionId, "display", "none");
                    } else { // details page
                        dojo.addClass("error_panel_" + auctionId, "hide");
                    }
                    
                    dojo.removeClass(dojo.byId("place_proxy_btn_" + auctionId).parentNode, "error");
                    dojo.removeClass(dojo.byId("place_bid_btn_" + auctionId).parentNode, "error");
                    dojo.removeClass("bid_panel_" + auctionId, "bid-error");
                }, 10000);
            }
        }
    };

    this.updateWarnMessage = function(msg) {
        var messageType = msg.data.message.type;
        if (messageType == "warning") {
            var auctionId = msg.data.auction_id;
            var recipient = msg.data.message.destination;
            var key = msg.data.message.text;
            var text = dojo.i18n.getLocalization("bluecycle.auction", "bundle")[key];
            if(typeof(text) == "undefined"){ 
            	text = key;
            }
            if (key == "BID_DOES_NOT_EXCEED_THE_INCREMENT") {
                text = text.replace("$1", cometUtils.getCurrencySymbol('GBP') + dojo.byId("increment_" + auctionId).value);
            }

            if (recipient == "bid_message_box") {
                dojo.attr(dojo.byId("single_bid_label_" + auctionId), "bcindex:id", "D33P99R074_" + auctionId);
                if (cometUtils.isSearchPage() || cometUtils.isBidwatchPage()) {
                    dojo.attr("error_message_" + auctionId, "innerHTML", text);
                    if (cometUtils.isBidwatchPage()) {
						dojo.style("error_message_" + auctionId, "width", "500px");
					}   
                    dojo.attr("error_message_" + auctionId, "name", key);
                    dojo.addClass("bid_panel_" + auctionId, "bid-error");
                    dojo.addClass(dojo.byId("place_bid_btn_" + auctionId).parentNode, "error");
                    dojo.removeClass(dojo.byId("place_proxy_btn_" + auctionId).parentNode, "error");
                    dojo.style("error_panel_" + auctionId, "display", "block");
                } else if(cometUtils.isDetailsPage()) {
                    dojo.attr("error_message_" + auctionId, "innerHTML", text);
                    dojo.attr("error_message_" + auctionId, "name", key);
                    dojo.style("error_message_" + auctionId, "float", "left");
                    dojo.addClass("bid_panel_" + auctionId, "bid-error");
                    dojo.addClass(dojo.byId("place_bid_btn_" + auctionId).parentNode, "error");
                    dojo.removeClass(dojo.byId("place_proxy_btn_" + auctionId).parentNode, "error");
                    dojo.removeClass("error_panel_" + auctionId, "hide");
                }
            } else if (recipient == "proxy_message_box") {
                dojo.attr(dojo.byId("proxy_label_" + auctionId), "bcindex:id", "D33P99R075_" + auctionId);
                if (cometUtils.isSearchPage() || cometUtils.isBidwatchPage()) {
                    dojo.attr("error_message_" + auctionId, "innerHTML", text);
                    dojo.attr("error_message_" + auctionId, "name", key);
                    dojo.addClass("bid_panel_" + auctionId, "bid-error");
                    dojo.addClass(dojo.byId("place_proxy_btn_" + auctionId).parentNode, "error");
                    dojo.removeClass(dojo.byId("place_bid_btn_" + auctionId).parentNode, "error");
                    dojo.style("error_panel_" + auctionId, "display", "block");
                } else if(cometUtils.isDetailsPage()) {
                    dojo.attr("error_message_" + auctionId, "innerHTML", text);
                    dojo.attr("error_message_" + auctionId, "name", key);
                    dojo.style("error_message_" + auctionId, "float", "left");
                    dojo.addClass("bid_panel_" + auctionId, "bid-error");
                    dojo.addClass(dojo.byId("place_proxy_btn_" + auctionId).parentNode, "error");
                    dojo.removeClass(dojo.byId("place_bid_btn_" + auctionId).parentNode, "error");
                    dojo.removeClass("error_panel_" + auctionId, "hide");
                }
            }
        } else if (messageType == 'error') {
            // redirect to error page
            location.href = location.href.substring(0, location.href.indexOf('/', 10)) + '/error';
        }
    };


    this.handleUpdateMessage = function(msg) {
        // console.log(dojo.toJson(msg, true));
        var messageType = msg.data.message_type;
        if (messageType == 'update_message') {
            var target = msg.data.target;
            if (target == "location_dialog") {
                var success = eval(msg.data.success);
                if (success) {
                    dijit.byId('dialog1').hide();
                    if (location.href.indexOf("bidwatch") != -1) { // bidwatch page
                        auctionsPreviewEnhancer.handleBidwatchUpdate();
                    } else {
                        auctionsPreviewEnhancer.handleResultsNavigation();
                    }

                    // update sort options list
                    var nfo = null; // nearest first option
                    var postcode = dojo.byId("postocde").value;
                    postcode = cometUtils.trim(postcode).replace(" ", "");
                    var partialPostcode = "";
                    var length = postcode.length;
                    if (length >= 2 && length <= 4) {
                        partialPostcode = postcode;
                    } else if (length >= 5 && length <= 7) {
                        partialPostcode = postcode.substring(0, length - 3);
                    }

                    var sortDropdown = dojo.byId("sort_dropdown");
                    for (var i = 0; i < sortDropdown.options.length; i++) {
                        var option = sortDropdown.options[i].value;
                        if (option == "nearest-first") {
                            nfo = option;
                            dojo.attr(sortDropdown.options[i], "innerHTML", "Closest First (To $1)".replace("$1", partialPostcode));
                            break;
                        }
                    }
                    if (nfo == null) {
                        dojo.create("option", {value: "nearest-first", innerHTML: "Closest First (To $1)".replace("$1", partialPostcode)}, sortDropdown, "last");
                    }
                } else {
                    dojo.removeClass("postcode_error", "hide");
                }
            }
        }
    };
}

function AuctionDetailsEnhancer() {

    this.updaterId = null;

    this.enhance = function() {
        // update the closing time
        if (this.updaterId != null) {
            clearInterval(this.updaterId);
        }
        this.updaterId = setInterval("auctionsPreviewEnhancer.refreshRemainingTime()", 1000);

        // No need to enhance this page if comet is disabled.
        var isCometEnabled = dojo.attr("cometConfig","content") == "true";
        if(!isCometEnabled) {
            return;
        }
        
        // enhance 'place bid' button
        var placeBidButtons = dojo.query("input[id^='place_bid_btn_']");
        dojo.forEach(placeBidButtons, function(button) {

            dojo.connect(button, "onclick", function(e) {
                e.preventDefault();

                var auctionId = dojo.attr(button, "id").replace("place_bid_btn_", "");
                var bidAmount = dojo.byId("bid_value_" + auctionId).value;
                var errorKey = cometUtils.validateAmount(bidAmount, auctionId);
                if (errorKey) {
                    var message = dojo.i18n.getLocalization("bluecycle.auction", "bundle")[errorKey];
                    dojo.attr("error_message_" + auctionId, "innerHTML", message);
                    dojo.addClass(button.parentNode, "error");
                    dojo.removeClass(dojo.byId("place_proxy_btn_" + auctionId).parentNode, "error");
                    dojo.addClass("bid_panel_" + auctionId, "bid-error");
                    dojo.removeClass("error_panel_" + auctionId, "hide");   
                } else {
                    dojo.removeClass(button.parentNode, "error");
                    dojo.removeClass(dojo.byId("place_proxy_btn_" + auctionId).parentNode, "error");
                    dojo.removeClass("bid_panel_" + auctionId, "bid-error");
                    dojo.addClass("error_panel_" + auctionId, "hide");   
                    dojo.attr("conf_bid_msg_" + auctionId, "innerHTML", "Place a single bid of:");
                    dojo.attr("conf_bid_amount_" + auctionId, "innerHTML", dojo.currency.format(bidAmount, {currency: "GBP"}));
                    dojo.byId("conf_numeric_bid_amount_" + auctionId).value = bidAmount;
                    dojo.byId("bid_type_" + auctionId).value = "SINGLE_BID";

                    var confVatFiled = dojo.byId("conf_bid_inc_vat_" + auctionId);
                    var vatApplies = dojo.attr(dojo.byId("bid_inc_vat_" + auctionId), "innerHTML") != "";
                    if (vatApplies) {
                        var amountIncVat = parseFloat(bidAmount) + (parseFloat(bidAmount) * parseFloat(dojo.byId("vat_rate_"+auctionId).value) / 100.0);
                        dojo.attr(confVatFiled, "innerHTML", "($ inc VAT)".replace("$", dojo.currency.format(amountIncVat, {currency: "GBP"})));
                    } else {
                        dojo.attr(confVatFiled, "innerHTML", "&nbsp;");
                    }

                    cometUtils.disableControls();
                    dojo.style("bid_panel_" + auctionId, "display", "none");
                    dojo.style("confirm_panel_" + auctionId, "display", "block");
                }
            });
        });

        // enhance 'place proxy' button
        var placeProxyButtons = dojo.query("input[id^='place_proxy_btn_']");
        dojo.forEach(placeProxyButtons, function(button) {
            dojo.connect(button, "onclick", function(e) {
                e.preventDefault();

                var auctionId = dojo.attr(button, "id").replace("place_proxy_btn_", "");
                var proxyAmount = dojo.byId("proxy_value_" + auctionId).value;
                var errorKey = cometUtils.validateAmount(proxyAmount, auctionId);
                if (errorKey) {
                    var message = dojo.i18n.getLocalization("bluecycle.auction", "bundle")[errorKey];
                    dojo.attr("error_message_" + auctionId, "innerHTML", message);
                    dojo.addClass(button.parentNode, "error");
                    dojo.removeClass(dojo.byId("place_bid_btn_" + auctionId).parentNode, "error");
                    dojo.addClass("bid_panel_" + auctionId, "bid-error");
                    dojo.removeClass("error_panel_" + auctionId, "hide");
                } else {
                    dojo.removeClass(button.parentNode, "error");
                    dojo.removeClass(dojo.byId("place_bid_btn_" + auctionId).parentNode, "error");
                    dojo.removeClass("bid_panel_" + auctionId, "bid-error");
                    dojo.addClass("error_panel_" + auctionId, "hide");

                    dojo.attr("conf_bid_msg_" + auctionId, "innerHTML", "Place a proxy bid of:");
                    dojo.attr("conf_bid_amount_" + auctionId, "innerHTML", dojo.currency.format(proxyAmount, {currency: "GBP"}));
                    dojo.byId("conf_numeric_bid_amount_" + auctionId).value = proxyAmount;
                    dojo.byId("bid_type_" + auctionId).value = "PROXY_BID";

                    var confVatFiled = dojo.byId("conf_bid_inc_vat_" + auctionId);
                    var vatApplies = dojo.attr(dojo.byId("bid_inc_vat_" + auctionId), "innerHTML") != "";
                    if (vatApplies) {
                        var amountIncVat = parseFloat(proxyAmount) + (parseFloat(proxyAmount) * parseFloat(dojo.byId("vat_rate_"+auctionId).value) / 100.0);
                        dojo.attr(confVatFiled, "innerHTML", "($ inc VAT)".replace("$", dojo.currency.format(amountIncVat, {currency: "GBP"})));
                    } else {
                        dojo.attr(confVatFiled, "innerHTML", "&nbsp;");
                    }

                    dojo.style("bid_panel_" + auctionId, "display", "none");
                    cometUtils.disableControls();
                    dojo.style("confirm_panel_" + auctionId, "display", "block");
                }
            });
        });

        var confirmBidButtons = dojo.query("input[id^='conf_btn_']");
        dojo.forEach(confirmBidButtons, function(confirmButton) {
            dojo.connect(confirmButton, "onclick", function(e) {
                e.preventDefault();

                var auctionId = dojo.attr(confirmButton, "id").replace("conf_btn_", "");
                var bidType = dojo.byId("bid_type_" + auctionId).value;
                if (bidType == "SINGLE_BID") {
                    var bidData = { command : 'place_bid', bid_value : dojo.byId('conf_numeric_bid_amount_' + auctionId).value };
                    cometUtils.sendCommand(bidData, auctionId);
                } else if (bidType == "PROXY_BID") {
                    var proxyData = { command : 'place_proxy', proxy_value : dojo.byId('conf_numeric_bid_amount_' + auctionId).value };
                    cometUtils.sendCommand(proxyData, auctionId);
                }
                auctionsPreviewEnhancer.updateBidwatchLink(auctionId, "add");
                cometUtils.enableControls();
                dojo.style("bid_panel_" + auctionId, "display", "block");
                dojo.style("confirm_panel_" + auctionId, "display", "none");
            });
        });

        var cancelBidButtons = dojo.query("input[id^='cancel_btn_']");
        dojo.forEach(cancelBidButtons, function(cancelButton) {
            dojo.connect(cancelButton, "onclick", function(e) {
                e.preventDefault();

                var auctionId = dojo.attr(cancelButton, "id").replace("cancel_btn_", "");
                cometUtils.enableControls();
                dojo.style("bid_panel_" + auctionId, "display", "block");
                dojo.style("confirm_panel_" + auctionId, "display", "none");
            });
        });

        var bidwatchLinks = dojo.query("a[id^='bid_watch_link_']");
        dojo.forEach(bidwatchLinks, function(link) {
            dojo.attr(link, "href", "#null");
            dojo.connect(link, "onclick", function(e) {
                e.preventDefault();
                auctionsPreviewEnhancer.addOrRemoveFromBidwatch(link);
            });
        });
        
        // show close icon for error message box
        var errorCloseIcons = dojo.query("a[id^='error_close_link_']");
        dojo.forEach(errorCloseIcons, function(link) {
            dojo.removeClass(link, "hide");
            dojo.connect(link, "onclick", function(e) {
                e.preventDefault();

                var auctionId = dojo.attr(link, "id").replace("error_close_link_", "");
                var parentBox = link.parentNode;
                /**
                 * When wicket is set to 'development' mode it inserts a 'wicket:panel' tag
                 * between 'error_panel' div and 'error_close_link' anchor so we have to
                 * make sure that 'error_close_link' will hide the right panel.
                 */
                while(dojo.attr(parentBox, "id") != "error_panel_" + auctionId) {
                	parentBox = parentBox.parentNode;
                }                
                //dojo.style(parentBox, "display", "none");
                dojo.addClass(parentBox, "hide");

                dojo.removeClass(dojo.byId("place_proxy_btn_" + auctionId).parentNode, "error");
                dojo.removeClass(dojo.byId("place_bid_btn_" + auctionId).parentNode, "error");
                dojo.removeClass("bid_panel_" + auctionId, "bid-error");
            });
        });        

        var auctions = dojo.query("input[id^='auction_id_']");
        for (var i = 0; i < auctions.length; i++) {
            var auctionId = auctions[i].value;
            if (auctionId != "") {
                // console.info("SET TIMER --> INDEX(" + i + "), AUCTION_ID(" + auctionId + ")");
                timerService.setTimer(new ExtTimer(auctionId, i), i);
            }
        }

        // subscribe auctions
        //subscriptions.manageSubscriptions();
    };

}

function ExtTimer(auctionId, position) {

    this.auctionId = auctionId;
    this.position = position;
    
    this.startTime = null;
    this.isStarted = false;
    this.pid = 0;
    this.numberOfArrows = 5;
    
    this._getIdleClass = function() {
		var CLASS_PREFIX = "idleIcon";
		return this.position % 2 == 0 ? CLASS_PREFIX + "White" : CLASS_PREFIX + "Blue";
	};

	this._getActiveClass = function() {
		var CLASS_PREFIX = "activeIcon";
		return this.position % 2 == 0 ? CLASS_PREFIX + "White" : CLASS_PREFIX + "Blue";
	};

	this._getWaitingClass = function() {
		var CLASS_PREFIX = "waitingIcon";
		return this.position % 2 == 0 ? CLASS_PREFIX + "White" : CLASS_PREFIX + "Blue";
	};

    /**
     * Starts the 'timer' animation at the position corresponding to the remaining time.
     *
     * @param seconds remaining seconds until auction close
     */
    this.startAt = function(seconds) {
        if (seconds > 20) throw "The remaining time should be less than 20 seconds";

        this.isStarted = true;
        for (var i = 0; i < this.numberOfArrows; i++) {
            var box = dojo.byId("box:" + i + "_" + this.auctionId);
            dojo.removeClass(box, this._getIdleClass());
            dojo.removeClass(box, this._getActiveClass());
            dojo.addClass(box, this._getWaitingClass());
            dojo.style(box, "opacity", "1");
        }

        var mark = 20 - seconds;
        for (var index = 0; index <= 4; index++) {
            for (var counter = 0; counter <= 3; counter++) {
                if (mark == 0) {
                    // change icons to status 'active'
                    for (i = 0; i <= index; i++) {
                        box = dojo.byId("box:" + i + "_" + this.auctionId);
                        dojo.removeClass(box, this._getIdleClass());
                        dojo.removeClass(box, this._getWaitingClass());
                        dojo.addClass(box, this._getActiveClass());
                    }
                    this.startTime = new Date().getTime();
                    this._activate(index, counter, ++this.pid);
                    return;
                } else {
                    mark--;
                }
            }
        }
    };

    /**
     * Stops the 'timer' animation.
     */
    this.stop = function() {
        this.pid = ++this.pid;
        this.isStarted = false;
        for (var i = 0; i < this.numberOfArrows; i++) {
            var box = dojo.byId("box:" + i + "_" + this.auctionId);
            dojo.addClass(box, this._getIdleClass());
            dojo.removeClass(box, this._getWaitingClass());
            dojo.removeClass(box, this._getActiveClass());
        }
    };

    /**
     * Initiates a flashing cycle.
     * This is an internal function and the clients should not use this function directly.
     *
     * @param index the index of the flashing icon
     * @param counter the index of the flashing cycle (starting with 0)
     * @param pid the process id
     */
    this._activate = function(index, counter, pid) {
        var box = "box:" + index + "_" + this.auctionId;
        var self = this;
        var k = 1.25;

        setTimeout(function() { // fade out
            if (self.pid != pid) return;
            dojo.addClass(box, self._getWaitingClass());
            dojo.removeClass(box, self._getActiveClass());
            setTimeout(function() { // fade in
                if (self.pid != pid) return;
                dojo.addClass(box, self._getActiveClass());
                dojo.removeClass(box, self._getWaitingClass());
                // reset counter after 4 flashes and increment icon index
                counter++;
                if (counter == 4) {
                    index ++;
                    counter = 0;
                }
                // activate the next icon after 4 flashes
                if (counter == 0) {
                    var next = dojo.byId("box:" + index + "_" + self.auctionId);
                    if (next) {
                        dojo.addClass(next, self._getActiveClass());
                        dojo.removeClass(next, self._getWaitingClass());
                    }
                }
                // stop the flashing sequence
                if (index > 4) {
                    return;
                }
                self._activate(index, counter, pid);
            }, 500 - k);
        }, 500 - k);
    };
}

function TimerService() {
    this.timerList = new Array(AUCTIONS_PER_PAGE);

    this.resetAll = function() {
        for (var i = 0; i < AUCTIONS_PER_PAGE; i++) {
            var timer = this.timerList[i];
            if (timer != null) {
                timer.stop();
                this.timerList[i] = null;
            }
        }
    };

    this.reset = function(auctionId) {
        for (var i = 0; i < AUCTIONS_PER_PAGE; i++) {
            var timer = this.timerList[i];
            if (timer.auctionId == auctionId) {
                timer.stop();
                break;
            }
        }
    };

    this.getTimer = function(index) {
        return this.timerList[index];
    };

    this.setTimer = function(timer, index) {
        this.timerList[index] = timer;
    };
}

function _SystemCommandHandler() {
	this._DEBUG = true;
	
	this._navigateToPage = function(pagePath) {	
		// disconnect the client
		dojox.cometd.disconnect();

		var currentPage = location.href.substring(0, location.href.indexOf('/', 10));
		var newPage = currentPage + "/" + pagePath;
		if(this._DEBUG) {
			console.debug("Redirecting to new page: " + newPage);
		}
		location.href = newPage;
	};
	
	this._disconnect = function() {
		// disconnect the client
		dojox.cometd.disconnect();

		dojo.require("dijit.form.Button");
		dojo.require("dijit.Dialog");

		var dialog = new dijit.Dialog( {
			title : "Programatic Dialog Creation",
			style : "width: 300px"
		});

		dialog.attr("content", "Hey, I wasn't there before !");
		dialog.show();

	};
	
	this._reconnectClient = function() {
		dojox.cometd.disconnect();
		
		if (cometUtils.isSearchPage() || cometUtils.isBidwatchPage()) {
			if(this._DEBUG) {
				console.debug("Disconnect client from Search/Bidwatch page.");
			}
			
			var checkboxes = dojo.query("input[id^='_checkbox:']");
			var selectedCategories = "";
			dojo.forEach(checkboxes, function(checkbox) {
				var id = dojo.attr(checkbox, "id").replace("_checkbox:", '');
				if (dojo.attr(checkbox, "checked")) {
					selectedCategories = selectedCategories + id + ';';
				}
			});

			var dropdown = dojo.byId("sort_dropdown");
			var index = dropdown.selectedIndex;
			var sortOption = dropdown.options[index].value;
			var landingPage = dojo.byId("page_number").value;
			var quickSearch = "";
			if (dojo.byId("quick_search")) {
				quickSearch = dojo.byId("quick_search").value;
			}

			var params = "{filter: '$1', sort: '$2', page: '$3', search: '$4'}"
					.replace("$1", selectedCategories)
					.replace("$2", sortOption).replace("$3", landingPage)
					.replace("$4", quickSearch);
			
			if(this._DEBUG) {
				console.debug("Page settings: " + params);
			}

			var form = dojo.create("form", {
				id : "redirectForm",
				action : location.href,
				method : "POST"
			}, "container", "last");
			dojo.create("input", {
				name : "filterSnapshot",
				type : "hidden",
				value : params
			}, form, 0);
			dojo.byId("redirectForm").submit();

		} else if (cometUtils.isDetailsPage()) {
			if(this._DEBUG) {
				console.debug("Disconnect client from Details page.");
			}			
			
			// refresh current page to re-initialize the connection and subscribers.
			location.href = location.href;
		} else {
			console.warn("UNKNOWN PAGE. CAN'T DISCONNECT CLIENT.");
		}
	};
	
	this._limitConnections = function(message) {
		dojox.cometd.disconnect();
		modalDialog.showModalDialog(message);
	};
}

function ModalDialog() {
	/*
	 * Extended version of the dojo Dialog widget with the option to disable
	 * the close button and suppress the escape key.
	 */
	dojo.declare("com.bluecycle.ModalDialog", [dijit.Dialog], {
	    disableCloseButton: true,

	    postCreate: function() {
	        this.inherited(arguments);
	        this._updateCloseButtonState();
	    },

	    _onKey: function(evt) {
	        if (this.disableCloseButton && evt.charOrCode == dojo.keys.ESCAPE) return;
	        this.inherited(arguments);
	    },

	    setCloseButtonDisabled: function(flag) {
	        this.disableCloseButton = flag;
	        this._updateCloseButtonState();
	    },

	    _updateCloseButtonState: function() {
	        dojo.style(this.closeButtonNode, "display", this.disableCloseButton ? "none" : "block");
	    }
	}); 
	
	this._modalDialog = null;
	
    this.prepareModalDialog = function() {
    	this._modalDialog = new com.bluecycle.ModalDialog( {
			title : "Warning",
			style : "width: 300px; color: #002F64; font: normal 14px Arial, sans-serif;"
		});   
    };
    
    this.showModalDialog = function(content) {
    	this._modalDialog.attr("content", content);
        this._modalDialog.show();
    };
}