// <script>
var dbg = {}

var MyGMap = function (config) {
  	var loading = document.getElementById("loading")
  	
    o = new GMap2(document.getElementById(config["map_id"]));
    var self = o;
    
	o.addControl(new GMapTypeControl());
    o.addControl(new GLargeMapControl());
    o.addControl(new GScaleControl());
    o.addControl(new GOverviewMapControl());
	o.setCenter(new GLatLng(config["y"], config["x"]), config["zoom"]);
		

	/**
	* @var MyGMapControler
	*/
	o.controler = new MyGMapControler(config["server_url"]);
//	dump("controler: " + o.controler.serverUrl);
	
	/**
	* @var Boolean
	*/
	o.usePaging;
	
	/**
	* @var HTMLElement
	*/
	o.grid;
	
	o.controlType = config["type"];
	
	if (o.controlType == "mapgrid") {
        o.grid = document.getElementById(config["grid_id"]);
        o.usePaging = true;
	}
	else {
        o.usePaging = false;
	}

	o.loadingPane = loading;

	
	var resultFilter = ResultFilter.create();
	o.resultFilter = resultFilter;
	
	
	// Methods
	
	o.moveTo = function(x, y)
	{
	    o.setCenter(new GLatLng(y, x), config["zoom"]);    
	}
	
    /**
    * @param Listing listing
    */
    o.addListing = function (l) {
        
        //debug('ENTER addListing()');
        //dump("addListing ("+listing.getProperty("lat")+", "+listing.getProperty("lng")+")");
        var html = '<table border="0" cellspacing="1" cellpadding="1">' +
                        '<tr><td colspan="2" nowrap="nowrap"><div class="gm_title">' + 
                            '<a target="_blank" href="' + l.getProperty('details_url') + '">' + l.getProperty('title').wordwrap(40) + '</a>' +
                            '</div>' +
                        '</tr>' +
                        '<tr valign="top"><td>' +
                            '<a target="_blank" href="' + l.getProperty('details_url') + '">' + 
                                '<img align="left" style="margin-right: 10px" border="0" height="90" src="' + l.getProperty('src') +'">' + 
                            '</a></td>' +
                            '<td align="left">' + 
                                "<div class='gm_addr'>" + l.getProperty('addr')+"</div>" +
                                "<div class='gm_text'><nobr>Ref ID: " + l.getProperty('refid') + "</nobr></div>" +
                                "<div class='gm_text'>" + l.getProperty('bed') + "</div>" +
                                "<div class='gm_text'>" + l.getProperty('bath') + "</div>" +
                                "<div class='gm_price'><nobr>Price: " + l.getProperty('price') + "</nobr></div>" +
                            '</td></tr></table>';
        
//        var html = "<p><a target=_blank href="+l.getProperty('details_url') +">" + 
//                        l.getProperty('title').wordwrap(40) + "</a></p>" + 
//                   "<p><strong>"+l.getProperty("price")+"</strong></p>" + 
//                   "<p><em>"+l.getProperty("addr")+"</em></p>";
        
        var point = new GLatLng(l.getProperty("lat"), l.getProperty("lng"));
        
        var marker = self.createMarker (point, html, l.getProperty("id"));
        self.addOverlay(marker);
        //debug('LEAVE addListing()');
    }
    
    o.createMarker = function (point, html, id) {

        var icon = new GIcon();
//http://www.google.com/mapfiles/marker.png
//        icon.image = "http://labs.google.com/ridefinder/images/mm_20_red.png";
//        icon.shadow = "http://labs.google.com/ridefinder/images/mm_20_shadow.png";
//        icon.iconSize = new GSize(12, 20);
//        icon.shadowSize = new GSize(22, 20);
//        icon.iconAnchor = new GPoint(6, 20);
        icon.image = "http://www.google.com/mapfiles/marker.png";
        icon.shadow = "http://www.google.com/mapfiles/shadow50.png";
        icon.iconSize = new GSize(20, 34);
        icon.shadowSize = new GSize(37, 34);
        icon.iconAnchor = new GPoint(6, 1);
        icon.infoWindowAnchor = new GPoint(5, 1);	    
	    
	    var marker = new GMarker(point, icon);
//	    var marker = new GMarker(point);
        GEvent.addListener(marker, "click", function () {
            marker.openInfoWindowHtml(html);
        });
        
        GEvent.addListener(marker, "infowindowopen", function () {
            self.focusedOverlay = marker;
        });
        GEvent.addListener(marker, "infowindowclose", function () {
            self.focusedOverlay = null;
        });
        
	    return marker;
	},
    
    o.showLoading = function () {
        debug('ENTER showLoading()');
        if (self.loadingPane) {
            self.loadingPane.style.visibility = "visible";
        }
        debug('LEAVE showLoading()');
    }
    
    o.hideLoading = function () {
        debug('ENTER hideLoading()');
        if (self.loadingPane) {
            self.loadingPane.style.visibility = "hidden";
        }
        debug('LEAVE hideLoading()');
    }
    
    o.getPagingOffset = function () {
    }
    
    o.getPagingQuantity = function () {
    }

    
    o.repaint = function () {
//        dump("repaint !!!");
        debug('ENTER repaint()');
    	self.clearOverlays();
        self.controler.getListings(self);
        debug('LEAVE repaint()');
    }
    
    // Event listeners

	GEvent.bind(o.resultFilter, "repaintmap", o, o.repaint);    
    
    o.onMoveEnd = function () {
        if (! self.focusedOverlay) {
        	self.repaint();
        }
    }
    
    o.onCloseInfoWindow = function () {
    }
	
	GEvent.addListener(o, "dragend", o.onMoveEnd);
	GEvent.addListener(o, "zoomend", o.onMoveEnd);
	GEvent.addListener(o, "closeinfowindow", o.onCloseInfoWindow);

    
    
	// Request map controler for listings portion
	o.controler.getListings (o);
	
	return o;
}


// end of MyGMap definition

// Split a string s at all occurrences of character c. This is like
// the split() method of the string object, but IE omits empty
// strings, which violates the invariant (s.split(x).join(x) == s).
function stringSplit(s, c) {
  var a = s.indexOf(c);
  if (a == -1) {
    return [ s ];
  }
  
  var parts = [];
  parts.push(s.substr(0,a));
  while (a != -1) {
    var a1 = s.indexOf(c, a + 1);
    if (a1 != -1) {
      parts.push(s.substr(a + 1, a1 - a - 1));
    } else {
      parts.push(s.substr(a + 1));
    } 
    a = a1;
  }

  return parts;
}






function ResultFilter () {
    debug('ENTER ResultFilter()');
	var source = document.forms["resultFilter"];
	if (source) {
		this.args = {};
		
		debug('Getting price');
		var priceFilter = source.elements["price"];
		GEvent.bindDom(priceFilter, "change", this, this.filter);
		this.priceFilter = priceFilter;
		
		debug('Getting bedrooms');
		var bedroomsFilter = source.elements['bedrooms'];
		GEvent.bindDom(bedroomsFilter, "change", this, this.filter);
		
		debug('Getting house');
		var houseFilter = source.elements['house'];
		GEvent.bindDom(houseFilter, "change", this, this.filter);
		this.houseFilter = houseFilter;
		
		debug('Getting market');
		//var marketFilter = source.elements["market"];
		debug('Invoke document.getElementsByName()');
		var marketFilter = document.getElementsByName("market");
		debug('Returned from document.getElementsByName()');
		for (var i=0; i<marketFilter.length; i++) {
		    debug('* marketFilter.item(i) - ' + i);
			var m = marketFilter.item(i);
			GEvent.bindDom(m, "click", this, this.filter);
		}
		this.marketFilter = marketFilter;
	}
	else {
		throw "resultFilter widget not found";
	}
    debug('LEAVE ResultFilter()');
}

ResultFilter.create = function () {
	return new ResultFilter();
}

ResultFilter.prototype.filter = function () {
	debug('ENTER ResultFilter.filter()');
	var args = {};

	var price = this.priceFilter.value;
	if (typeof price != "undefined") {
		var v = stringSplit(price, "-");
		args["minprice"] = v[0] || "";
		args["maxprice"] = v[1] || "";
	}

    if (0 == for_status)
    {
        args['minprice'] = '';
        args['maxprice'] = '';
    }
	
	for (var i=0; i<this.marketFilter.length; i++) {
		var m = this.marketFilter[i];
		if (m.checked) {
			args["rentorsale"] = m.value;
		}
	}
	
	args['house'] = this.houseFilter.value;

	this.args = args;
//	dump("trigger ResultFilter repaintmap");
	GEvent.trigger(this, "repaintmap");
	debug('LEAVE ResultFilter.filter()');
}


var MyGMapControler = function (serverUrl) {this.__construct(serverUrl)}
MyGMapControler.prototype = {
    
    serverUrl : null,
    
    __construct : function (serverUrl) {
        this.serverUrl = serverUrl;
    },
    
    abortLoader : function () {
    	if (this.loader) {
			this.loader.cont = false;
		}
    },
    
    registerLoader : function (loader) {
    	this.loader = loader;
    },
    
    /**
    * @param MyGMap map
    */
    getListings : function (map) {
        debug('ENTER getListings()');
        this.abortLoader();
        var responseParser = new ResponseParser();        
        
        var loader = new ListingsLoader (this.serverUrl);
        this.registerLoader(loader);
        var b = map.getBounds();
        var d = document;

        loader.setArgs({"minx":b.getSouthWest().lng(), "miny":b.getSouthWest().lat(), "maxx":b.getNorthEast().lng(), "maxy":b.getNorthEast().lat(), 
                        "beds":d.getElementById('bedrooms').value});
                        
        var p = d.getElementById('prices');
        var txt = p.options[p.selectedIndex].text;
        
        
        //by SJ
//        if (false == select_changed || 0 == for_status) {
            for_status = document.getElementById('for_sale').checked + 1;
            xajax_getPrices(for_status, b.minX, b.minY, b.maxX, b.maxY, d.getElementById('bedrooms').value, d.getElementById('house').value, txt);
//        }
//        else {
            select_changed = false;
//        }
        //end
        
        var filterArgs = map.resultFilter.args;
        for (var p in filterArgs) {
        	loader.addArg(p, filterArgs[p]);
        }
        
        if ( map.usePaging ) {
            var listingNodes = loader.syncLoad(responseParser, map.getPagingOffset(), map.getPagingQuantity());
            for (var i=0; i<listingNodes.length; i++) {
                var listing = new Listing(listingNodes[i]);
                map.addListing(listing);
            }
            map.setPagingOffset(loader.getOffset());
            map.setPagingTotal(loader.getTotal());
            map.setPagingQuantity(loader.getQuantity());
        }
        else {
            
            loader.setQuantity (25);
//			loader.setOffset (0);
            var self = this;
            
            var asyncHandler = function (listingNodes) {
                
                //dump("processResponse");
                
				if (loader.continueLoading()) {
					for (var i=0; i<listingNodes.length; i++) {
						var listing = new Listing(listingNodes[i]);
						map.addListing(listing);
					}
				}
                
                if (loader.hasMore()) {
					if (loader.continueLoading()) {
//						dump ("continue query...")
//						dump (loader.buildQueryString());
						
						loader.asyncLoad(responseParser, null, null, asyncHandler);
					}
                }
                else {
                    map.hideLoading();
                }
            };
            
            map.showLoading();
//            dump("query ...");
//            dump (loader.buildQueryString());
            loader.asyncLoad(responseParser, null, null, asyncHandler);
        }
        
        debug('LEAVE getListings()');
    }
}


//////////////////////////////////////////////////////////////////////////
// ResponseParser object
//

var ResponseParser = function () {}
ResponseParser.prototype = {
    xml : null,
    
    listingsNode : null,
    
    setXml : function (xml) {
        this.xml = xml;
        this.listingsNode = xml.getElementsByTagName("listings")[0];
    },
    
    hasContent : function () {
        return this.xml != null;
    },
    
    getTotal : function () {
        if (this.hasContent()) {
            return parseInt(this.listingsNode.getAttribute("total"), 10);
        }
        throw "ResponseParser has no content";
    },
    
    getOffset : function () {
        if (this.hasContent()) {
            return parseInt(this.listingsNode.getAttribute("offset"), 10);    
        }
        throw "ResponseParser has no content";
    },

    getTime : function () {
        if (this.hasContent()) {
            return parseInt(this.listingsNode.getAttribute("time"), 10);    
        }
        throw "ResponseParser has no content";
    },
    
    getListings : function () {
        if (this.hasContent()) {
            return this.listingsNode.getElementsByTagName("listing");
        }
        throw "ResponseParser has no content";
    }
}

// end of ResponseParser definition


//////////////////////////////////////////////////////////////////////////
// ListingsLoader object
//

var ListingsLoader = function (serverUrl) {this.__construct(serverUrl)}
ListingsLoader.prototype = {

    serverUrl : null,
    
    args : {},

    offset : null,
    
    nextOffset : null,
    
    quantity : null,
    
    total : null,
    
    __construct : function (serverUrl) {
        this.serverUrl = serverUrl;
        this.setQuantity(25);
        this.nextOffset = 0;
        this.cont = true;
    },
    
    continueLoading : function () {
//    	dump("continueLoading: " + this.cont);
//		dump(this.buildQueryString());
    	return Boolean(this.cont);
    },

    setArgs : function (args) {
        this.args = args;
    },
    
    addArg : function (name, value) {
        this.args[name] = value;
    },
    
    removeArg : function (name) {
        delete this.args[name];
    },
    
    setQuantity : function (q) {
        this.quantity = q;
    },
    
    getQuantity : function () {
        return this.quantity;
    },
    
    setOffset : function (o) {
        this.offset = o;
        this.nextOffset = this.offset + this.quantity;
    },
    
    getOffset : function () {
        return this.offset;
    },
    
    getTotal : function () {
        return this.total;
    },
    
    buildQueryString : function () {
		var query = new Array();
	    
		for (var k in this.args) {
            var v = this.args[k];
            query.push(k.toString() + "=" + v.toString());
		}
		
		query.push("_o=" + this.offset);
		query.push("_q=" + this.quantity);
		
		var query_str = this.serverUrl + "?" + query.join("&");
		debug(query_str);
		return query_str;
    },
    
    syncLoad : function (responseParser, offset, quantity) {
        if (quantity) { this.setQuantity(quantity); }
        if (offset) { this.setOffset(offset); }
        
        var client = new HttpClient();
        try {
            client.call("GET", this.buildQueryString());
            var xml = client.getResponseXml();
            responseParser.setXml(xml.documentElement);
            this.total = responseParser.getTotal();
            this.setOffset(this.nextOffset);
            
            return responseParser.getListings();
        }
        catch (e) {
            // 
            alert(e);
        }
    },
    
    asyncLoad : function (responseParser, offset, quantity, handler) {
        if (quantity) { this.setQuantity(quantity); }
        if (offset) { this.setOffset(offset); }
        else {
            this.setOffset(this.nextOffset);
        }
        
        var client = new HttpClient();
        try {
            var self = this;
			
//			var d = new Date();
//			dump(d.toUTCString() + "; request");
//			dump("http://www.citycribs.com/map/" + this.buildQueryString());

            client.call("GET", dbg.requestURI = this.buildQueryString(), {
                onOpen : function () {
                    //dump("XMLHTTPRequest.open() has just been called");
                },
                onSend : function () {
                    //dump("XMLHTTPRequest.send() has just been called");
                },
                onProgress : function () {
                    //dump("Fetching response from server in progress");
                },
                onAbort : function () {
                    //dump("Request timeout. Abort");
                    // HACK !!!
                    // give asyncLoad() new param 'failedHandler' ? -- Ivan
                    window.mygmap.hideLoading();
                },
                onLoad : function (responseText, responseXml) {
                    try {
                        var xml = client.getResponseXml();
                        if (xml === null) alert('responseXML is not received or parsed')
                        responseParser.setXml(xml.documentElement);
                        
                        self.total = responseParser.getTotal();
                        self.setOffset(responseParser.getOffset());
                        
    					var lsts = responseParser.getListings()
                        handler(lsts);
					}
					catch (e) {
                        alert(e)
						dump("error: " + e);
					}
                }
            });
            
            return ;
        }
        catch (e) {
            // 
            alert(e);
        }
    },
    
    /*
    head : function () {
        this.addArg ("_head", 1);
        var client = new HttpClient();
        try {
            client.call("GET", this.buildQueryString());
            var xml = client.getResponseXml();
            this.removeArg("_head");
            return xml.documentElement;
        }
        catch (e) {
            alert (e);
        }
    },
    */
    
    hasMore : function () {
        if (this.total == null) {
            // Total not initialized. No request was sent
            return true;
        }
        
        return (this.nextOffset < this.total && this.nextOffset < 100);
    }
}

// end of ListingsLoader definition


//////////////////////////////////////////////////////////////////////////
// Listing object
//

var Listing = function (xmlNode) {this.__construct(xmlNode)}
Listing.prototype = {
    
    props : {},
    
    parseInstructs : {
            "lat" : "float",
            "lng" : "float",
            "id"  : "int"
            // Default parse result is string value
        },
    
    __construct : function (xmlNode) {
        if (xmlNode) {
            this.createFromXml(xmlNode);
        }
    },
        
    createFromXml : function (xmlNode) {
        for (var i=0; i<xmlNode.childNodes.length; i++) {
            var node = xmlNode.childNodes.item(i);
            
            // Only element nodes to be processed
            if (node.nodeType != 1) continue;
            
            var propname = node.nodeName.toLowerCase();
            var propval  = xmlValue(node);
            
            var instruct = this.parseInstructs[propname];
            if (instruct != undefined) {
                switch (instruct) {
                    case "int":
                        propval = parseInt(propval, 10);
                        break;
                        
                    case "float":
                        propval = parseFloat(propval);
                        break;
                        
                    default:
                        break;
                }
            }
            
            this.setProperty(propname, propval);
        }
    },
    
    getProperty : function (prop) {
        return this.props[prop];
    },
    
    setProperty : function (prop, value) {
        this.props[prop] = value;
    }
}

// end of Listing definition



window.DOM_ELEMENT_NODE = 1;
window.DOM_ATTRIBUTE_NODE = 2;
window.DOM_TEXT_NODE = 3;
window.DOM_CDATA_SECTION_NODE = 4;
window.DOM_ENTITY_REFERENCE_NODE = 5;
window.DOM_ENTITY_NODE = 6;
window.DOM_PROCESSING_INSTRUCTION_NODE = 7;
window.DOM_COMMENT_NODE = 8;
window.DOM_DOCUMENT_NODE = 9;
window.DOM_DOCUMENT_TYPE_NODE = 10;
window.DOM_DOCUMENT_FRAGMENT_NODE = 11;
window.DOM_NOTATION_NODE = 12;

function xmlValue(node) {
  if (!node) {
    return '';
  }

  var ret = '';
  if (node.nodeType == DOM_TEXT_NODE ||
      node.nodeType == DOM_CDATA_SECTION_NODE ||
      node.nodeType == DOM_ATTRIBUTE_NODE) {
    ret += node.nodeValue;

  } else if (node.nodeType == DOM_ELEMENT_NODE ||
             node.nodeType == DOM_DOCUMENT_NODE ||
             node.nodeType == DOM_DOCUMENT_FRAGMENT_NODE) {
    for (var i = 0; i < node.childNodes.length; ++i) {
      ret += arguments.callee(node.childNodes[i]);
    }
  }
  return ret;
}
