function toggleChecked(form, name, value)
{
    for (i=0; i<form.elements.length; i++) {
        var el = form.elements[i];
        if (el.name == name) {
            el.checked = value;
        }
    }
}


function countProperties(obj)
{
    var cnt = 0;
    for (var i in obj) cnt++;
    return cnt;
}


//
// adds handler to an element
// Ex.: addEventHandler(document.getElementById('input1'), 'change', function(){alert('preved')})
//

function addEventHandler(whom, event, handler)
{
    if (whom.addEventListener) {        //Firefox
        whom.addEventListener(event, handler, false);
    }
    else if (whom.attachEvent) {        //IE
        whom.attachEvent('on' + event, handler);
    }
    else {                              //HZ
        whom['on' + event] = handler;
    }
}


function populateInput(input, options)
{
    removeChildren(input);
    
    var op = document.createElement('option');
    op.value = 0;
    input.appendChild(op);
    
    for (i in options) {
        var op = document.createElement('option');
        var s = document.createTextNode(options[i]);
        op.appendChild(s);
        op.value = i;
        input.appendChild(op);
    }
}


function removeChildren(where)
{
    while (where.childNodes.length > 0) {
        where.removeChild(where.childNodes[0]);
    }
}


function createXmlHttpRequest()
{
    var req = null;
    if (window.XMLHttpRequest) req = new XMLHttpRequest();
    else if (window.ActiveXObject) req = new ActiveXObject("Microsoft.XMLHTTP");
    
    if (!req) alert("XMLHttpRequest is not supported by your browser");
    
    return req;
}




/***********************************************************/
/* SPECIAL */

function updateBreeds(type_id)
{
    if (type_id == 0) return;
    if (!breedOptions[type_id]) fetchBreeds(type_id);
    populateInput(document.getElementById('breed'), breedOptions[type_id]);
}

function fetchBreeds(type_id)
{
    alert('not implemented');
}




//
// PetSearch object
//

function PetSearch(form)
{
    if (form) {
        this.state_code = form.state_code.value;
        this.zip        = form.zip.value;
        this.type_id    = form.type_id.value;
        this.breed_id   = form.breed_id.value;
        this.breed_id   = breedOptions[this.type_id] && breedOptions[this.type_id][form.breed_id.value] ? form.breed_id.value : 0;
        this.gender     = form.gender.value;
        this.lostfound   = new Array();
        for (i=0; i<form['lostfound[]'].length; i++)
            if (form['lostfound[]'][i].checked)
                this.lostfound.push(form['lostfound[]'][i].value);
        if (this.lostfound.length == 0) {
            this.lostfound = new Array('L', 'F');
            //TODO: update form to show both lost & found checked?
        }
    }

    this.bounds = null;
    var me = this;
    
    
    /**
    * @param GLatLngBounds bounds
    */
    this.constructor.prototype.setBounds = function(bounds)
    {
        this.bounds = bounds;
    }
    this.constructor.prototype.getBounds = function()
    {
        return this.bounds;
    }
    
    
    this.constructor.prototype.getUrl = function()
    {
        var url = 'map.php?';
        var ar = new Array('state_code', 'zip', 'type_id', 'breed_id', 'gender');
        
        var urlAr = new Array();
        urlAr.push("xml=true");
        
        for (i in ar) {
            urlAr.push(ar[i] + '=' + encodeURIComponent(me[ar[i]]));
        }
        
        for (i=0; i<me.lostfound.length; i++) {
            urlAr.push("lostfound[]=" + me.lostfound[i]);
        }
        
        //map bounds
//        if (currentState == me.state_code && currentZip == me.zip) {
        if (me.bounds) {
            urlAr.push("lat1=" + me.bounds.getSouthWest().lat());
            urlAr.push("lon1=" + me.bounds.getSouthWest().lng());
            urlAr.push("lat2=" + me.bounds.getNorthEast().lat());
            urlAr.push("lon2=" + me.bounds.getNorthEast().lng());
        }else {
            currentState = me.state_code;
            currentZip = me.zip;
        }
        
        url = url + urlAr.join('&');
//        alert(url)
//        document.write(url);
        return url;
    }
    
    
    this.constructor.prototype.perform = function()
    {
        me.req = createXmlHttpRequest();
        me.req.onreadystatechange = this._acceptResponse;
        me.req.open("GET", this.getUrl(), true);
        me.req.send(null);
    }
    
    
    this.constructor.prototype._acceptResponse = function()
    {
        if (me.req.readyState == 4) {
            result = eval(me.req.responseText);
            me.onResultReady(result);
        }
    }
    
    
    this.constructor.prototype.onResultReady = function(result)
    {
        alert('redefine me');
    }
}




//
// ResultSet object
//

function ResultSet(map)
{
    this.map = map;
    this.resultSet = new Array();
    this.markerSet = new Array();
    this.areaSeen = new GLatLngBounds();
    this.cleanup = null;
    this.isLoading = null;
    this.msgBox = document.getElementById('msgBox');
    this.loadingBox = document.getElementById('loadingBox');
    var me = this;
    
    this.constructor.prototype.update = function(req, cleanup)
    {
//        if (!cleanup && me.areaSeen.containsBounds(req.getBounds())) return;
        
        me.setLoading(true);
        me.cleanup = cleanup;
        req.onResultReady = function(result)
        {
            if (me.cleanup) me.clear();
            for (i in result) {
                var pet = result[i];
                if (!me.resultSet[pet.id]) {
                    var marker = me.createMarker(pet);
                    me.markerSet[pet.id] = marker;
                    me.show(marker);
                }
                me.resultSet[pet.id] = pet;
            }
            if (me.cleanup) me.centerMap();
            
            me.setLoading(false);
            me.clearMsgs();
            if (countProperties(result) == 0) me.addMsg('No advertisements found');
            
//            me.areaSeen.extend(this.getBounds().getSouthWest());
//            me.areaSeen.extend(this.getBounds().getNorthEast());
        }
        req.perform();
    }
    
    
    this.constructor.prototype.clear = function()
    {
//        for (i=0; i<me.markerSet.length; i++) {
//            me.map.removeOverlay(me.markerSet[i]);
//        }
        me.map.clearOverlays();
        me.resultSet = new Array();
        me.markerSet = new Array();
        me.map.closeInfoWindow();
        me.areaSeen = new GLatLngBounds();
    }
    
    
    /**
    @param boolean value
    */
    this.constructor.prototype.setLoading = function(value)
    {
        me.isLoading = value ? true : false;
        var el = me.loadingBox;
        if (value) el.style.display = 'block';
        else el.style.display = 'none';
    }
    
    
    this.constructor.prototype.createMarker = function(pet)
    {
        var icon = G_DEFAULT_ICON;
        if (pet.lostfound == 'L') icon.image = "img/iconr.png";
        else icon.image = "img/icong.png";
        var marker = new GMarker(new GLatLng(pet.lat, pet.lon), icon);
//        marker.popupHtml = pet.popupHtml;
        marker.pet = pet;
        GEvent.addListener(marker, 'click', this._markerClicked);
        return marker;
    }
    
    
    this.constructor.prototype._markerClicked = function()
    {
        //'this' here refers to GMarker that was clicked http://www.google.com/apis/maps/documentation/reference.html#GEvent
//        this.openInfoWindowHtml(this.popupHtml);

        var imgHtml = this.pet.imageUrl ? "<p style=\"float:left; margin-right:10px;\"><a href=\""+ this.pet.url +"\"><img src=\""+ this.pet.imageUrl +"\" alt=\""+ this.pet.title +"\"></a></p>" : '';
        var gender = this.pet.gender ? this.pet.gender == 'M' ? 'Male' : 'Female' : '';

        var s = "\
<div style=\"width:300px; height:180px; overflow:auto\">\
<h3><a href=\""+ this.pet.url +"\">"+ this.pet.title +"</a></h3>\
"+ imgHtml +"\
<table>\
<tr>\
<td>Gender:</td>\
<td>"+ gender +"</td>\
</tr>\
<tr>\
<td>Breed:</td>\
<td>"+ this.pet.breed +"</td>\
</tr>\
<tr>\
<td>Color:</td>\
<td>"+ this.pet.color +"</td>\
</tr>\
</table>\
</div>\
";
        this.openInfoWindowHtml(s);
    }
    
    
    this.constructor.prototype.show = function(marker)
    {
        me.map.addOverlay(marker);
    }
    
    
    this.constructor.prototype.centerMap = function()
    {
        var min = this._getPoint(Math.min);
        var max = this._getPoint(Math.max);
        if (min && max) {
            var center = new GLatLng((max.lat()+min.lat())/2, (parseFloat(max.lng())+parseFloat(min.lng()))/2);
//            alert(min + ' - ' + max + ' - ' + center + ' - ' + max.lng() + ' - ' + min.lng());
            var bounds = new GLatLngBounds(min, max);
            var zoom = me.map.getBoundsZoomLevel(bounds);
            if (zoom > 14) zoom = 14;
        }else {
            var center = startPoint;
            var zoom = startZoom;
//            alert(center.lat() + ' ' + center.lng() + ' ' + zoom);
        }
//        alert(center + ' - ' + zoom);
        me.map.setCenter(center, zoom);
    }
    
    
    this.constructor.prototype.clearMsgs = function()
    {
        while (me.msgBox.childNodes.length > 0)
            me.msgBox.removeChild(me.msgBox.childNodes[0]);
    }
    
    
    this.constructor.prototype.addMsg = function(s)
    {
        var msg = document.createElement('p');
        var span = document.createElement('span');
        span.appendChild(document.createTextNode(s));
        msg.appendChild(span);
        me.msgBox.appendChild(msg);
    }
    
    
    this.constructor.prototype._getPoint = function(callback)
    {
        if (me.resultSet.length == 0) return null;
        
        var lat = null, lon = null;
        
        for (i=0; i<me.resultSet.length; i++) {
            var pet = me.resultSet[i];
            if (!pet) continue;
            
            if (lat == null) lat = pet.lat;
            else lat = callback(lat, pet.lat);
            
            if (lon == null) lon = pet.lon;
            else lon = callback(lon, pet.lon);
        }
        return new GLatLng(lat, lon);
    }
}
