
// **** CONSTANTS **** //
var MIN_LENGTH_PASSWORD = 5;

var REGEX_URL = /\b((https|http|ftp):\/\/)?([a-z]([a-z0-9\-_]*\.)+)([a-z]([a-z0-9\-_]*\.)+)[^ ]+\b/gi;
var REGEX_EMAIL = /\b([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+\b/gi;
var REGEX_PHONE = /\b((\+\d{1,3}(-| |.)?\(?\d\)?(-| |.)?\d{1,5})|(\(?\d{2,6}\)?))(-| |.)?(\d{3,4})(-| |.)?(\d{4})(( x| ext)\d{1,5}){0,1}\b/g;
var REGEX_TWITTER = /@([A-Za-z0-9_]+)/g;

var AJAX_ROOT = "roman";
var AJAX_ATTR_STATUS = "status";

var SORT_PRICE = "price";
var SORT_RECOMENDED = "recommended";
var SORT_SIZE = "size";
var SORT_LOCATION = "location";
var SORT_RATING = "rating";

var APT_SEARCH_ALL = "all";
var APT_SEARCH_FEATURED = "feat";


// array of keys as values, allows for more efficient value search without iteration.
function List() {

    var _items = [];
    var _length = 0;

    for (var i = 0, item = arguments[i]; item; item = arguments[++i]) {
        _items[item] = item;
        _length++;
    }

    this.add = function(val) {
        if (!this.contains(val))
            _length++;
        _items[val] = val;

    };

    this.addAll = function(arr) {
        for (var i=0, item = arr[0]; item; item = arr[++i])
            this.add(item);
        Log.info(_items);
    };

    this.contains = function(val) {
        return Utils.isDefined(_items[val]);
//        return (val in _items);
    };

    this.remove = function(val) {
        if (this.contains(val)) {
            delete _items[val];
            _length--;
        }
    };

    //returns and array
    this.values = function(sorter) {
        var retval = [];
        for (var key in _items)
            retval[retval.length] = key;
        if (sorter)
            retval.sort(sorter);
        return retval;
    };

    this.size = function() {
        return _length;
    };

    this.clear = function() {
        _items = [];
        _length = 0;
    };

    this.getLastItem = function() {
        var vals = this.values();
        return (vals.length > 0)? vals[vals.length - 1] : null;
    };

    this.getItems = function() {
        return _items;
    };

    this.toString = function() {
        return _items.toString();
    }
}

function checkAjaxResponse(xml) {

    try {

        var status = null;
        var rootNode = xml.getElementsByTagName(AJAX_ROOT)[0];
        if (Utils.isNotEmpty(rootNode))
            status = rootNode.getAttribute(AJAX_ATTR_STATUS);
        if (status != "1") {
            alert("Bad Response");
            Log.error("Ajax Response",request.responseText);
            return null;
        }
        var elapsed = rootNode.getAttribute("elapsed");
        if (elapsed)
            Log.info("request time = " + elapsed);
        return xml.getElementsByTagName(AJAX_ROOT)[0].childNodes;

    } catch (error) {
        Log.error("Ajax Response",error);

    }
    return null;
}


function getXMLHttpRequest() {
    if (window.XMLHttpRequest) {
        var xmlHttpReq = new XMLHttpRequest();
        if (xmlHttpReq.overrideMimeType)
            xmlHttpReq.overrideMimeType('text/xml');
        return xmlHttpReq;
    }
    return null;
}

function sendRequestNoResponse(url, params) {
    Log.debug("sendRequestNoResponse " + url);

    try {

        var req = getXMLHttpRequest();
        req.open("POST", url, true);
        req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
        req.setRequestHeader("X-Requested-With", "XMLHttpRequest");
        req.send(Utils.urlEncodeParameters(params));

    }
    catch (error) {
        this.handleError(error, "sendRequestNoResponse, url=" + url);
    }
}

var request = null;
function HttpRequest(requestUrl) {

    var _requestUrl = requestUrl;
    var _params = {};
    var _successFcn = null;
    var _failureFcn = null;
    var _timeoutID = null;
    var _requestTimeout = 60000;
    var _aborted = false;

    this.setParams = function(params) {
        _params = params;
    };

    this.setTimeout = function(to) {
        _requestTimeout = to;
    };

    this.onSuccess = function(fcn) {
        _successFcn = fcn;
    };

    this.onFailure = function(fcn) {
        _failureFcn = fcn;
    };

    this.getRequestUrl = function() {
        return _requestUrl;
    };

    this.sendRequest = function(queueItem) {

        Log.debug("HttpRequest.sendRequest to " + _requestUrl);
//        _queueItem = queueItem;

        try {

            if (Utils.isNull(request))
                request = getXMLHttpRequest();
            request.open("POST", _requestUrl, true);
            request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
            request.setRequestHeader("X-Requested-With", "XMLHttpRequest");

            var parent_this = this;
            request.onreadystatechange = function() {
                parent_this.onReadyStateChange(request);
            };
            _timeoutID = setTimeout(function() {
                parent_this.abort();
            }, _requestTimeout);

            request.send(Utils.urlEncodeParameters(_params));

        }
        catch (error) {
            this.handleError(error, "HttpRequest.sendRequest, url=" + _requestUrl);
        }
    };


    this.onReadyStateChange = function(request) {

//        if (Utils.isUndefined(request)) {
//            server.queue.executed();
//            return;
//        }

        if (request.readyState == 4) {

            try {

                if (_timeoutID)
                    clearTimeout(_timeoutID);

                if (request.status == 200) {

//                    Log.info("REQUEST " + _requestUrl + ":\n" + request.responseText);

                    try {

                        request.onreadystatechange = null;
                        if (Utils.isFunction(_successFcn)) {
                            Log.debug("success: " + _requestUrl);
                            _successFcn(request);
                        }

                    } catch (error) {
                        this.handleError(error, "HttpRequest.onReadyStateChange, url=" + _requestUrl);
                    }

                } else {

                    this.handleError("Response Code: " + request.status, "HttpRequest.onReadyStateChange, url=" + _requestUrl);
                }
            }
            finally {
//                server.queue.executed();
            }
        }
    };

    this.abort = function() {
        _aborted = true;
        request.abort();
        Log.info("HttpRequest.abort: " + _requestUrl);
    };

    this.handleTimeout = function() {
        Log.warn("HttpRequest.handleTimeout: " + _requestUrl);
        if (Utils.isNotEmpty(_failureFcn))
            _failureFcn("timeout");
    };

    this.handleError = function(error,logMsg) {
        Log.exception(error,logMsg);
        if (Utils.isNotEmpty(_failureFcn))
            _failureFcn(error);
    };

}



// **** UTILS **** //

var Utils = {

};

// set in main layout AFTER page load
Utils.aptImagePath = null;
Utils.language = null;

Utils.isUndefined = function(obj) {
    return (typeof obj == "undefined");
//    return (obj == "undefined" || typeof obj == "undefined");
};

Utils.isDefined = function(obj) {
    return !Utils.isUndefined(obj);
};

Utils.isNull = function(obj) {
    return (typeof obj == "object" && !obj);
};

Utils.isString = function(obj) {
    return (typeof obj == "string");
};

Utils.isNumber = function(obj) {
    return (typeof obj == "number" && isFinite(obj));
};

Utils.isBoolean = function(obj) {
    return (typeof obj == "boolean");
};

Utils.isFunction = function(obj) {
    return (typeof obj == "function");
};

Utils.isArray = function(obj) {
    return (typeof obj == "object" && obj.constructor == Array);
};

Utils.isDate = function(obj) {
    return (typeof obj == "object" && obj.constructor == Date);
};

Utils.isRegEx = function(obj) {
    return (typeof obj == "object" && obj.constructor == RegExp);
};


// returns true if state changed
Utils.show = function(obj) {
    if (Utils.isString(obj))
        obj = getObj(obj);
    var val = obj.style.display != "";
    obj.style.display = "";
    return val;
};

// returns true if state changed
Utils.hide = function(obj) {
    if (Utils.isString(obj))
        obj = getObj(obj);
    var val = obj.style.display != "none";
    obj.style.display = "none";
    return val;
};

Utils.write = function(div,txt) {
    getObj(div).innerHTML = txt;
};

Utils.breakFrames = function() {
    if (top.location != location)
        top.location.href = document.location.href;
};

Utils.emptyIfNull = function(str) {
    return (str)? str : "";
};

Utils.isEmpty = function(val) {
    return (Utils.isUndefined(val) || Utils.isNull(val) || val.length == 0);
};

Utils.isNotEmpty = function(val) {
    return !Utils.isEmpty(val);
};

Utils.isLocalhost = function() {
    return document.location.href.indexOf("local") != -1;
};

// trims whitespace from a string.
Utils.trim = function(str) {
	return str.replace(/^\s+|\s+$/g,"");
};

Utils.trimStart = function(str) {
    return str.replace(/^\s+/,"");
};

Utils.trimEnd = function(str) {
    return str.replace(/\s+$/,"");
};
Utils.addDaysToDate = function(date, days) {
    if (date == null)
        date = new Date();

    var addTime = date.getTime() + (days * (1000*60*60*24));
    date.setTime(addTime);
    return date;
};

Utils.toggleDisplay = function(obj) {
    obj = getObj(obj);
    if (obj)
        obj.style.display = (obj.style.display == "none")? "" : "none";
};

Utils.getTagValue = function(node, tagName) {
    var tag = node.getElementsByTagName(tagName)[0];
    if (!Utils.isEmpty(tag) && !Utils.isEmpty(tag.childNodes))
        return tag.childNodes[0].nodeValue;
    return null;
};

Utils.metersToFeet = function(mt) {
    return Math.round(mt* 10.76);
};


Utils.isValidUrl = function(str) {
    return Utils.isNotEmpty(str) && str.match(REGEX_URL);
};

Utils.isValidEmail = function(str) {
    return Utils.isNotEmpty(str) && str.match(REGEX_EMAIL);
};

Utils.isValidPassword = function(str) {
    return Utils.isNotEmpty(str) && str.length >= MIN_LENGTH_PASSWORD;
};


Utils.capitalize = function(str) {
    return str.charAt(0).toUpperCase() + str.substring(1);
};

Utils.addLoadEvent = function(func) {
    var oldonload = window.onload;
    if (typeof window.onload != 'function') {
        window.onload = func;
    } else {
        window.onload = function() {
            if (oldonload)
                oldonload();
            func();
        }
    }
};

function getObj(objId) {
    if (Utils.isString(objId))
        return document.getElementById(objId);
    return objId;
}

Utils.urlEncodeParameters = function(parameters) {
    var urlEncoded = "";
    for (var name in parameters) {
        if (urlEncoded.length > 0)
            urlEncoded += "&";
        urlEncoded += name + "=" + encodeURIComponent(parameters[name]);
    }
    return urlEncoded;
};

Utils.createDiv = function(id, className) {
    var div = document.createElement("div");
    if (!Utils.isNull(id))
        div.id = id;
    if (!Utils.isNull(className))
        div.className = className;
    return div;
};

Utils.formatCurrency = function(cost) {

    return Math.round(parseInt(cost)*100)/100;

};

Utils.timerTime = 0;
Utils.timerStart = function() {
    Utils.timerTime = new Date().getTime();
};

Utils.timerEnd = function() {
    return (new Date().getTime() - Utils.timerTime)/1000;
};

function pageUnload() {
    if (request != null)
        request.abort();
}


if (Utils.isDefined(window.onbeforeunload))
    window.onbeforeunload = pageUnload;
else
    window.onunload = pageUnload;



// **** LOG **** //

var LOG_ALWAYS = -1;
var LOG_EXCEPTION = 0;
var LOG_ERROR = 1;
var LOG_WARN = 2;
var LOG_INFO = 3;
var LOG_DEBUG = 4;

var Log = {
    txt:"",
    level:Utils.isLocalhost()? LOG_DEBUG : LOG_INFO,
    maxLength:200000,
    timer:null,
    levelDisplay:new Array("Exception","Error","Warn","Info","Debug"),
    logTextDivName:"logText",
    logDivName:"log"
};

Log.error = function(msg) {
    this.msg(LOG_ERROR,msg);
};
Log.error = function(msg, err) {
    this.msg(LOG_ERROR,msg + ", Error: " + err);
};
Log.warn = function(msg) {
    this.msg(LOG_WARN,msg);
};
Log.info = function(msg) {
    this.msg(LOG_INFO,msg);
};
Log.debug = function(msg) {
    this.msg(LOG_DEBUG,msg);
};
Log.always = function(msg) {
    this.msg(LOG_ALWAYS,msg);
};
Log.exception = function(error, msg) {
    this.msg(LOG_EXCEPTION, (Utils.isEmpty(error)? error.logMessage() : error) + ", " + msg);
};


Log.msg = function(level,msg) {

    if (level <= Log.level) {
        this.txt += this.dateString() + (level >= 0? " [" + this.levelDisplay[level] + "] " : "  ") + msg + "\n";
        if (this.txt.length > Log.maxLength)
            this.txt = this.txt.substring(this.txt.length - this.maxLength);
        if (document.getElementById(this.logTextDivName  ))
            document.getElementById(this.logTextDivName).value = this.txt;
    }
};

Log.clear = function() {
    this.txt = "";
    document.getElementById(this.logTextDivName).value = "";
};

Log.setLevel = function(lvl) {
    this.level = lvl;
    Log.always("Log level set to " + this.levelDisplay[lvl]);
};


Log.dateString = function(dt) {
    if (dt == null)
        dt = new Date();
    var dateStr = (dt.getHours() < 10) ? "0" : "";
    dateStr += dt.getHours() + ":";
    dateStr += (dt.getMinutes() < 10) ? "0" : "";
    dateStr += dt.getMinutes() + ":";
    dateStr += (dt.getSeconds() < 10) ? "0" : "";
    dateStr += dt.getSeconds();
    return dateStr;
};

Log.toggle = function() {
    Utils.toggleDisplay(getObj(this.logDivName));
};

Log.showCookies = function() {
    Log.always(unescape(document.cookie));
};

// ****************************** //
// **** Errors / Exceptions ***** //

Error.prototype.errorType = null;
Error.prototype.responseCode = null;

Error.prototype.logMessage = function() {
    return Utils.isDefined(this.name)
        ? this.name + ": " + this.message
        : this.message;
};

Error.prototype.displayMessage = function() {
    return this.message;
};

Error.prototype.getType = function() {
    return this.errorType;
};

Error.prototype.getResponseCode = function() {
    return this.responseCode;
};








function changeLanguage(lang) {

//    alert(
//        "Pathname: " + document.location.pathname  +"\n" +
//        "Host: " + document.location.host +"\n" +
//        "Hostname: " + document.location.hostname +"\n" +
//        "Protocol: " + document.location.protocol +"\n" +
//        "Search: " + document.location.search +"\n"
//            );

    var url = document.location.protocol + "//" + document.location.host; // hostname if issuses;
    url += "/" + lang;
//    var path = document.location.pathname;
//    if (Utils.isNotEmpty(path) && path.length > 3) {
//        path = path.substring(3);
//        url += path;
//    }
    document.location = url;

}



function submitCitiesSearch(formObj) {
    formObj.action = formObj.city.value + Utils.language + "/search";
    return true;
}


// **** Apartment Search **** //

var AptSearch = {
    apts : new Array(),
    apartmentSort : SORT_RECOMENDED,
    totalApartments : 0,
    useMap : false,
    loading : false,

    skipSearchUpdate : false,
    allAmenties : [],
    selectedAmenties : [],
    selectedAreas : [],
    apartmentMaxPrice : 0,
    apartmentMinRating : 0,
    apartmentBedrooms : null,
    apartmentBathrooms : null,
    apartmentVideo : false

};

//AptSearch.requestFeaturedApartments = function() {
//
//    Log.info("requestFeaturedApartments");
//    var req = new HttpRequest("/en/search");
//    var params = {
//        act:"featured"
//    };
//    req.setParams(params);
//    req.onSuccess(function() {
//
//        AptSearch.parseApartmentSearch(request.responseXML);
//        Log.info(request.responseText);
//    });
//    req.onFailure(function(str) {
//        alert(str);
//    });
//
//    req.sendRequest();
//};

AptSearch.requestApartments = function(start, search_type) {
    Utils.timerStart();
    Log.info("requestApartments, s=" + start);
    AptSearch.loading = true;
    var req = new HttpRequest("/en/search");
    var params = {
        act:search_type,
        s:start
    };
    req.setParams(params);
    req.onSuccess(function() {
        Log.info("RETURN TIME: " + Utils.timerEnd());
        try {
//            Log.info(request.responseText);
            Log.info("request returned, " + Utils.timerEnd());

            AptSearch.parseApartmentSearch(request.responseXML, search_type);

            Log.info("xml parsed, " + Utils.timerEnd());

            Log.info("search updated, " + Utils.timerEnd());

        } catch(error) {
            Log.error(error + "\n" + request.responseText);
        }
    });
    req.onFailure(function(str) {
        Log.error("requestApartments onFailure: " + str);
    });

    req.sendRequest();

};


AptSearch.requestUpdateSearchParam = function(searchParam, searchValue) {
    if (AptSearch.skipSearchUpdate)
        return;
    Log.info("requestUpdateSearchParam");
//    var req = new HttpRequest("/en/search");
    var params = {
        act:"update",
        sp:searchParam,
        sv:searchValue
    };
//    req.setParams(params);
//    req.onSuccess(function() {
//        Log.info(request.responseText);
//    });
//    req.onFailure(function(str) {
//        alert(str);
//    });
//
//    req.sendRequest();
    sendRequestNoResponse("/en/search", params);
};


AptSearch.parseApartmentSearch = function(xml, search_type) {

    AptSearch.loading = false;

    var apartmentsNode = checkAjaxResponse(xml)[0];

    var start = apartmentsNode.getAttribute("s");
    var end = apartmentsNode.getAttribute("e");
    var more = apartmentsNode.getAttribute("m");
    var total = apartmentsNode.getAttribute("t");
    Log.info("START " + start + "," + end + "," + more);


    var aptNodes = apartmentsNode.childNodes;
    var count = AptSearch.apts.length;
    if (aptNodes != null) {

        var apt;
        for (var i=0, aptNode = aptNodes[i]; aptNode ; aptNode = aptNodes[++i]) {

            apt = new Apartment();
            apt.id = aptNode.getAttribute(ATT_ID);
            apt.ref = aptNode.getAttribute(ATT_REF);
            apt.site = aptNode.getAttribute(ATT_SITE);
            apt.price = aptNode.getAttribute(ATT_PRICE);
            apt.price_day = aptNode.getAttribute(ATT_PRICE_DAY);
            apt.price_raw = parseFloat(aptNode.getAttribute(ATT_PRICE_RAW));
            apt.aptType = aptNode.getAttribute(ATT_APT_TYPE);
            apt.ib = aptNode.getAttribute(ATT_IB);
            apt.sqmt = parseFloat(aptNode.getAttribute(ATT_SQMT));
            apt.balconySqmt = parseFloat(aptNode.getAttribute(ATT_BALCONY_SQMT));
            apt.rooms = aptNode.getAttribute(ATT_ROOMS);
            apt.bedrooms = aptNode.getAttribute(ATT_BEDROOMS);
            apt.bathrooms = aptNode.getAttribute(ATT_BATHROOMS);
            apt.floor = aptNode.getAttribute(ATT_FLOOR);
            apt.sleeps_adults = aptNode.getAttribute(ATT_SLEEPS_ADULTS);
            apt.sleeps_children = aptNode.getAttribute(ATT_SLEEPS_CHILDREN);
            apt.office_rating = parseFloat(aptNode.getAttribute(ATT_OFFICE_RATING));
            apt.areakey = aptNode.getAttribute(ATT_AREAKEY);
            apt.overallGuestRating = parseFloat(aptNode.getAttribute(ATT_OVERALL_GUEST_RATING));
            apt.picture = aptNode.getAttribute(ATT_PICTURE);
            apt.hasVideo = aptNode.getAttribute(ATT_HAS_VIDEO) == 1;


            apt.aptName = Utils.getTagValue(aptNode,TAG_NAME);
            apt.area = Utils.getTagValue(aptNode,TAG_AREA);
            apt.street1 = Utils.getTagValue(aptNode,TAG_STREET1);
            apt.street2 = Utils.getTagValue(aptNode,TAG_STREET2);
            apt.postal = Utils.getTagValue(aptNode,TAG_POSTAL);
            apt.coords = Utils.getTagValue(aptNode,TAG_COORDS);

            var areaTag = aptNode.getElementsByTagName(TAG_AREA)[0];
            apt.areakey = areaTag.getAttribute(ATT_AREAKEY);

            var amenities = Utils.getTagValue(aptNode,TAG_AMENITIES);
            apt.amenitiesStr = amenities + ",";
            apt.amenities = amenities.split(",");

            AptSearch.apts[count] = apt;
            count++;
        }

    }

    if (more > 0) {
        AptSearch.requestApartments(end, search_type);
        AptSearch.showProgress(end, total)
    } else {
        AptSearch.sortApartments();
        getObj("search_loading").style.display = "none";
        getObj("search_results").style.display = "";
        AptSearch.updateRefinedSearch();
    }


};

AptSearch.showProgress = function(num, total) {
    if (getObj("meter") != null && total > 0) {
        Log.info(parseInt((num/total)*100) + "%");
        getObj("meter").style.width = parseInt((num/total)*100) + "%";
    }
};

AptSearch.showList = function() {
    Utils.show("search_list");
    Utils.hide("search_map");
};

AptSearch.showMap = function() {
    Utils.show("search_map");
    Utils.hide("search_list");
};

AptSearch.updateApartments = function(param, value) {

    if (getObj("search_number") != null) {

        if (AptSearch.useMap)
            Maps.clearMapApartments();

        var num = 0;
        for (var i=0, apt = AptSearch.apts[i]; apt; apt = AptSearch.apts[++i]) {
            if (AptSearch.matchesFilter(apt)) {
                getObj("apt" + apt.id).style.display = "";
                num++;
                if (AptSearch.useMap)
                    Maps.addApartment(apt);

            } else {
                getObj("apt" + apt.id).style.display = "none"
            }
        }
        getObj("search_number").innerHTML = (num > 0)? "Showing " + num + " of " + AptSearch.totalApartments +  " Apartments" : "No Apartments meet your criteria, please update your search.";

    }

    AptSearch.requestUpdateSearchParam(param, value);
};




var ATT_ID = "id";
var ATT_REF = "rf";
var ATT_SITE = "st";
var ATT_PRICE = "pr";
var ATT_PRICE_RAW = "prr";
var ATT_PRICE_DAY = "pd";
var ATT_APT_TYPE = "at";
var ATT_IB = "ib";
var ATT_SQMT = "sq";
var ATT_BALCONY_SQMT = "bs";
var ATT_ROOMS = "rm";
var ATT_BEDROOMS = "br";
var ATT_BATHROOMS = "ba";
var ATT_FLOOR = "fl";
var ATT_SLEEPS_ADULTS ="sa";
var ATT_SLEEPS_CHILDREN = "sc";
var ATT_OFFICE_RATING = "or";
var ATT_AREAKEY = "ak";
var ATT_OVERALL_GUEST_RATING = "gr";
var ATT_PICTURE = "pc";
var ATT_HAS_VIDEO = "vd";

var TAG_APARTMENT = "apt";
var TAG_NAME = "nm";
var TAG_AREA = "ar";
var TAG_STREET1 = "s1";
var TAG_STREET2 = "s2";
var TAG_POSTAL = "pc";
var TAG_COORDS = "co";
var TAG_AMENITIES = "am";

function Apartment() {

    var id = null;
    var ref = null;
    var price = null;
    var price_day = null;
    var site = null;
    var aptType = null;
    var ib = null;
    var sqmt = null;
    var balconySqmt = null;
    var rooms = null;
    var bedrooms = null;
    var bathrooms = null;
    var floor = null;
    var sleeps_adults = null;
    var sleeps_children = null;
    var office_rating = null;
    var areakey = null;
    var area = null;
    var overallGuestRating = null;
    var picture = null;
    var aptName = null;
    var street1 = null;
    var street2 = null;
    var postal = null;
    var coords = null;
    var hasVideo = false;
    var amenities = null;
    var amenitiesStr = null;

    this.getTitle = function(includeArea) {
        return "<b>Listing " + this.ref + (includeArea? " :: " + this.area : "" ) + " :: " + (this.name == null? this.street1 : this.name) + "</b>"
    };

    this.getRoomDescription = function() {
        return  (this.bedrooms == 0? "Studio" : this.bedrooms) + " Bedroom, " +
                (this.bathrooms == 0? "Shared Bathroom" : this.bathrooms + " Bathroom ") +
                "Apartment " + this.aptType;
    };

    this.getSleepsDescription = function() {
        return "Sleeps " + this.sleeps_adults +
                (this.sleeps_children > 0 ? " Adults &amp;" + this.sleeps_children + " Children" : "") +
                ", " + this.sqmt + " sqmt / "+ Utils.metersToFeet(this.sqmt) +" sqft";
    };


    this.toString = function() {
        return "Apartment[id=" + this.id +
               ",ref=" + this.ref +
               ",site=" + this.site +
               ",aptType=" + this.aptType +
                ",price=" + this.price +
                ",price_day=" + this.price_day +
                ",price_raw=" + this.price_raw +
               ",ib=" + this.ib +
                ",sqmt=" + this.sqmt +
                ",balconySqmt=" + this.balconySqmt +
                ",rooms=" + this.rooms +
                ",bedrooms=" + this.bedrooms +
                ",bathrooms=" + this.bathrooms +
                ",floor=" + this.floor +
                ",sleeps_adults=" + this.sleeps_adults +
                ",sleeps_children=" + this.sleeps_children +
                ",office_rating=" + this.office_rating +
                ",areakey=" + this.areakey +
                ",overallGuestRating=" + this.overallGuestRating +
                ",picture=" + this.picture +
                ",aptName=" + this.aptName +
                ",street1=" + this.street1 +
                ",street2=" + this.street2 +
                ",postal=" + this.postal +
                ",coords=" + this.coords +
                ",hasVideo=" + this.hasVideo +
                ",amenities=" + this.amenitiesStr +
               "]";
    };

    this.getLatLng = function() {
        if (Utils.isEmpty(this.coords))
            return null;
        var coord = this.coords.split(",");
        if (coord.length == 2)
            return {lat:coord[0],lng:coord[1]};
        return null;
    };

    this.addToMap = function() {

//        window.map.addShape(creatPoi(
//                this.street1,
//                "Description " + this.coords,
//                this.getLatitude(),
//                this.getLongitude()
//                ));
        
    };

}

AptSearch.matchesFilter = function(apt) {

    var i;

    if (AptSearch.apartmentBedrooms != null) {
        if (apt.bedrooms < AptSearch.apartmentBedrooms)
            return false;
    }

    if (AptSearch.apartmentBathrooms != null) {
        if (apt.bathrooms < AptSearch.apartmentBathrooms)
            return false;
    }

    if (AptSearch.apartmentVideo) {
        if (!apt.hasVideo)
            return false;
    }

    if (AptSearch.apartmentMaxPrice > 0) {
        if (apt.price_raw > AptSearch.apartmentMaxPrice)
            return false;
    }

    if (AptSearch.apartmentMinRating > 0) {
        if (apt.overallGuestRating < AptSearch.apartmentMinRating)
            return false;
    }

    if (AptSearch.selectedAreas.length > 0) {
        var hasArea = false;
        for (i=0;i<AptSearch.selectedAreas.length;i++) {
            if (AptSearch.selectedAreas[i] == apt.areakey) {
                hasArea = true;
                break;
            }
        }
        if (!hasArea)
            return false;
    }

    if (AptSearch.selectedAmenties.length > 0) {
        var hasAllAmenities = true;
        for (i=0;i<AptSearch.selectedAmenties.length;i++) {
            if (apt.amenitiesStr.indexOf(AptSearch.selectedAmenties[i]) == -1) {
                hasAllAmenities = false;
                break;
            }
        }
        if (!hasAllAmenities)
            return false;
    }

    return true;

};


AptSearch.createAptDiv = function(apt) {

    var aptDiv = Utils.createDiv("apt" + apt.id, "result_container");
    var content = getObj("apt_template").innerHTML;
    content = content.replace(/@id@/g,apt.id);
    aptDiv.innerHTML = content;

    getObj("search_list").appendChild(aptDiv);
    getObj("apt_title" + apt.id).innerHTML = apt.getTitle(true);

    var pic = "/picture/" + Utils.aptImagePath + apt.ref + "-1t.jpg";
    getObj("apt_pic" + apt.id).innerHTML = "<a href=\"\"><img src=\""+pic+"\" width=\"160\" height=\"120\"/></a>";


    var details = "<div style='float:left'><b>&euro;" + apt.price + "</b> (&euro;" + apt.price_day + " per night)</div>";
    details += "<div style='float:right'>Guest Rating: "+apt.overallGuestRating + " stars"+"</div>";
    details += "<div style='clear:both;'></div>";

    details += apt.getRoomDescription();
    details += "<br/>";
    details += apt.getSleepsDescription();
    details += "<br/>";

    details += "<b>Amenities:</b> ";
    var len = apt.amenities.length;
    for (var i=0;i<len;i++)
        details += this.allAmenties["amenity." + apt.amenities[i]] + ((len == i+1)? "" : ", ");
    details += "<br/>";

    getObj("apt_details" + apt.id).innerHTML = details;

};

AptSearch.sortApartments = function(val) {

    if (Utils.isNotEmpty(val))
        AptSearch.apartmentSort = val;

    AptSearch.apts.sort(AptSearch.doSortApartments);

    getObj("search_list").innerHTML = "";
    for (var i=0, apt = AptSearch.apts[i]; apt; apt = AptSearch.apts[++i]) {
        AptSearch.createAptDiv(apt);
        if (AptSearch.useMap)
            Maps.addApartment(apt);
    }
    AptSearch.updateApartments();
};

AptSearch.doSortApartments = function(a, b){

    if (AptSearch.apartmentSort == SORT_PRICE) {
        if (a.price_raw != b.price_raw)
            return a.price_raw > b.price_raw? -1 : 1;
    }
    else if (AptSearch.apartmentSort == SORT_SIZE) {
        if (a.sqmt != b.sqmt)
            return a.sqmt > b.sqmt? -1 : 1;
    }
    else if (AptSearch.apartmentSort == SORT_LOCATION) {
        if (a.area != b.area)
            return a.area < b.area? -1 : 1;
    }
    else if (AptSearch.apartmentSort == SORT_RATING) {
        if (a.overallGuestRating != b.overallGuestRating)
            return a.overallGuestRating > b.overallGuestRating? 1 : -1;
    }
    return a.office_rating > b.office_rating? -1 : 1;

};


AptSearch.checkApartmentPrice = function() {
    if (this.priceTimeout != null)
        clearTimeout(this.priceTimeout);
    this.priceTimeout = setTimeout(AptSearch.setApartmentPrice, 1000);
};


var SEARCH_BEDROOMS = "bed";
var SEARCH_BATHROOMS = "bath";
var SEARCH_VIDEO = "vid";
var SEARCH_MAX_PRICE = "price";
var SEARCH_MIN_RATING = "rate";
var SEARCH_AMENITIES = "amen";
var SEARCH_AREAS = "area";



AptSearch.updateRefinedSearch = function() {

    this.skipSearchUpdate = true;
    this.setApartmentPrice();
    this.bedroomsChanged();
    this.bathroomsChanged();
    this.videoChanged();
    this.ratingsChanged();
    this.amenityChanged();
    this.areaChanged();
    this.skipSearchUpdate = false;

};

AptSearch.setApartmentPrice = function() {

    var price = document.forms["apartment_search_refine"].maxprice.value;
    price = price.replace(/[^0-9]+/g, "");
    price = parseFloat(price);
    if (!isNaN(price))
        document.forms["apartment_search_refine"].maxprice.value = price;
    this.apartmentMaxPrice = (!isNaN(price))? price : 0;
    this.priceTimeout = null;
    this.updateApartments(SEARCH_MAX_PRICE,this.apartmentMaxPrice);
};

AptSearch.bedroomsChanged = function() {
    var val = document.forms["apartment_search_refine"].bedrooms.value;
    this.apartmentBedrooms = val == ""? null : parseInt(val);
    this.updateApartments(SEARCH_BEDROOMS,val);
};

AptSearch.bathroomsChanged = function() {
    var val = document.forms["apartment_search_refine"].bathrooms.value;
    this.apartmentBathrooms = val == ""? null : parseInt(val);
    this.updateApartments(SEARCH_BATHROOMS,val);
};

AptSearch.videoChanged = function() {
    this.apartmentVideo = document.forms["apartment_search_refine"].video.checked;
    this.updateApartments(SEARCH_VIDEO, this.apartmentVideo? "1" : "0");
};

AptSearch.ratingsChanged = function(val) {
    var rating = document.forms["apartment_search_refine"].minrating.value;
    this.apartmentMinRating = parseInt(rating);
    this.updateApartments(SEARCH_MIN_RATING, this.apartmentMinRating);

};

AptSearch.amenityChanged = function() {

    var amenityObjs = document.forms["apartment_search_refine"].amenities;
    this.selectedAmenties = [];
    var paramStr = "";
    for (var i=0, amenityObj = amenityObjs[i]; amenityObj; amenityObj = amenityObjs[++i]) {
        if (amenityObj.checked) {
            this.selectedAmenties[this.selectedAmenties.length] = amenityObj.value;
            paramStr += "amenity." + amenityObj.value + (i==amenityObjs.length-1? "" : ",");
        }
    }
    AptSearch.updateApartments(SEARCH_AMENITIES, paramStr);
};

AptSearch.areaChanged = function(isAll) {

    var areaObjs = document.forms["apartment_search_refine"].areas;
    this.selectedAreas = [];

    if (isAll) {

        this.selectedAreas = [];
        if (!areaObjs[0].checked) {

            areaObjs[0].checked = true;

        } else {

            this.selectedAreas = [];
            for (var i=1;i<areaObjs.length;i++)
                areaObjs[i].checked = false;
        }

    } else {

        areaObjs[0].checked = false;

        for (var i=1, areaObj = areaObjs[i]; areaObj; areaObj = areaObjs[++i]) {
            if (areaObj.checked) {
                this.selectedAreas[this.selectedAreas.length] = areaObj.value;
            }
        }

        if (this.selectedAreas.length == 0)
            areaObjs[0].checked = true;
    }

    AptSearch.updateApartments(SEARCH_AREAS, isAll? "" : this.selectedAreas.join(","));
};



// ***** MAPS ******

var Maps = {
    aptPois : null,
    areaPois : null
};

Maps.initMap = function() {

    AptSearch.useMap = true;

//MQA.EventUtil.observe(window, 'load', function() {

    window.map = new MQA.TileMap(getObj('map'), 10, {lat:41.895633, lng:12.480125}, 'map');

    MQA.withModule('zoomcontrol3','mousewheel', function() {

        window.map.addControl(
        new MQA.LargeZoomControl3(),
        new MQA.MapCornerPlacement(MQA.MapCorner.TOP_LEFT)
        );

        window.map.enableMouseWheelZoom();

        Maps.aptPois = new MQA.ShapeCollection();
        Maps.aptPois.collectionName = 'aptPois';
        Maps.areaPois = new MQA.ShapeCollection();
        Maps.areaPois.collectionName = 'areaPois';
        
//		map.setZoomLevel(13);
//		map.setMapType("hyb");



//		var basic=new MQA.Poi({lat:39.743943, lng:-105.020089});
//		basic.setBias({x:-50,y:-50});
//		map.addShape(basic);
//
//		var custom=new MQA.Poi( {lat:39.743943, lng:-105.020089} );
//		custom.setBias({x:50,y:50});
//		var icon = new MQA.Icon("smiley.png",32,32);
//		custom.setIcon(icon);
//		map.addShape(custom);
//
//		var info=new MQA.Poi({lat:39.743943, lng:-105.020089});
//		info.setBias({x:50,y:-50});
//		info.setInfoTitleHTML('Invesco Field');
//		info.setInfoContentHTML('Home of the Denver Broncos');
//		map.addShape(info);



    });
//});

};

Maps.clearMapApartments = function() {

    window.map.removeAllShapes();

};

Maps.addApartment = function(apt) {

    var latlng = apt.getLatLng();
    if (Utils.isEmpty(latlng)) {
        Log.error("Apt " + apt.id + " does not have lat/lon");
        return;
    }

    var title = "<div style=\"white-space:nowrap;background:#E0E0E0;padding:2px 5px;\">"+apt.getTitle(true)+"</div>";

    var pic = "/picture/" + Utils.aptImagePath + apt.ref + "-1t.jpg";
    var desc = "<div style=\"float:left;padding:5px 5px 5px 0\"><img src=\""+pic+"\" width=\"80\" height=\"60\"/></div>";
    desc += "<div style=\"white-space:nowrap;padding-top:5px;\"><b>&euro;" + apt.price + "</b> (&euro;" + apt.price_day + " per night)</div>";
    desc += "<div style=\"white-space:nowrap;\">Guest Rating" + apt.overallGuestRating + " stars</div>";
    desc += "<div style=\"white-space:nowrap;\">" + apt.getRoomDescription() + "</div>";
    desc += "<div style=\"white-space:nowrap;\">" + apt.getSleepsDescription() + "</div>";


//
//
//    details += "<div style='float:right'>Guest Rating: "+apt.overallGuestRating + " stars"+"</div>";
//    details += "<div style='clear:both;'></div>";
//
//    details += (apt.bedrooms == 0? "Studio" : apt.bedrooms) + " Bedroom, ";
//    details += (apt.bathrooms == 0)? "Shared Bathroom" : apt.bathrooms + " Bathroom ";
//    details += "Apartment " + apt.aptType;
//    details += "<br/>";
//
//    details += "Sleeps " + apt.sleeps_adults;
//    if (apt.sleeps_children > 0)
//        details += " Adults &amp;" + apt.sleeps_children + " Children";
//    details += ", " + apt.sqmt + " sqmt / "+ Utils.metersToFeet(apt.sqmt) +" sqft";
//    details += "<br/>";
//

    map.addShape(Maps.createMarker(title, desc, latlng));

};

Maps.createMarker = function(title,description,latlng) {
//    var poi = new MQA.Poi({lat:lat,lng:lng});
    var poi = new MQA.Poi(latlng);
//    poi.setDeclutter(true);
//    poi.setInfoTitleHTML(title);

    poi.setInfoTitleHTML("");
    poi.setInfoContentHTML("");
    poi.setRolloverContent(title + description);
    return poi;
};


