ONESEARCH_URL = "http://onesearch.svc.primedia.com";  //prod
//ONESEARCH_URL = "http://10.130.87.12";  //QA
APARTMENT_GUIDE = "AG";
NEW_HOME_GUIDE = "NHG";
RENTALS = "R";
RENTAL_HOUSES = "RH";
 
APPLICATION = RENTALS;
channel = "apartments"
/*
 * Autocomplete - jQuery plugin 1.0.2
 *
 * Copyright (c) 2007 Dylan Verheul, Dan G. Switzer, Anjesh Tuladhar, Jörn Zaefferer
 *
 * Dual licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 *
 * Revision: $Id: jquery.autocomplete.js 5747 2008-06-25 18:30:55Z joern.zaefferer $
 *
 */

; (function($) {

    $.fn.extend({
        autocomplete: function(urlOrData, options) {
            var isUrl = typeof urlOrData == "string";
            options = $.extend({},
            $.Autocompleter.defaults, {
                url: isUrl ? urlOrData: null,
                data: isUrl ? null: urlOrData,
                delay: isUrl ? $.Autocompleter.defaults.delay: 10,
                max: options && !options.scroll ? 10: 150
            },
            options);

            // if highlight is set to false, replace it with a do-nothing function
            options.highlight = options.highlight ||
            function(value) {
                return value;
            };

            // if the formatMatch option is not specified, then use formatItem for backwards compatibility
            options.formatMatch = options.formatMatch || options.formatItem;

            // TJ - Custom property added onSelect is called when Enter/Return is pressed
            options.onSelect = options.onSelect ||
            function(value) {
                return value;
            };

            return this.each(function() {
                new $.Autocompleter(this, options);
            });
        },
        result: function(handler) {
            return this.bind("result", handler);
        },
        search: function(handler) {
            return this.trigger("search", [handler]);
        },
        flushCache: function() {
            return this.trigger("flushCache");
        },
        setOptions: function(options) {
            return this.trigger("setOptions", [options]);
        },
        unautocomplete: function() {
            return this.trigger("unautocomplete");
        }
    });

    $.Autocompleter = function(input, options) {

        var KEY = {
            UP: 38,
            DOWN: 40,
            DEL: 46,
            TAB: 9,
            RETURN: 13,
            ESC: 27,
            COMMA: 188,
            PAGEUP: 33,
            PAGEDOWN: 34,
            BACKSPACE: 8
        };

        // Create $ object for input element
        var $input = $(input).attr("autocomplete", "off").addClass(options.inputClass);

        var timeout;
        var previousValue = "";
        var cache = $.Autocompleter.Cache(options);
        var hasFocus = 0;
        var lastKeyPressCode;
        var config = {
            mouseDownOnSelect: false
        };
        var select = $.Autocompleter.Select(options, input, selectCurrent, config);

        var blockSubmit;

        // prevent form submit in opera when selecting with return key
        $.browser.opera && $(input.form).bind("submit.autocomplete",
        function() {
            if (blockSubmit) {
                blockSubmit = false;
                return false;
            }
        });

        // only opera doesn't trigger keydown multiple times while pressed, others don't work with keypress at all
        $input.bind(($.browser.opera ? "keypress": "keydown") + ".autocomplete",
        function(event) {
            // track last key pressed
            lastKeyPressCode = event.keyCode;
            switch (event.keyCode) {
            case KEY.UP:
                event.preventDefault();
                if (select.visible()) {
                    select.prev();
                } else {
                    onChange(0, true);
                }
                break;

            case KEY.DOWN:
                event.preventDefault();
                if (select.visible()) {
                    select.next();
                } else {
                    onChange(0, true);
                }
                break;

            case KEY.PAGEUP:
                event.preventDefault();
                if (select.visible()) {
                    select.pageUp();
                } else {
                    onChange(0, true);
                }
                break;

            case KEY.PAGEDOWN:
                event.preventDefault();
                if (select.visible()) {
                    select.pageDown();
                } else {
                    onChange(0, true);
                }
                break;

                // matches also semicolon
            case options.multiple && $.trim(options.multipleSeparator) == "," && KEY.COMMA:
            case KEY.TAB:
                if (selectCurrent()) {
                    event.preventDefault();
                    blockSubmit = true;
                    return false;
                }
                break;
            case KEY.RETURN:
                if (selectCurrent()) {
                    // custom property to call a method when item selected and user hits Enter/Return
                    options.onSelect();
                    // stop default to prevent a form submit, Opera needs special handling
                    event.preventDefault();
                    blockSubmit = true;
                    return false;
                }
                break;

            case KEY.ESC:
                select.hide();
                break;

            default:
                clearTimeout(timeout);
                timeout = setTimeout(onChange, options.delay);
                break;
            }
        }).focus(function() {
            // track whether the field has focus, we shouldn't process any
            // results if the field no longer has focus
            hasFocus++;
        }).blur(function() {
            hasFocus = 0;
            if (!config.mouseDownOnSelect) {
                hideResults();
            }
        }).click(function() {
            // show select when clicking in a focused field
            if (hasFocus++>1 && !select.visible()) {
                onChange(0, true);
            }
        }).bind("search",
        function() {
            // TODO why not just specifying both arguments?
            var fn = (arguments.length > 1) ? arguments[1] : null;
            function findValueCallback(q, data) {
                var result;
                if (data && data.length) {
                    for (var i = 0; i < data.length; i++) {
                        if (data[i].result.toLowerCase() == q.toLowerCase()) {
                            result = data[i];
                            break;
                        }
                    }
                }
                if (typeof fn == "function") fn(result);
                else $input.trigger("result", result && [result.data, result.value]);
            }
            $.each(trimWords($input.val()),
            function(i, value) {
                request(value, findValueCallback, findValueCallback);
            });
        }).bind("flushCache",
        function() {
            cache.flush();
        }).bind("setOptions",
        function() {
            $.extend(options, arguments[1]);
            // if we've updated the data, repopulate
            if ("data" in arguments[1])
            cache.populate();
        }).bind("unautocomplete",
        function() {
            select.unbind();
            $input.unbind();
            $(input.form).unbind(".autocomplete");
        });


        function selectCurrent() {
            var selected = select.selected();
            if (!selected)
            return false;

            var v = selected.result;
            previousValue = v;

            if (options.multiple) {
                var words = trimWords($input.val());
                if (words.length > 1) {
                    v = words.slice(0, words.length - 1).join(options.multipleSeparator) + options.multipleSeparator + v;
                }
                v += options.multipleSeparator;
            }
            //Modified by Fadi & Bill, saving actual typed in value
            if ($("input#typed")) $("input#typed").val($input.val());
            $input.val(v);
            hideResultsNow();
            $input.trigger("result", [selected.data, selected.value]);
            return true;
        }

        function onChange(crap, skipPrevCheck) {
            if (lastKeyPressCode == KEY.DEL) {
                select.hide();
                return;
            }

            var currentValue = $input.val();

            if (!skipPrevCheck && currentValue == previousValue)
            return;

            previousValue = currentValue;

            currentValue = lastWord(currentValue);
            if (currentValue.length >= options.minChars) {
                $input.addClass(options.loadingClass);
                if (!options.matchCase)
                currentValue = currentValue.toLowerCase();
                request(currentValue, receiveData, hideResultsNow);
            } else {
                stopLoading();
                select.hide();
            }
        };

        function trimWords(value) {
            if (!value) {
                return [""];
            }
            var words = value.split(options.multipleSeparator);
            var result = [];
            $.each(words,
            function(i, value) {
                if ($.trim(value))
                result[i] = $.trim(value);
            });
            return result;
        }

        function lastWord(value) {
            if (!options.multiple)
            return value;
            var words = trimWords(value);
            return words[words.length - 1];
        }

        // fills in the input box w/the first match (assumed to be the best match)
        // q: the term entered
        // sValue: the first matching result
        function autoFill(q, sValue) {
            // autofill in the complete box w/the first match as long as the user hasn't entered in more data
            // if the last user key pressed was backspace, don't autofill
            if (options.autoFill && (lastWord($input.val()).toLowerCase() == q.toLowerCase()) && lastKeyPressCode != KEY.BACKSPACE) {
                // fill in the value (keep the case the user has typed)
                $input.val($input.val() + sValue.substring(lastWord(previousValue).length));
                // select the portion of the value not typed by the user (so the next character will erase)
                $.Autocompleter.Selection(input, previousValue.length, previousValue.length + sValue.length);
            }
        };

        function hideResults() {
            clearTimeout(timeout);
            timeout = setTimeout(hideResultsNow, 200);
        };

        function hideResultsNow() {
            var wasVisible = select.visible();
            select.hide();
            clearTimeout(timeout);
            stopLoading();
            if (options.mustMatch) {
                // call search and run callback
                $input.search(
                function(result) {
                    // if no value found, clear the input box
                    if (!result) {
                        if (options.multiple) {
                            var words = trimWords($input.val()).slice(0, -1);
                            $input.val(words.join(options.multipleSeparator) + (words.length ? options.multipleSeparator: ""));
                        }
                        else
                        $input.val("");
                    }
                }
                );
            }
            // CSI: Commented out to prevent resetting of focus back to user search
            // if (wasVisible)
            //  // position cursor at end of input field
            //  $.Autocompleter.Selection(input, input.value.length, input.value.length);
        };

        function receiveData(q, data) {
            if (data && data.length && hasFocus) {
                stopLoading();
                select.display(data, q);
                autoFill(q, data[0].value);
                select.show();
            } else {
                hideResultsNow();
            }
        };

        function request(term, success, failure) {
            if (!options.matchCase){
              term = term.toLowerCase();
              term = term.replace(/=/g, '');
            }            
            var data = cache.load(term);
            // recieve the cached data
            if (data && data.length) {
                success(term, data);
                // if an AJAX url has been supplied, try loading the data now
            } else if ((typeof options.url == "string") && (options.url.length > 0)) {

                var extraParams = {
                    timestamp: +new Date()
                };
                $.each(options.extraParams,
                function(key, param) {
                    extraParams[key] = typeof param == "function" ? param() : param;
                });

                $.ajax({
                    // try to leverage ajaxQueue plugin to abort previous requests
                    mode: "abort",
                    // limit abortion to this input
                    port: "autocomplete" + input.name,
                    dataType: options.dataType,
                    url: options.url,
                    data: $.extend({
                        q: lastWord(term),
                        channel: channel,
						application: APPLICATION,
                        limit: options.max
                    },
                    extraParams),
                    success: function(data) {
                        var parsed = options.parse && options.parse(data) || parse(data);
                        cache.add(term, parsed);
                        success(term, parsed);
                    }
                });
            } else {
                // if we have a failure, we need to empty the list -- this prevents the the [TAB] key from selecting the last successful match
                select.emptyList();
                failure(term);
            }
        };

        function parse(data) {
            return JSONDataParser.parse(data, options);
        };

        function stopLoading() {
            $input.removeClass(options.loadingClass);
        };

    };

    $.Autocompleter.defaults = {
        inputClass: "ac_input",
        resultsClass: "ac_results",
        loadingClass: "ac_loading",
        minChars: 1,
        delay: 400,
        matchCase: false,
        matchSubset: true,
        matchContains: false,
        cacheLength: 10,
        max: 100,
        mustMatch: false,
        extraParams: {},
        selectFirst: true,
        formatItem: function(row) {
            return row[0];
        },
        formatMatch: null,
        autoFill: false,
        width: 0,
        multiple: false,
        multipleSeparator: ", ",
        highlight: function(value, term) {
            return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + term.replace(/([^$()[]{}*.+?|\])/gi, "\$1") + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong>$1</strong>");
        },
        scroll: true,
        scrollHeight: 180
    };

    $.Autocompleter.Cache = function(options) {

        var data = {};
        var length = 0;

        function matchSubset(s, sub) {
            if (!options.matchCase)
            s = s.toLowerCase();
            var i = s.indexOf(sub);
            if (i == -1) return false;
            return i == 0 || options.matchContains;
        };

        function add(q, value) {
            if (length > options.cacheLength) {
                flush();
            }
            if (!data[q]) {
                length++;
            }
            data[q] = value;
        }

        function populate() {
            if (!options.data) return false;
            // track the matches
            var stMatchSets = {},
            nullData = 0;

            // no url was specified, we need to adjust the cache length to make sure it fits the local data store
            if (!options.url) options.cacheLength = 1;

            // track all options for minChars = 0
            stMatchSets[""] = [];

            // loop through the array and create a lookup structure
            for (var i = 0, ol = options.data.length; i < ol; i++) {
                var rawValue = options.data[i];
                // if rawValue is a string, make an array otherwise just reference the array
                rawValue = (typeof rawValue == "string") ? [rawValue] : rawValue;

                var value = options.formatMatch(rawValue, i + 1, options.data.length);
                if (value === false)
                continue;

                var firstChar = value.charAt(0).toLowerCase();
                // if no lookup array for this character exists, look it up now
                if (!stMatchSets[firstChar])
                stMatchSets[firstChar] = [];

                // if the match is a string
                var row = {
                    value: value,
                    data: rawValue,
                    result: options.formatResult && options.formatResult(rawValue) || value
                };

                // push the current match into the set list
                stMatchSets[firstChar].push(row);

                // keep track of minChars zero items
                if (nullData++<options.max) {
                    stMatchSets[""].push(row);
                }
            };

            // add the data items to the cache
            $.each(stMatchSets,
            function(i, value) {
                // increase the cache size
                options.cacheLength++;
                // add to the cache
                add(i, value);
            });
        }

        // populate any existing data
        setTimeout(populate, 25);

        function flush() {
            data = {};
            length = 0;
        }

        return {
            flush: flush,
            add: add,
            populate: populate,
            load: function(q) {
                if (!options.cacheLength || !length)
                return null;
                /* 
			 * if dealing w/local data and matchContains than we must make sure
			 * to loop through all the data collections looking for matches
			 */
                if (!options.url && options.matchContains) {
                    // track all matches
                    var csub = [];
                    // loop through all the data grids for matches
                    for (var k in data) {
                        // don't search through the stMatchSets[""] (minChars: 0) cache
                        // this prevents duplicates
                        if (k.length > 0) {
                            var c = data[k];
                            $.each(c,
                            function(i, x) {
                                // if we've got a match, add it to the array
                                if (matchSubset(x.value, q)) {
                                    csub.push(x);
                                }
                            });
                        }
                    }
                    return csub;
                } else
                // if the exact item exists, use it
                if (data[q]) {
                    return data[q];
                } else
                if (options.matchSubset) {
                    for (var i = q.length - 1; i >= options.minChars; i--) {
                        var c = data[q.substr(0, i)];
                        if (c) {
                            var csub = [];
                            $.each(c,
                            function(i, x) {
                                if (matchSubset(x.value, q)) {
                                    csub[csub.length] = x;
                                }
                            });
                            return csub;
                        }
                    }
                }
                return null;
            }
        };
    };

    $.Autocompleter.Select = function(options, input, select, config) {
        var CLASSES = {
            ACTIVE: "ac_over"
        };

        var listItems,
        active = -1,
        data,
        term = "",
        needsInit = true,
        element,
        list;

        // Create results
        function init() {
            if (!needsInit)
            return;
            element = $("<div/>")
            .hide()
            .addClass(options.resultsClass)
            .css("position", "absolute")
            .appendTo(document.body);

            list = $("<ul/>").appendTo(element).mouseover(function(event) {
                if (target(event).nodeName && target(event).nodeName.toUpperCase() == 'LI') {
                    active = $("li", list).removeClass(CLASSES.ACTIVE).index(target(event));
                    $(target(event)).addClass(CLASSES.ACTIVE);
                }
            }).click(function(event) {
                $(target(event)).addClass(CLASSES.ACTIVE);
                select();
                // TODO provide option to avoid setting focus again after selection? useful for cleanup-on-focus
                input.focus();
                return false;
            }).mousedown(function() {
                config.mouseDownOnSelect = true;
            }).mouseup(function() {
                config.mouseDownOnSelect = false;
            });

            if (options.width > 0)
            element.css("width", options.width);

            needsInit = false;
        }

        function target(event) {
            var element = event.target;
            while (element && element.tagName != "LI")
            element = element.parentNode;
            // more fun with IE, sometimes event.target is empty, just ignore it then
            if (!element)
            return [];
            return element;
        }

        function moveSelect(step) {
            listItems.slice(active, active + 1).removeClass(CLASSES.ACTIVE);
            movePosition(step);
            var activeItem = listItems.slice(active, active + 1).addClass(CLASSES.ACTIVE);
            if (options.scroll) {
                var offset = 0;
                listItems.slice(0, active).each(function() {
                    offset += this.offsetHeight;
                });
                if ((offset + activeItem[0].offsetHeight - list.scrollTop()) > list[0].clientHeight) {
                    list.scrollTop(offset + activeItem[0].offsetHeight - list.innerHeight());
                } else if (offset < list.scrollTop()) {
                    list.scrollTop(offset);
                }
            }
        };

        function movePosition(step) {
            active += step;
            if (active < 0) {
                active = listItems.size() - 1;
            } else if (active >= listItems.size()) {
                active = 0;
            }
        }

        function limitNumberOfItems(available) {
            return options.max && options.max < available
            ? options.max
            : available;
        }

        function fillList() {
            list.empty();
            var max = limitNumberOfItems(data.length);
            for (var i = 0; i < max; i++) {
                if (!data[i])
                continue;
                var formatted = options.formatItem(data[i].data, i + 1, max, data[i].value, term);
                if (formatted === false)
                continue;
                var li = $("<li/>").html(options.highlight(formatted, term)).addClass(i % 2 == 0 ? "ac_even": "ac_odd").appendTo(list)[0];
                $.data(li, "ac_data", data[i]);
            }
            listItems = list.find("li");
            if (options.selectFirst) {
                listItems.slice(0, 1).addClass(CLASSES.ACTIVE);
                active = 0;
            }
            // apply bgiframe if available
            if ($.fn.bgiframe)
            list.bgiframe();
        }

        return {
            display: function(d, q) {
                init();
                data = d;
                term = q;
                fillList();
            },
            next: function() {
                moveSelect(1);
            },
            prev: function() {
                moveSelect( - 1);
            },
            pageUp: function() {
                if (active != 0 && active - 8 < 0) {
                    moveSelect( - active);
                } else {
                    moveSelect( - 8);
                }
            },
            pageDown: function() {
                if (active != listItems.size() - 1 && active + 8 > listItems.size()) {
                    moveSelect(listItems.size() - 1 - active);
                } else {
                    moveSelect(8);
                }
            },
            hide: function() {
                //needed to hide drop down boxes, IE6 only
                hideDropdowns(false);
                element && element.hide();
                listItems && listItems.removeClass(CLASSES.ACTIVE);
                active = -1;
            },
            visible: function() {
                return element && element.is(":visible");
            },
            current: function() {
                return this.visible() && (listItems.filter("." + CLASSES.ACTIVE)[0] || options.selectFirst && listItems[0]);
            },
            show: function() {
                //needed to hide drop down boxes, IE6 only
                hideDropdowns(true);
                var offset = $(input).offset();
                element.css({
                    width: typeof options.width == "string" || options.width > 0 ? options.width: $(input).width(),
                    top: offset.top + input.offsetHeight + 8,
                    left: offset.left - 1
                }).show();
                if (options.scroll) {
                    list.scrollTop(0);
                    list.css({
                        maxHeight: options.scrollHeight,
                        overflow: 'auto'
                    });

                    if ($.browser.msie && typeof document.body.style.maxHeight === "undefined") {
                        var listHeight = 0;
                        listItems.each(function() {
                            listHeight += this.offsetHeight;
                        });
                        var scrollbarsVisible = listHeight > options.scrollHeight;
                        list.css('height', scrollbarsVisible ? options.scrollHeight: listHeight);
                        if (!scrollbarsVisible) {
                            // IE doesn't recalculate width when scrollbar disappears
                            listItems.width(list.width() - parseInt(listItems.css("padding-left")) - parseInt(listItems.css("padding-right")));
                        }
                    }

                }
            },
            selected: function() {
                var selected = listItems && listItems.filter("." + CLASSES.ACTIVE).removeClass(CLASSES.ACTIVE);
                return selected && selected.length && $.data(selected[0], "ac_data");
            },
            emptyList: function() {
                list && list.empty();
            },
            unbind: function() {
                element && element.remove();
            }
        };
    };

    $.Autocompleter.Selection = function(field, start, end) {
        if (field.createTextRange) {
            var selRange = field.createTextRange();
            selRange.collapse(true);
            selRange.moveStart("character", start);
            selRange.moveEnd("character", end);
            selRange.select();
        } else if (field.setSelectionRange) {
            field.setSelectionRange(start, end);
        } else {
            if (field.selectionStart) {
                field.selectionStart = start;
                field.selectionEnd = end;
            }
        }
        field.focus();
    };

})(jQuery);

// ################## BEGIN JAVASCRIPT REFACTORING ##################
JSONDataParser = {
  parse: function(data, options) {
    var parsed = [];
    if (data) {
   $(data).each(function(index, jsonData) {
        var row = $.trim(jsonData.name + "|" + jsonData.seopath + "|" + jsonData.geocode + "|" + jsonData.radius + "|" + jsonData.sortfield + "|" + jsonData.count);
        if (row) {
       row = row.split("|");
       parsed[parsed.length] = {
     data: row,
     value: row[0],
     result: options.formatResult && options.formatResult(row, row[0]) || row[0]
       };
        }
   });
    }
    return parsed;
  }
}

function hideAllSelects() {
  $("select").hide();
}

function showAllSelects() {
  $("select").show();
}

function isIESixOrLower() {
  return $.browser.msie && parseInt($.browser.version) <= 6;
}

function hideDropdowns(hide){
  if (isIESixOrLower()) {
    if (hide) {
      hideAllSelects();
    }
    else{
      showAllSelects();
    }
  }
 
}var ONESEARCH_OPTIONS;
var INVALID_QUERIES = [""];
var PROCESSING = false;

/*
 * jQuery plugin for implementing OneSearch on the specified form.
 *
 * Usage: jQuery(selector).onesearch(options);
 * selector is the jQuery selector to the form submit button.
 * options are key/value pairs of options to the plugin.
 *
 * This plugin has a dependency on the jquery.autocomplete plugin.
 * 
 * options.highlight: The function that gets called when an item is highlighted.
 *
 */
jQuery.fn.onesearch = function(options) {
	setupOptions(options);
	jQuery(this).bind("submit", getSeoPath);
	jQuery('#btnSearch').bind("click", getSeoPath);
    jQuery('#user_search').keypress(function (event) {
        if (event.keyCode == 13) {
            getSeoPath();
            return false;
        }
    });

};


/*
 * jQuery plugin for adding autocomplete functionality on the
 * specified input field.
 *
 * Usage: jQuery(selector).onesearch(options);
 * selector is the jQuery selector to the form submit button.
 * options are key/value pairs of options to the plugin.
 *
 * This plugin has a dependency on the jquery.autocomplete plugin.
 *
 * options.highlight: The function that gets called when an item is highlighted.
 * 
 */
jQuery.fn.oneautocomplete = function(options) {
    //console.log('here');
	setupOptions(options);
        jQuery("body").append("<input type='hidden' id='seopath'/>");
        jQuery("body").append("<input type='hidden' id='geocode'/>");
        jQuery("body").append("<input type='hidden' id='radius'/>");
        jQuery("body").append("<input type='hidden' id='sortfield'/>");
        jQuery(this).autocomplete(ONESEARCH_URL + "/autocomplete?callback=?", {
		dataType: "json",
    highlight: options.highlight, 
    minChars: 3, 
    delay: 200, 
    cacheLength: 1000,
    maxItemsToShow: 10,
		matchSubset: 1,
		matchContains: 0,
    onSelect: selectLocation }).result(function(event, item) {
        jQuery(this).attr("value", item[0]);
        jQuery("#seopath").attr("value", item[1]);
        jQuery("#geocode").attr("value", item[2]);
        jQuery("#radius").attr("value", item[3]);
        jQuery("#sortfield").attr("value", item[4]);
		PROCESSING = true;
	});
};

/*
 * This object represents a search via OneSearch.
 * 
 * controller: The LocationsController that encapsulates the ajax call 
 *             to the controller on the server side.
 */
Search = function(controller) {
	this.controller = controller;
};

/*
 * Executes a search for a seo path based on the supplied query or dimension id.
 * 
 * query: The user entered search query
 * dimensionId: The N= value of the dimension, known if this was autocompleted.
 *
 */
Search.prototype.execute = function(query) {
	var newQuery = query.replace(/=/g, '');
  if (this.invalid(query)) {
    jQuery("body").trigger({ type: "onesearch-error-invalid", query: query });
    return false;
  }
	this.controller.seoPath(newQuery);
};

/*
 * Will return true if the query is suggestion text or empty.
 *
 * query: The search query to examine.
 * 
 */
Search.prototype.invalid = function(query) {
  if (jQuery.inArray(query, INVALID_QUERIES) >= 0) {
    return true;
  }
  return false;
};

/*
 * This object provides the interface to the OnesearchService 
 * on the server and all communication between the client and 
 * server via AJAX.
 *
 * channel: The channel to search in.
 *
 */
OnesearchService = function(channel) {
	this.channel = channel;
};

/*
 * Retrieves the seo_path for the provided query or dimension id.
 *
 * query: The user entered search query
 * dimensionId: The N= value of the dimension, known if this was autocompleted.
 * 
 */
OnesearchService.prototype.seoPath = function(query) {
	var self = this;
	jQuery.getJSON(ONESEARCH_URL + "/seopath?callback=?", { q: query, channel: this.channel, application: APPLICATION }, function(response) {
		if (response.seopath) {
			self.handleSuccess(response);
		} 
		else {
			self.handleError(response);
		}
	});
};

/*
 * This function gets fired when the search returns a seo path
 * successfully. It will in turn fire the success event for the 
 * application to handle accordingly.
 *
 * seoPath: The seo path returned from the service.
 *
 */
OnesearchService.prototype.handleSuccess = function(response) {
  var seoPath = response.seopath;
	// TODO: Need to change the name of the form.
	jQuery("#search_form").unbind("submit", getSeoPath);
	jQuery("body").trigger({ type: "onesearch-success", seoPath: seoPath, query: response.query, geocode: response.geocode, radius: response.radius, sortfield: response.sortfield });
	PROCESSING = false;
};

/*
 * This function gets fired when the search returns an error, 
 * currently this will happen if there are no results from the search.
 *
 * response: The error response from the server.
 *
 */
OnesearchService.prototype.handleError = function(response) {
	jQuery("body").trigger({ type: "onesearch-error-noresults", message: response.message, query: response.query });
	PROCESSING = false;
};

/*
 * This function sets up the global options "hash" for OneSearch.
 * If the options have already been set, it will ignore them.
 *
 * options.highlight: The function that gets called when an item is highlighted.
 *
 */
setupOptions = function(options) {
	if (!ONESEARCH_OPTIONS) {
		ONESEARCH_OPTIONS = options;
	}
};

/*
 * This function is called when the user selects an item from 
 * the autocomplete list - will trigger the success event with the seo path.
 *
 */
selectLocation = function() {
    var seoPath = jQuery("#seopath").attr("value");
    var geoCode = jQuery("#geocode").attr("value");
    var radius = jQuery("#radius").attr("value");
    var sortField = jQuery("#sortfield").attr("value");
    var query = jQuery("#user_search").attr("value");
    jQuery("#search_form").unbind("submit", getSeoPath);
    jQuery("body").trigger({ type: "onesearch-success", seoPath: seoPath, query: query, geocode: geoCode, radius: radius, sortfield: sortField });
    PROCESSING = false;
};


/*
 * Creates a new Search and retrieves the seo path for the users
 * selection in the autocomplete or value in the search box.
 *
 */
getSeoPath = function() {
  if (!PROCESSING) { 
  	PROCESSING = true;
  	var query = jQuery("#user_search").attr("value");
  	new Search(new OnesearchService(channel)).execute(query);
  }
  else {
    selectLocation();
  }
  return false;
};var channel = "apartments";
var valid_key = false;
var default_records_per_page = 20;
var dummy_search_options = ['Price-Range','Bedrooms','Bathrooms'];

$(document).ready(function(){
    do_eraseCookies();
    $("form#aspnetForm").unbind('submit');
    $("#aspnetForm").attr("action", "/");
	$("input#user_search").oneautocomplete({ highlight: highlightItem });
    $("#search_form").onesearch();

    $("body").bind("onesearch-success", onesearchSuccess);
    $("body").bind("onesearch-error-noresults", onesearchNoResults);
    $("body").bind("onesearch-error-invalid", onesearchInvalid);
    
    $("#osClear").bind("click", InitControl);
    
	INVALID_QUERIES = ["City, State or Zip", "College, State", "Military Base, State", ""];

    var savedVal = "";
    if ($('#overrideInit').val()) {
        savedVal = $('#hdn_init').val();
    }
    else {
        savedVal = readCookie("user.search");
    }
	if (!savedVal) {
	    savedVal = $('#hdn_init').val();
        if ((savedVal==="undefined")||(!savedVal)) {
            savedVal = "";
        } 
	}
    var vals = savedVal.match(/.*(\d{5,5})/);
    if(vals != null && vals[1] != null) {
	    savedVal = vals[1];
	}
    if ($('#blankOneSearch').val()) {
        savedVal = "";
    }
	$("input#user_search").val(savedVal);

});

function highlightItem(value, term) {
  return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + term.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi, "\\$1") + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong>$1</strong>");
}

function exists(value) {
  return ((value != null) && (value.length > 0) && ($.inArray(value, dummy_search_options) == -1) );
}

function GetRefinements() {
    if (!$("[id$='_searchRefinement']").length) {
        return "";
    }

    var seoText = "";
    var endecaIds = "";
    var vals = [];
    
    if ($("[id$='_propertyTypes']").length) {
        if ($(".property_types input[type=checkbox][checked]").length != $(".property_types input[type=checkbox]").length) {
            $(".property_types input[type=checkbox][checked]").each(function(){
                vals.push([this.value, this.id.replace("_CheckBox","") + "-", ""]);
            }); 
        }
    }
    
    var ctrl = $("#pricerange");
    if (ctrl.val() != "-1") {
        vals.push([ctrl.val(), ctrl.find('option').filter(':selected').text().replace(new RegExp("\\$", "g" ), ""), "Price-Range-"]);
    }

    ctrl = $("#bedrooms");
    if (ctrl.val() != "-1") {
        vals.push([ctrl.val(), ctrl.find('option').filter(':selected').text(), "Beds-"]);
    }

    ctrl = $("#fullbaths");
    if (ctrl.val() != "-1") {
        vals.push([ctrl.val(), ctrl.find('option').filter(':selected').text(), "Baths-"]);
    }
    
    var sep = "";
    $(vals).each(function(index, value){
	    endecaIds += sep + value[0];
	    seoText += value[1] + ((value[2] != "") ? "-" + value[2] : "");
        sep = "+";
    }); 
    if (sep != "") {
        endecaIds += "/";
    }
    return seoText + endecaIds;
}
 
function InitControl() {
    $("input#user_search").val("");
} 
      
function onesearchSuccess(event) {
   var search_val = $("#user_search").val();
    createCookie("user.search", search_val);
   //if the search_val contains 5 digits (a possible zip code), replace the field value with just the 5 digits
	var vals = search_val.match(/.*(\d{5,5})/);
	if(vals != null && vals[1] != null) {
		search_val = vals[1];
		$("#user_search").val(search_val);
	}
    var post_url = (event.seoPath.substring(0, 1) == "/") ? event.seoPath : "/" + event.seoPath;
    CalldcsMultiTrack();
    do_redirect(post_url + GetRefinements());
    //do_submitForm(post_url + GetRefinements());
}
function do_redirect(url){
    do_setCookies();
    if ($('#isaptdomain').val().toLowerCase() == 'true') {
        url = url.replace('/Rental-Listings', '');
    }
    window.location.href = url;
}
function do_submitForm(url){
    var submitForm = getNewSubmitForm();
    createNewFormElement(submitForm, "geocode", jQuery("#geocode").val());
    createNewFormElement(submitForm, "radius", jQuery("#radius").val());
    createNewFormElement(submitForm, "sortfield", jQuery("#sortfield").val());
    submitForm.action= url;
    submitForm.submit();
}
function do_setCookies() {
    createCookie("geocode", jQuery("#geocode").val());
    createCookie("radius", jQuery("#radius").val());
    createCookie("sortfield", jQuery("#sortfield").val());
}
function do_eraseCookies() {
    eraseCookie("geocode");
    eraseCookie("radius");
    eraseCookie("sortfield");
}
function onesearchNoResults(event) {
	searchErrorMessage(event.message);
}

function onesearchInvalid(event) {
	searchErrorMessage("You must enter a city, state or a zip code before this search can be performed.");
}

function searchErrorMessage(message){
    $("#searchErrors").text(message).show();
    $("body").bind('click.searchErrors', function(){
        $("#searchErrors").hide();
        $("body").unbind('click.searchErrors');
    });
}
function createCookie(name,value,days) {
	if (days) {
		var date = new Date();
		date.setTime(date.getTime()+(days*24*60*60*1000));
		var expires = "; expires="+date.toGMTString();
	}
	else {
	    var expires = "";
	}
	var val = escape(value);
	if(name=="user.search")
	    document.cookie = name+"="+val+expires+";domain=.rentals.com;";
	else
	    document.cookie = name+"="+val+expires+"; path=/";
}

function readCookie(name) {
	var nameEQ = name + "=";
	var ca = document.cookie.split(';');
	for(var i=0;i < ca.length;i++) {
		var c = unescape(ca[i]);
		while (c.charAt(0)==' ') c = c.substring(1,c.length);
		if (c.indexOf(nameEQ) == 0) { 
		    return c.substring(nameEQ.length,c.length);
		}
	}
	return null;
}

function eraseCookie(name) {
	createCookie(name,"",-1);
}

function CalldcsMultiTrack(){
    var clickValue = $("input#typed").val();
    var selSearch = $("#user_search").val();
    dcsMultiTrackClick('DCS.dcsuri', 'Multitrack', 'DCSext.clicktype', 'search', 'DCSext.clickvalue', clickValue, 'DCSext.search', clickValue, 'DCSext.selsearch', selSearch);
}

//helper function to create the form
function getNewSubmitForm(){
    var submitForm = document.createElement("FORM");
    document.body.appendChild(submitForm);
    submitForm.method = "POST";
    return submitForm;
}

//helper function to add elements to the form
function createNewFormElement(inputForm, elementName, elementValue){
    var newElement = document.createElement("<input name='"+elementName+"' type='hidden'>");
    inputForm.appendChild(newElement);
    newElement.value = elementValue;
    return newElement;
}