﻿/**
* @author lucas.gunn
*/
(function(w) {
    var w = window;
    var d = document;
    var get = function(inId) {
        return d.getElementById(inId);
    };

    var r = {
        init: function(inId) {
            this.ele = {};
            this.ele.dom = get(inId);
            this.ele.results_table = get('float_shim');
            this.ele.width = this.ele.dom.offsetWidth;
            this.ele.height = this.ele.dom.offsetHeight;
            this.ele.orig_pos = this.findpagepos(this.ele.dom);
            this.w = document.documentElement.offsetWidth;

            var thiz = this;

            attachEvent(w, 'scroll', function(e) {
                return thiz.watchscroll(e, thiz);
            });

            attachEvent(w, 'resize', function(e) {
                return thiz.watchresize(e, thiz);
            });
        },

        watchscroll: function(e, thiz) {
            e = e || window.event;
            var scroll_pos = 0;
            if (document.documentElement.scrollTop) {
                scroll_pos = document.documentElement.scrollTop;
            }
            else if (document.body.scrollTop) {
                scroll_pos = document.body.scrollTop;
            }

            var ele = thiz.ele;
            var tools = thiz.ele.dom;
            var table = thiz.ele.results_table;
            if (scroll_pos > thiz.ele.orig_pos[1]) {
                if (tools.className != 'floating') {
                    thiz.setstyle(tools, { 'position': 'fixed', 'top': '0', 'width': table.offsetWidth + 'px', 'zIndex': '999999' });
                    thiz.setstyle(table, { 'marginTop': ele.height + 'px' });
                    tools.className = 'floating';
                }
            } else {
                if (tools.className == 'floating') {
                    thiz.setstyle(tools, { 'position': 'static', 'top': '', 'width': 'auto', 'zIndex': '0' });
                    thiz.setstyle(table, { 'marginTop': '0' });
                    tools.className = '';
                }
            }
        },

        watchresize: function(e, thiz) {

            if (this.w != document.documentElement.offsetWidth) {

                this.w = document.documentElement.offsetWidth;

                var ele = thiz.ele;
                if (ele.dom.className == 'floating') {
                    thiz.setstyle(ele.dom, { 'width': ele.results_table.offsetWidth + 'px' });
                }
                ele.width = ele.results_table.offsetWidth;
            }
        },

        findpagepos: function(ele) {
            var curleft = curtop = 0;
            if (ele.parentNode) {
                do {
                    if (ele.tagName != 'TD' && ele.tagName != 'TH' && ele.tagName != 'THEAD' && ele.tagName != 'TBODY') {
                        if (!isNaN(ele.offsetLeft))
                            curleft += ele.offsetLeft;
                        if (!isNaN(ele.offsetTop))
                            curtop += ele.offsetTop;
                    }
                } while (ele = ele.parentNode);
                return [curleft, curtop];
            }

        },

        setstyle: function(ele, object) {
            for (key in object) {
                var val = object[key];
                ele.style[key] = val;
            }
        }
    };

    // Our global obj
    function attachEvent(el, event, func) {
        if (el.addEventListener)
            el.addEventListener(event, func, true);
        else if (el.attachEvent)
            el.attachEvent('on' + event, func);
        else
            eval('el.on' + event + ' = ' + func);
    }

    attachEvent(w, 'load', function(e) {
        if (document.getElementById('chaser_container').className != 'static')
            r.init('chaser_container');
    });

    function debug(object, verbose) {
        verbose = verbose || false;
        if (typeof w.console !== 'undefined' && typeof w.console.firebug !== 'undefined') {
            if (verbose) {
                console.dir(object);
            } else {
                console.info(object);
            }
        } else {
            alert(object);
        }

    };

})();

/**
* @author michael.savage
*/
var grid = function(frmGrid, divFlasher, divResults, txtOperatorName, ddlSortBy, imgdirection) {

    var arrivalDate = new Date();
    var numberOfNights = 0;
    var showStarRating = true;
    var operators = new Array();
    var showShortList = false;

    var wWidth = document.documentElement.offsetWidth;
    var wHeight = document.documentElement.offsetHeight;

    var init = function() {
        utilities.addEvent(frmGrid, 'submit', function() { grid.load('', true); flasher.setDefaults(); flasher.stop(); return true; });
        utilities.addEvent(txtOperatorName, 'keyup', function() { txtOperatorName.className = txtOperatorName.value == '' ? '' : 'noBG'; utilities.runInBG('filter', function() { renderer.render(sorter.sort(filterer.filter(operators, txtOperatorName.value))) }, 700); });
        utilities.addEvent(txtOperatorName, 'focus', function() { txtOperatorName.className = 'noBG'; });
        utilities.addEvent(txtOperatorName, 'blur', function() { txtOperatorName.className = txtOperatorName.value == '' ? '' : 'noBG'; });
        utilities.addEvent(ddlSortBy, 'change', function() { sorter.setField(ddlSortBy.value); renderer.render(sorter.sort(filterer.filter(operators, txtOperatorName.value))); });
        utilities.addEvent(document.getElementById('date_input'), 'click', function() { displayDatePicker('date_input'); });
        utilities.addEvent(imgdirection, 'click', function() { sorter.reverse(); renderer.render(sorter.sort(filterer.filter(operators, txtOperatorName.value))); });
        utilities.addEvent(document.getElementById('aShortList'), 'click', function() { showShortList = !showShortList; document.getElementById('aShortList').src = 'http://www.bookeasy.com.au/images/short_list_' + (showShortList ? 'on' : 'off') + '.gif'; renderer.render(sorter.sort(filterer.filter(operators, txtOperatorName.value))); });
        utilities.addEvent(window, 'resize', function() { if (wWidth != document.documentElement.offsetWidth) { wWidth = document.documentElement.offsetWidth; renderer.showDates(); renderer.hideDates(); }; });

        sorter.setField(ddlSortBy.value);
    }

    var loader = function() {

        var loadUrl = function(url, removeMissingOperators) {

            if (!url || url == '')
                document.getElementById('thSearch').className = 'search loading';

            var id = 'if' + Math.random();

            var ifGridLoader;
            {
                try {
                    ifGridLoader = document.createElement('<iframe name="' + id + '">');
                } catch (ex) {
                    ifGridLoader = document.createElement('iframe');
                }

                ifGridLoader.id = id;
                ifGridLoader.name = id;
                ifGridLoader.src = 'about:blank';
                ifGridLoader.style.display = 'none';

                document.body.appendChild(ifGridLoader);

                utilities.addEvent(ifGridLoader, 'load', function() { ifGridLoader_OnLoadCallback(ifGridLoader, window.frames[ifGridLoader.name], removeMissingOperators); });
            }

            if (url != '')
                window.frames[ifGridLoader.name].location = url;
            else {
                if (document.getElementById(frmGrid.id).target != '_self')
                    document.getElementById(frmGrid.id).target = ifGridLoader.name;
            }
        }

        var ifGridLoader_OnLoadCallback = function(el, w, removeMissingOperators) {

            if (w.location == 'about:blank')
                return;

            try {
                var results = w.getResults();

                arrivalDate = results.arrivalDate;
                numberOfNights = results.numberOfNights;
                showStarRating = results.showStarRating;

                // loop through all operators returned in the search and merge them with existing operator information
                for (var operatorIndex in results.operators) {
                    var operator = results.operators[operatorIndex];
                    var isOperatorFound = false;
                    for (var existingOperatorIndex in operators) {
                        if (operators[existingOperatorIndex].id == operator.id) {

                            if (!removeMissingOperators) {
                                operator.isExpanded = true;
                                operator.sortOrder = operators[existingOperatorIndex].sortOrder;
                            }
                            else
                                operator.isExpanded = operators[existingOperatorIndex].isExpanded;

                            for (var roomIndex in operator.rooms) {
                                for (var existingRoomIndex in operators[existingOperatorIndex].rooms) {
                                    if (operators[existingOperatorIndex].rooms[existingRoomIndex].id == operator.rooms[roomIndex].id) {
                                        operator.rooms[roomIndex].isShortListed = operators[existingOperatorIndex].rooms[existingRoomIndex].isShortListed;
                                        break;
                                    }
                                }
                            }

                            operators[existingOperatorIndex] = operator;

                            isOperatorFound = true;
                            break;
                        }
                    }

                    if (!isOperatorFound)
                        operators.push(operator);
                }

                // loop through existing operators and remove any that weren't returned in the search results
                if (removeMissingOperators) {
                    var existingOperators = operators;
                    operators = new Array();

                    for (var existingOperatorIndex = 0; existingOperatorIndex < existingOperators.length; existingOperatorIndex++) {
                        var isOperatorFound = false;
                        for (var operatorIndex in results.operators) {
                            if (existingOperators[existingOperatorIndex].id == results.operators[operatorIndex].id) {
                                isOperatorFound = true;
                                break;
                            }
                        }
                        if (isOperatorFound)
                            operators.push(existingOperators[existingOperatorIndex]);
                    }
                }
            }
            catch (ex) {
                alert('There was an error processing your request.\nPlease check your search criteria and try again');
            }
            finally {
                document.body.removeChild(el);
            }

            renderer.render(sorter.sort(filterer.filter(operators, txtOperatorName.value)));

            document.getElementById('thSearch').className = 'search';
        }

        return {
            loadUrl: loadUrl
        }
    } ();

    var renderer = function() {

        var searchResults = document.getElementById('search_results');
        var searchResultsTRIndex = 0;

        var expandDescription = function(operatorID, roomID) {
            var searchResultsTR = document.getElementById('searchResultsTR_' + operatorID + '_' + roomID);

            if (searchResultsTR) {
                var descriptions = utilities.getElementsByClassName(searchResultsTR, 'description');
                if (descriptions.length > 0) {
                    var description = descriptions[0];
                    for (var operatorIndex in operators) {
                        var operator = operators[operatorIndex];
                        if (operator.id == operatorID) {
                            for (var roomIndex in operator.rooms) {
                                var room = operator.rooms[roomIndex];
                                if (room.id == roomID) {
                                    description.onclick = function() { grid.contractDescription(operatorID, roomID); };
                                    description.title = '';
                                    description.innerHTML =
                                        '<p>' + room.description + '</p>' +
                                        '<p>' +
                                        '    <b>Room Configuration</b>: ' + room.type + '<br />' +
                                        '    <b>Max # of Persons</b>: ' + room.maxNumberOfPersons + '<br />' +
                                        '</p>';

                                    if (room.facilities != '') {
                                        description.innerHTML +=
                                            '<p>' +
                                            '    <b>Facilities</b>:<br />' + room.facilities +
                                            '</p>';
                                    }

                                    description.innerHTML += '<div style="position: relative; float: right; clear: both; background-color: #fff"><a style="font-weight: normal">&laquo; less info</a></div>';

                                    // this will ensure all links provided in the room description content get opened in a new window
                                    var aTags = description.getElementsByTagName('a');

                                    for (var aTagIndex = 0; aTagIndex < aTags.length; aTagIndex++)
                                        aTags[aTagIndex].target = '_blank';
                                }
                            }
                        }
                    }
                }
            }
        }

        var contractDescription = function(operatorID, roomID) {
            var searchResultsTR = document.getElementById('searchResultsTR_' + operatorID + '_' + roomID);
            if (searchResultsTR) {
                var descriptions = utilities.getElementsByClassName(searchResultsTR, 'description');
                if (descriptions.length > 0) {
                    var description = descriptions[0];
                    for (var operatorIndex in operators) {
                        var operator = operators[operatorIndex];
                        if (operator.id == operatorID) {
                            for (var roomIndex in operator.rooms) {
                                var room = operator.rooms[roomIndex];
                                if (room.id == roomID) {
                                    description.onclick = function() { grid.expandDescription(operatorID, roomID); };
                                    description.title = 'Click for more information';
                                    description.innerHTML =
                                        '<div style="height: 2.6em; overflow: hidden">' +
                                        '    <p>' + room.description.replace(/<.*?>/g, '') + '</p>' +
                                        '</div>' +
                                        '<div style="position: relative; float: right; margin-top: -1em; background-color: #fff; line-height: 11px">... <a href="javascript:void(0)" style="font-weight: normal">more info &raquo;</a></div>';
                                    break;
                                }
                            }
                        }
                    }
                }
            }
        }

        var render = function(operators, operatorID) {
            if (!operatorID)
                clear();
            else
                showDates();

            drawHeader();

            for (var operatorIndex in operators)
                drawOperator(operators[operatorIndex]);

            if (searchResults.rows.length == 0)
                drawNoResults(operators);

            hideDates();
        }

        var showDates = function() {
            var dates = new Array();
            var curDate = new Date(arrivalDate);

            for (var i = 0; i < numberOfNights; i++) {
                curDate.setDate(curDate.getDate() + (i == 0 ? 0 : 1)); // increment the current date by 1 day
                dates.push(curDate.toString());

                var els = utilities.getElementsByClassName(document.body, 'date' + formatDate(curDate, 'ddmmyyyy'));

                for (var elIndex = 0; elIndex < els.length; elIndex++) {
                    els[elIndex].className = els[elIndex].className.replace(' hiddenDate', '');
                    els[elIndex].style.display = '';
                }
            }
        }

        var hideDates = function() {
            var dates = new Array();
            var curDate = new Date(arrivalDate);

            for (var i = 0; i < numberOfNights; i++) {
                curDate.setDate(curDate.getDate() + (i == 0 ? 0 : 1)); // increment the current date by 1 day
                dates.push(curDate.toString());
            }

            if (utilities.getElementsByClassName(document.getElementById('search_header').tHead, 'name')[0].offsetWidth < 385) {
                var els = [];
                var curDateIndex = Math.ceil(dates.length / 2) - 1;
                var direction = 1;
                var step = 1;

                while (curDateIndex >= 0 && curDateIndex < dates.length && utilities.getElementsByClassName(document.getElementById('search_header').tHead, 'name')[0].offsetWidth < 385) {

                    els = utilities.getElementsByClassName(document.body, 'date' + formatDate(dates[curDateIndex], 'ddmmyyyy'));

                    for (var elIndex = 0; elIndex < els.length; elIndex++) {
                        els[elIndex].style.display = 'none';
                    }

                    curDateIndex += parseInt(step * direction);
                    step++;
                    direction = direction * -1;
                }

                for (var elIndex = 0; elIndex < els.length; elIndex++) {
                    els[elIndex].className += ' hiddenDate';
                    els[elIndex].style.display = '';
                }
            }
        }

        var clear = function() {
            while (searchResults.rows.length > 0)
                searchResults.deleteRow(0);

            var searchHeaderTR = document.getElementById('search_header').rows[0];
            {
                var searchHeaderTRDates = utilities.getElementsByClassName(searchHeaderTR, 'date');
                {
                    for (var searchHeaderTRDateIndex = 0; searchHeaderTRDateIndex < searchHeaderTRDates.length; searchHeaderTRDateIndex++)
                        searchHeaderTR.removeChild(searchHeaderTRDates[searchHeaderTRDateIndex]);
                }
            }
        }

        var getPLSize = function(el) { return { w: el.offsetWidth, h: el.offsetHeight} };
        var getSize = function() { return { w: document.body.scrollWidth, h: document.body.offsetHeight} };
        var getScroll = function() { return { x: document.body.scrollLeft, y: document.body.scrollTop} };

        var drawInstructions = function() {
            var searchResultsTR = searchResults.insertRow(0);
            {
                searchResultsTR.id = 'searchResultsTR';

                var searchResultsTRTD = searchResultsTR.insertCell(searchResultsTR.cells.length);
                {
                    searchResultsTRTD.colSpan = document.getElementById('search_header').rows[0].cells.length;
                    searchResultsTRTD.innerHTML = '<p>Please check your stay details above and click search to see the rooms we have available.</p>';
                }
            }
        }

        var drawSeparator = function() {
            var searchResultsTR = searchResults.insertRow(searchResults.rows.length);
            {
                searchResultsTR.id = 'searchResultsTR';
                searchResultsTR.className = 'exp_bot_sep';

                var searchResultsTRTD = searchResultsTR.insertCell(searchResultsTR.cells.length);
                {
                    searchResultsTRTD.colSpan = document.getElementById('search_header').rows[0].cells.length;
                }
            }
        }

        var drawNoResults = function(operators) {
            var searchResultsTR = searchResults.insertRow(0);
            {
                searchResultsTR.id = 'searchResultsTR';

                var searchResultsTRTD = searchResultsTR.insertCell(searchResultsTR.cells.length);
                {
                    searchResultsTRTD.colSpan = document.getElementById('search_header').rows[0].cells.length
                    searchResultsTRTD.innerHTML = '<p><b style="font-size: 14px; font-weight: bold">There are no results to display</b></p>';

                    if (operators.length > 0) {
                        if (showShortList)
                            searchResultsTRTD.innerHTML += '<p>Try turning the short list filter off and checking the shortlist box against a room before turning the short list filter on.</p>';
                    } else {
                        if (txtOperatorName.value != '')
                            searchResultsTRTD.innerHTML += '<p>Try a different Search filter to give you more results.</p>';
                        else
                            searchResultsTRTD.innerHTML += '<p>Try clearing some advanced search options and seaching again.</p>';
                    }
                }
            }
        }

        var drawHeader = function() {
            var searchHeaderTHeadRow = document.getElementById('search_header').rows[0];
            var curDate = new Date(arrivalDate);

            for (var i = 0; i < numberOfNights; i++) {
                curDate.setDate(curDate.getDate() + (i == 0 ? 0 : 1)); // increment the current date by 1 day

                var searchHeaderTHeadRowTH = document.createElement('th');
                {
                    searchHeaderTHeadRowTH.className = 'date' + formatDate(curDate, 'ddmmyyyy') + ' date' + ((formatDate(curDate, 'ddd') == 'Sat' || formatDate(curDate, 'ddd') == 'Sun') ? ' weekend' : '');
                    searchHeaderTHeadRowTH.innerHTML = ('<b class="day">' + formatDate(curDate, 'ddd') + '</b> ') + ('<b class="day_num">' + formatDate(curDate, 'd') + '</b> ') + ('<b class="month">' + formatDate(curDate, 'mmm') + '</b>');
                    searchHeaderTHeadRow.insertBefore(searchHeaderTHeadRowTH, searchHeaderTHeadRow.cells[4 + i])
                }
            }
        }

        var drawOperator = function(operator) {

            var hasShortList = false;

            if (showShortList) {
                for (var roomIndex in operator.rooms) {
                    if (operator.rooms[roomIndex].isShortListed)
                        hasShortList = true;
                }
                if (!hasShortList)
                    return;
            }

            var searchResultsTR = document.getElementById('searchResultsTR_' + operator.id);
            {
                if (!searchResultsTR)
                    searchResultsTR = searchResults.insertRow(searchResults.rows.length);
                else {
                    for (var rowIndex = 0; rowIndex < searchResults.rows.length; rowIndex++) {
                        if (searchResults.rows[rowIndex].id == searchResultsTR.id) {
                            searchResultsTR.parentNode.removeChild(searchResultsTR);
                            searchResultsTR = searchResults.insertRow(searchResults.rows.length);

                            break;
                        }
                    }
                }

                var room = null;

                for (var roomIndex in operator.rooms) {
                    if (operator.rooms[roomIndex].rank == 1) {
                        room = operator.rooms[roomIndex];
                        break;
                    }
                }

                searchResultsTR.id = 'searchResultsTR_' + operator.id;
                searchResultsTR.operatorID = operator.id;

                searchResultsTR.className = ((operator.isExpanded || (showShortList && hasShortList)) ? 'expanded ' : '');

                if (!operator.isExpanded && (!showShortList && !hasShortList)) {
                    var searchResultsTRTDShortList = searchResultsTR.insertCell(searchResultsTR.cells.length);
                    {
                        searchResultsTRTDShortList.className = 'shortlist';

                        var input = document.createElement('input');
                        {
                            input.type = 'checkbox';
                            input.operatorID = operator.id;
                            input.roomID = room.id;
                            input.onchange = function() { filterer.shortList(this.operatorID, this.roomID, this.checked); };
                            input.checked = room.isShortListed;

                            searchResultsTRTDShortList.appendChild(input);
                        }
                    }
                }

                var searchResultsTRTDName = searchResultsTR.insertCell(searchResultsTR.cells.length);
                {
                    searchResultsTRTDName.className = 'name';
                    searchResultsTRTDName.colSpan = (operator.isExpanded || (showShortList && hasShortList)) ? 2 : 1;
                    searchResultsTRTDName.style.cursor = 'pointer';
                    searchResultsTRTDName.innerHTML = (room.availability.isSpecial ? '<div class="' + (room.availability.isLastMinute ? 'last_minute' : 'hot_deal') + '" title="' + room.availability.special + '"></div>' : '');

                    if (operator.isGoldMedal) {
                        if (operator.isGoldMedalToday || arrivalDate > new Date())
                            searchResultsTRTDName.innerHTML += '<div class="medal"><img src="http://www.bookeasy.com.au/images/bookable.gif" title="Instant Booking" /></div>';
                        else
                            searchResultsTRTDName.innerHTML += '<div class="medal"><img src="http://www.bookeasy.com.au/images/notbookabletoday.gif" title="Booking Requires Confirmation" /></div>';
                    }
                    else {
                        searchResultsTRTDName.innerHTML += '<div class="medal"><img src="http://www.bookeasy.com.au/images/24hour.gif" title="Booking Requires Confirmation" /></div>';
                    }

                    searchResultsTRTDName.innerHTML +=
                        '<a class="prop_name" onclick="shadowBox.show(\'accomgrid_searchoperatordetails.asp?OperatorID=' + operator.id + '\')">' + operator.name + '</a> ' +
                        (
                            showStarRating && operator.starRating > 0 ?
                            (
                                '<b title="' + (operator.isSelfRated ? 'Self Rated' : 'AAA Rated') + '" class="rating' + (operator.isSelfRated ? ' self' : ' star') + '_' + operator.starRating.toString().replace('.', '_') + '">' +
                                    '<b>' + operator.starRating + ' star' + (operator.isSelfRated ? ' self-rated' : '') + '</b>' +
                                '</b> '
                            ) : ('<b class="rating" style="visibility: hidden; width: 2px"></b>')
                        ) +
                        '<b class="region">' + operator.location + '</b>';
                }

                if (!operator.isExpanded && (!showShortList && !hasShortList)) {
                    var searchResultsTRTDFullCost = searchResultsTR.insertCell(searchResultsTR.cells.length);
                    {
                        searchResultsTRTDFullCost.className = 'fullCost';

                        var fullCost = 0;

                        for (var dayIndex in room.availability.days) {
                            var day = room.availability.days[dayIndex];
                            if (day.fullCost > fullCost)
                                fullCost = day.fullCost;
                        }

                        searchResultsTRTDFullCost.innerHTML = '$' + parseInt(fullCost);
                    }
                }
                else {
                    var searchResultsTRTDFullCost = searchResultsTR.insertCell(searchResultsTR.cells.length);
                    {
                        searchResultsTRTDFullCost.className = 'fullCost';
                        searchResultsTRTDFullCost.innerHTML = 'Full Rate';
                    }
                }

                var searchResultsTRTDShiftBack = searchResultsTR.insertCell(searchResultsTR.cells.length);
                {
                    searchResultsTRTDShiftBack.className = 'shift_back';
                }

                if (operator.isExpanded || (showShortList && hasShortList)) {
                    var curDate = new Date(arrivalDate);

                    for (var i = 0; i < numberOfNights; i++) {
                        curDate.setDate(curDate.getDate() + (i == 0 ? 0 : 1)); // increment the current date by 1 day

                        var searchResultsTRTD = searchResultsTR.insertCell(searchResultsTR.cells.length);
                        {
                            searchResultsTRTD.className = 'date' + formatDate(curDate, 'ddmmyyyy') + ' date' + ((formatDate(curDate, 'ddd') == 'Sat' || formatDate(curDate, 'ddd') == 'Sun') ? ' weekend' : '');
                            searchResultsTRTD.innerHTML = '<b class="day_num">' + formatDate(curDate, 'd') + '</b> ' + '<b class="month">' + formatDate(curDate, 'mmm') + '</b>';
                        }
                    }
                }
                else {
                    for (var dayIndex in room.availability.days) {
                        var day = room.availability.days[dayIndex];

                        var searchResultsTRTDDate = searchResultsTR.insertCell(searchResultsTR.cells.length);
                        {
                            searchResultsTRTDDate.className = 'date' + formatDate(day.date, 'ddmmyyyy') + ' date';

                            if (false == day.isAvailable) {
                                searchResultsTRTDDate.className += ' sold';
                                searchResultsTRTDDate.innerHTML = '<b>SOLD</b>';
                                searchResultsTRTDDate.title = 'This day is unavailable';
                                searchResultsTRTDDate.style.cursor = 'help';
                            }
                            else if (day.isConstrained) {
                                searchResultsTRTDDate.className += ' min_nights'
                                searchResultsTRTDDate.innerHTML = '<b>Min ' + parseInt(day.constrainedMinNights) + ' ' + (day.constrainedMinNights == 1 ? 'night' : 'nights') + '</b>';

                                if (day.constrainedDescription == '')
                                    searchResultsTRTDDate.title = parseInt(day.constrainedMinNights) + ' ' + (day.constrainedMinNights == 1 ? 'night' : 'nights');
                                else
                                    searchResultsTRTDDate.title = day.constrainedDescription;

                                searchResultsTRTDDate.style.cursor = 'help';
                            }
                            else {
                                searchResultsTRTDDate.innerHTML = '<b>$' + parseInt(day.cost) + '</b>';

                                if (day.isSpecial) {
                                    searchResultsTRTDDate.title = day.special;
                                    searchResultsTRTDDate.style.cursor = 'help';
                                }
                            }
                        }
                    }
                }

                var searchResultsTRTDShiftForward = searchResultsTR.insertCell(searchResultsTR.cells.length);
                {
                    searchResultsTRTDShiftForward.className = 'shift_forward';
                }

                var searchResultsTRTDTotal = searchResultsTR.insertCell(searchResultsTR.cells.length);
                {
                    searchResultsTRTDTotal.id = 'gridOperator' + operator.id;

                    if (operator.isExpanded || (showShortList && hasShortList)) {
                        searchResultsTRTDTotal.className = 'buttons hide_rooms';

                        if (!showShortList) {
                            searchResultsTRTDTotal.innerHTML =
                                '<a>' +
                                '<b class="hide_rooms"><b class="label">Hide Rooms</b></b>' +
                                '</a>';
                        }
                    }
                    else {
                        searchResultsTRTDTotal.className = 'buttons view_rooms';

                        // Get Cheapest Night Rate
                        var cheapestRate = null;

                        for (var dayIndex = 0; dayIndex < room.availability.days.length; dayIndex++) {
                            var day = room.availability.days[dayIndex];

                            if (!cheapestRate || day.cost < cheapestRate)
                                cheapestRate = day.cost;
                        }

                        searchResultsTRTDTotal.innerHTML =
                            '<a class="navboxcolorback">' +
                            '<b class="label">View rooms</b> ' +
                            '<b class="price">from $' + parseInt(cheapestRate) + '</b>' +
                            '</a>';
                    }
                }

                var onClickCallback = null;
                {
                    if (operator.isExpanded || (showShortList && hasShortList))
                        onClickCallback = function() { operator.isExpanded = false; renderer.render(sorter.sort(filterer.filter(operators, txtOperatorName.value))); };
                    else
                        onClickCallback = function() { searchResultsTRTDTotal.innerHTML = '<img src="http://www.bookeasy.com.au/images/ajax-loader.gif" style="margin: 8px 0 8px 0" width="16" height="16" />'; loader.loadUrl('accomgrid_condensed.js.asp?OperatorID=' + searchResultsTR.operatorID + '&IncludeAllRooms=True'); };

                    searchResultsTRTDName.onclick = function(e) { e = e || window.event; var el = e.srcElement || e.target; if (el.tagName == 'A') return; onClickCallback() };
                    searchResultsTRTDTotal.onclick = onClickCallback;
                }
            }

            if (operator.isExpanded || (showShortList && hasShortList))
                drawRooms(operator);
        }

        var drawRooms = function(operator) {
            for (var roomIndex in operator.rooms) {
                var room = operator.rooms[roomIndex];

                if (showShortList && !room.isShortListed)
                    continue;

                var searchResultsTR = searchResults.insertRow(searchResults.rows.length);
                {
                    searchResultsTR.id = 'searchResultsTR_' + operator.id + '_' + room.id;
                    searchResultsTR.className = 'room_type';

                    if (!room.availability.isAvailable || room.availability.isConstrained)
                        searchResultsTR.className += ' unavailable';

                    var searchResultsTRTDShortList = searchResultsTR.insertCell(searchResultsTR.cells.length);
                    {
                        searchResultsTRTDShortList.className = 'shortlist';

                        var input = document.createElement('input');
                        {
                            input.type = 'checkbox';
                            input.operatorID = operator.id;
                            input.roomID = room.id;
                            input.onchange = function() { filterer.shortList(this.operatorID, this.roomID, this.checked); };
                            input.checked = room.isShortListed;

                            searchResultsTRTDShortList.appendChild(input);
                        }
                    }

                    var searchResultsTRTDName = searchResultsTR.insertCell(searchResultsTR.cells.length);
                    {
                        searchResultsTRTDName.className = 'name';
                        searchResultsTRTDName.innerHTML =
                            '<table>' +
                            '    <tr>' +
                            '        <td class="img">' +
                            '            <div class="img">' +
                                            (room.imageURL == '' ? '' : ('<img src="http://www.bookeasy.com.au/utilities/getThumbnail.aspx?URL=' + room.imageURL + '&Width=65&Height=0" alt=""  onclick="shadowBox.show(\'accomgrid_condensedimage.asp?URL=' + room.imageURL + '\', parseInt(this.clientWidth * 3.846153846153846) + 40, parseInt(this.clientHeight * 3.846153846153846) + 40)" title="Enlarge Picture" />')) +
                            '            </div>' +
                            '        </td>' +
                            '        <td class="separator">' +
                            '        </td>' +
                            '        <td class="room_container">' +
                                         (room.availability.isSpecial ? '<div class="' + (room.availability.isLastMinute ? 'last_minute' : 'hot_deal') + '" title="' + room.availability.special + '"></div>' : '') +
                            '            <div class="room_name">' +
                                            room.name +
                                            (room.isActive ? '' : ' <span style="color: #f00">** Inactive On Website **</span>') +
                            '            </div> ' +
                            '            <div class="description" onclick="grid.expandDescription(' + operator.id + ', ' + room.id + ')" title="Click for more information">' +
                            '                <div style="height: 2.6em; overflow: hidden">' +
                            '                    <p>' + room.description.replace(/<.*?>/g, '') + '</p>' +
                            '                </div>' +
                            '                <div style="position: relative; float: right; margin-top: -1em; background-color: #fff; line-height: 11px">... <a href="javascript:void(0)" style="font-weight: normal">more info &raquo;</a></div>' +
                            '            </div>' +
                            '        </td>' +
                            '    </tr>' +
                            '</table>';
                    }

                    var searchResultsTRTDShiftBack = searchResultsTR.insertCell(searchResultsTR.cells.length);
                    {
                        searchResultsTRTDShiftBack.className = 'shift_back';
                    }

                    var searchResultsTRTDFullCost = searchResultsTR.insertCell(searchResultsTR.cells.length);
                    {
                        searchResultsTRTDFullCost.className = 'fullCost';

                        var fullCost = 0;

                        for (var dayIndex in room.availability.days) {
                            var day = room.availability.days[dayIndex];
                            if (day.fullCost > fullCost)
                                fullCost = day.fullCost;
                        }

                        searchResultsTRTDFullCost.innerHTML = '$' + parseInt(fullCost);
                    }

                    for (var dayIndex in room.availability.days) {
                        var day = room.availability.days[dayIndex];

                        var searchResultsTRTDDate = searchResultsTR.insertCell(searchResultsTR.cells.length);
                        {
                            searchResultsTRTDDate.className = 'date' + formatDate(day.date, 'ddmmyyyy') + ' date';

                            if (false == day.isAvailable) {
                                searchResultsTRTDDate.className += ' sold';
                                searchResultsTRTDDate.innerHTML = '<b>SOLD</b>';
                                searchResultsTRTDDate.title = 'This day is unavailable';
                                searchResultsTRTDDate.style.cursor = 'help';
                            }
                            else if (day.isConstrained) {
                                searchResultsTRTDDate.className += ' min_nights'
                                searchResultsTRTDDate.innerHTML = '<b>Min ' + parseInt(day.constrainedMinNights) + ' ' + (day.constrainedMinNights == 1 ? 'night' : 'nights') + '</b>';

                                if (day.constrainedDescription == '')
                                    searchResultsTRTDDate.title = parseInt(day.constrainedMinNights) + ' ' + (day.constrainedMinNights == 1 ? 'night' : 'nights');
                                else
                                    searchResultsTRTDDate.title = day.constrainedDescription;

                                searchResultsTRTDDate.style.cursor = 'help';
                            }
                            else {
                                searchResultsTRTDDate.innerHTML = '<b>$' + parseInt(day.cost) + '</b>';

                                if (day.isSpecial) {
                                    searchResultsTRTDDate.title = day.special;
                                    searchResultsTRTDDate.style.cursor = 'help';
                                }
                            }
                        }
                    }

                    var searchResultsTRTDShiftForward = searchResultsTR.insertCell(searchResultsTR.cells.length);
                    {
                        searchResultsTRTDShiftForward.className = 'shift_forward';
                    }

                    var searchResultsTRTDTotal = searchResultsTR.insertCell(searchResultsTR.cells.length);
                    {
                        searchResultsTRTDTotal.className = 'buttons';

                        if (!room.availability.isAvailable || room.availability.isConstrained) {
                            searchResultsTRTDTotal.innerHTML =
                                '<a>' +
                                    '<b class="label">Not Bookable</b>' +
                                '</a>';
                        }
                        else {
                            searchResultsTRTDTotal.innerHTML =
                                '<a href="javascript:void(0)" onclick="shadowBox.show(\'accomgrid_condensed_tc.asp?OperatorID=' + operator.id + '&RoomID=' + room.id + '\', 470, 490);">' +
                                    '<b class="label">$' + parseInt(room.availability.cost) + '</b>' +
                                '</a>';
                        }
                    }
                }
            }

            drawSeparator();
        }

        return {
            render: render,
            contractDescription: contractDescription,
            expandDescription: expandDescription,
            hideDates: hideDates,
            showDates: showDates,
            drawInstructions: drawInstructions
        }
    } ();

    var flasher = function() {

        // private properties
        var wi = null;
        var op = 0;
        var step = 5;

        var init = function() {
            utilities.setOpacity(divFlasher, 0);
            var els = frmGrid.getElementsByTagName('*');
            for (var elIndex in els) {
                utilities.addEvent(els[elIndex], 'change', function() { if (utilities.hasFormChanged(frmGrid, 'defaultValue')) { flasher.start() } else { flasher.stop() } });
            }
        }

        var setDefaults = function() {
            divFlasher.style.visibility = 'hidden';
            var els = frmGrid.getElementsByTagName('*');
            for (var elIndex in els) {
                els[elIndex].defaultValue = els[elIndex].value;
            }
        }

        // private methods
        var changeOpacity = function() {
            step = op == 0 ? 5 : op == 100 ? -5 : step;
            op += step;
            utilities.setOpacity(divFlasher, op);
        }

        // public
        return {
            init: function() { init(); setDefaults() },
            setDefaults: setDefaults,
            start: function() { if (wi == null) { divFlasher.style.visibility = 'visible'; wi = window.setInterval(changeOpacity, 50); } },
            stop: function() { window.clearInterval(wi); divFlasher.style.visibility = 'hidden'; wi = null; }
        }
    } ();

    var sorter = function() {

        // private methods
        var bubbleSort = function(arr) { for (var i = 0; i < arr.length - 1; i++) { for (var j = arr.length - 1; j > i; j--) { for (var x = 0; x < arr[j].values.length; x++) { var dir = arr[j].values[x].direction; if (dir > 0) { if (arr[j].values[x].value < arr[i].values[x].value) { var dummy = arr[i]; arr[i] = arr[j]; arr[j] = dummy; } } else if (dir < 0) { if (arr[j].values[x].value > arr[i].values[x].value) { var dummy = arr[i]; arr[i] = arr[j]; arr[j] = dummy; } } } } } return arr; };
        var direction = 0;
        var field = '';

        // public methods
        var sort = function(operators) {

            var sortedOperators = new Array();

            var unsortedArray = new Array();
            {
                for (var operatorIndex in operators) {
                    var operator = operators[operatorIndex];
                    if (field == 'name') {
                        unsortedArray.push({ key: operator.id, values: new Array({ direction: 1 * (direction == 0 ? 1 : direction), value: operator.name }) });
                    }
                    else if (field == 'rating') {
                        unsortedArray.push({ key: operator.id, values: new Array({ direction: -1 * (direction == 0 ? 1 : direction), value: operator.isSelfRated }, { direction: 1 * (direction == 0 ? 1 : direction), value: operator.starRating }) });
                    }
                    else if (field == 'price') {
                        for (var roomIndex in operator.rooms) {
                            var room = operator.rooms[roomIndex];
                            if (room.rank == 1)
                                unsortedArray.push({ key: operator.id, values: new Array({ direction: 1 * (direction == 0 ? 1 : direction), value: room.availability.cost }) });
                        }
                    }
                    else if (field == 'instantconfirmation') {
                        unsortedArray.push({ key: operator.id, values: new Array({ direction: -1 * (direction == 0 ? 1 : direction), value: ((operator.isGoldMedal ? 1 : 0) + (operator.isGoldMedalToday ? 1 : 0)) }) });
                    }
                    else {
                        unsortedArray.push({ key: operator.id, values: new Array({ direction: 1 * (direction == 0 ? 1 : direction), value: operator.sortOrder }) });
                    }
                }

                var sortedArray = bubbleSort(unsortedArray);
                for (var sortedArrayIndex in sortedArray) {
                    for (var operatorIndex in operators) {
                        var operator = operators[operatorIndex];
                        if (sortedArray[sortedArrayIndex].key == operator.id) {
                            sortedOperators.push(operator);
                            break;
                        }
                    }
                }
            }

            if (direction == -1)
                imgdirection.className = 'up';
            else if (direction == 0)
                imgdirection.className = 'none';
            else if (direction == 1)
                imgdirection.className = 'down';

            return sortedOperators;
        }

        return {
            sort: sort,
            setField: function(f) {
                field = f;
                if (field == 'name')
                    direction = 1;
                else if (field == 'rating')
                    direction = -1;
                else if (field == 'price')
                    direction = 1;
                else if (field == 'instantconfirmation')
                    direction = 1;
                else
                    direction = 0;
            },
            reverse: function() { direction = direction * -1; }
        }
    } ();

    var filterer = function() {

        var filter = function(operators, v) {

            if (v == '')
                return operators;
            else {
                var filteredOperators = new Array();
                {
                    for (var operatorIndex in operators) {
                        var operator = operators[operatorIndex];
                        {
                            if (operator.name.toLowerCase().indexOf(v.toLowerCase()) > -1)
                                filteredOperators.push(operator);
                        }
                    }

                    return filteredOperators;
                }
            }
        }

        var shortList = function(operatorID, roomID, isShortListed) {
            for (var operatorIndex in operators) {
                if (operators[operatorIndex].id == operatorID) {
                    for (var roomIndex in operators[operatorIndex].rooms) {
                        if (operators[operatorIndex].rooms[roomIndex].id == roomID) {
                            operators[operatorIndex].rooms[roomIndex].isShortListed = isShortListed;
                            break;
                        }
                    }
                }
            }
        }

        return {
            filter: filter,
            shortList: shortList
        }
    } ();

    var backgroundProcesses = new Array();

    var utilities = {
        addEvent: function(el, event, func) { if (el.addEventListener) { el.addEventListener(event, func, true) } else if (el.attachEvent) { el.attachEvent('on' + event, func) } },
        removeEvent: function(el, event, func) { if (el.removeEventListener) { el.removeEventListener(event, func, true) } else if (el.detachEvent) { el.detachEvent('on' + event, func) } },
        hasFormChanged: function(el, p) { var els = el.getElementsByTagName('*'); for (var elIndex in els) { var v = els[elIndex][p]; if (v != null && els[elIndex].value != v) return true; } return false; },
        setOpacity: function(el, op) { el.style['KHTMLOpacity'] = op / 100; el.style['MozOpacity'] = op / 100; el.style['-khtml-opacity'] = op / 100; el.style['-moz-opacity'] = op / 100; el.style['opacity'] = op / 100; el.style['-ms-filter'] = 'alpha(opacity=' + op + ')'; el.style['filter'] = 'alpha(opacity=' + op + ')'; },
        getElementsByClassName: function(el, className) { var retnode = []; var myclass = new RegExp('(\\b|\\s)' + className + '(\\b|\\s)'); var elem = el.getElementsByTagName('*'); for (var i = 0; i < elem.length; i++) { var classes = elem[i].className; if (myclass.test(classes)) { retnode.push(elem[i]); } } return retnode; },
        runInBG: function(processName, func, delay) { if (backgroundProcesses[processName]) { window.clearTimeout(backgroundProcesses[processName]); backgroundProcesses[processName] = null; } backgroundProcesses[processName] = window.setTimeout(func, delay); }
    }

    return {
        init: function() { init(); flasher.init() },
        load: loader.loadUrl,
        contractDescription: renderer.contractDescription,
        drawInstructions: renderer.drawInstructions,
        expandDescription: renderer.expandDescription,
        operators: operators,
        shift: function(direction) { var curDate = new Date(arrivalDate); curDate.setDate(curDate.getDate() + direction); document.getElementById('date_input').value = formatDate(curDate, 'dd/mm/yyyy'); document.getElementById('thSearch').className = 'search loading'; loader.loadUrl('accomgrid_condensed.js.asp?ArrivalDate=' + formatDate(curDate, 'dd/mm/yyyy') + '&IncludeAllRooms=1', true); }
    }
}