﻿// This needs to be redone after thinking about the app design more
// 

google.load("maps", "2");

function SchoolSearchApp() {
    if(google.maps) { // ...If the google maps api has loaded 
        if (google.maps.BrowserIsCompatible()) { // ...and the browser being used is compatible, start the app.
            this.SortBy = "distance";
            this.pwindow;

            this.MaxResultsViewable = 10;
            this.MinZoomLevel = 9;
            this.MaxZoomLevel = 13;
            this.ResultsNodes = [];
            this.ResultsPane = document.getElementById("results");
            this.ResultsListElement = document.createElement("ol");
            this.Synonyms = { "st" : "st.", "saint" : "st." };
            
            for(var i = 0; i < this.MaxResultsViewable; i++) {
                this.ResultsNodes.push(document.createElement("li"));
            }
            
            this.AddressFinder = new google.maps.ClientGeocoder();
            this.AddressFinder.setViewport(new google.maps.LatLngBounds(
                            new google.maps.LatLng(40.7, -87.9),
                            new google.maps.LatLng(42.1, -87.5)));
            this.StartPoint = new google.maps.LatLng(41.985, -87.743); // Center of the map will start around Chicago
            this.Markers = []; // Array to store the markers
            this.Filters = { "gender" : { "B": false, "G": false, "C": false } }; // Object to store filters
            this.Results = []; // Array to store the search results
            this.latestFilter = null;
            
            // Initialize the map
            this.Map = new google.maps.Map2(document.getElementById("map"));
            this.Map.setCenter(this.StartPoint, this.MinZoomLevel);
            this.Map.addControl(new google.maps.SmallZoomControl());
            this.Map.addControl(new google.maps.MapTypeControl());
            this.Map.enableContinuousZoom();
            
            // Bind Events
            document.getElementById("coed").checked=true;
            google.maps.Event.bindDom(document.getElementById("coed"), "click", this, this.AddFilter);
            document.getElementById("boys").checked=true;
            google.maps.Event.bindDom(document.getElementById("boys"), "click", this, this.AddFilter);
            document.getElementById("girls").checked=true;
            google.maps.Event.bindDom(document.getElementById("girls"), "click", this, this.AddFilter);
            google.maps.Event.bindDom(document.getElementById("UserLocationSearchButton"), "click", this, this.GetUserLocation);
            google.maps.Event.bindDom(document.getElementById("SchoolNameSearchButton"), "click", this, this.NameSearch);
            google.maps.Event.bindDom(document.getElementById("ResetSearchButton"), "click", this, this.ResetSearch);
            // Load high school data
            google.maps.DownloadUrl("/schoolsxml.aspx", google.maps.Event.callback(this, this.LoadMarkers));       
        } else {
            alert("Your browser is incompatible with the Google Maps API.");
        }
    } else {
        alert("The Google Maps API was unable to load.");
    }
}

SchoolSearchApp.prototype.DistanceSort = function(a, b) {
    if(a.distanceFromUserLoc < b.distanceFromUserLoc) {
        return -1;
    } else if(a.distanceFromUserLoc > b.distanceFromUserLoc) {
        return 1;
    } else {
        return 0;
    }
}
// Strings are funny i think, need to look up how strings behave in this situation
// probably not doing this right
SchoolSearchApp.prototype.AlphaSort = function(a, b) {
    var i = a.schoolName.indexOf("St.");
    var a_temp = a.schoolName;
    if(i != -1){
        a_temp = a.schoolName.substring(4);
    }
    i = b.schoolName.indexOf("St.");
    var b_temp = b.schoolName;
    if(i != -1) {
        b_temp = b.schoolName.substring(4);
    }
    if(a_temp < b_temp) {
        return -1;
    } else if(a_temp > b_temp) {
        return 1;
    } else {
        return 0;
    }
}

SchoolSearchApp.prototype.LoadMarkers = function(xmlstring, responsecode) {
    if(responsecode == 200) {
        var xmldoc = google.maps.Xml.parse(xmlstring);
        var highschools = xmldoc.getElementsByTagName("HighSchool");
        for(var i = 0; i < highschools.length; i++) {
            this.SetMarker(highschools[i]);
        }
    }
    else {
        alert("Could not load data");
    }
} 

SchoolSearchApp.prototype.SetMarker = function(s) {  
    var bicon = new google.maps.Icon(G_DEFAULT_ICON);
    bicon.image = "../images/icons/marker-blue.png";
    var ricon = new google.maps.Icon(G_DEFAULT_ICON);
    ricon.image = "../images/icons/marker-red.png";
    var gicon = new google.maps.Icon(G_DEFAULT_ICON);
    gicon.image = "../images/icons/marker-green.png";
    var m;

    var point = new google.maps.LatLng(s.getElementsByTagName("Latitude")[0].childNodes[0].nodeValue, s.getElementsByTagName("Longitude")[0].childNodes[0].nodeValue);
    switch(s.getElementsByTagName("Gender")[0].childNodes[0].nodeValue) {
        case "G":
            var marker = new google.maps.Marker(point, { icon: ricon } );
            break;
        case "B":
            var marker = new google.maps.Marker(point, { icon: bicon } );
            break;
        case "C":
            var marker = new google.maps.Marker(point, { icon: gicon } );
            break;
        default:
            var marker = new google.maps.Marker(point, { icon: ricon } );
            break;
    }
    this.Map.addOverlay(marker);
    m = new HighSchoolMarker(s.getElementsByTagName("SchoolID")[0].childNodes[0].nodeValue,
                                      s.getElementsByTagName("SchoolName")[0].childNodes[0].nodeValue,
                                      s.getElementsByTagName("Address1")[0].childNodes[0].nodeValue,
                                      s.getElementsByTagName("City")[0].childNodes[0].nodeValue,
                                      s.getElementsByTagName("State")[0].childNodes[0].nodeValue,
                                      s.getElementsByTagName("Zip")[0].childNodes[0].nodeValue,
                                      s.getElementsByTagName("Gender")[0].childNodes[0].nodeValue,
                                      marker, this.HSInfoWindow);
    this.Markers.push(m);
    this.Results.push(m);
}

SchoolSearchApp.prototype.ResetSearch = function() {
    for(var filtername in this.Filters) {
        for(var filtervalue in this.Filters[filtername]) {
            this.Filters[filtername][filtervalue] = false;
        }
    }
    document.getElementById("coed").checked=true;
    document.getElementById("boys").checked=true;
    document.getElementById("girls").checked=true;
	this.Filters["gender"]["B"] = false;
	this.Filters["gender"]["G"] = false;
	this.Filters["gender"]["C"] = false;
    document.getElementById("SchoolNameTextbox").value = "";
    document.getElementById("UserLocationTextbox").value = "";
    document.getElementById("miles").value = "5";
    this.Results.length = 0;
    for(var i = 0; i < this.Markers.length; i++) {
        this.Markers[i].marker.show();
		this.Results.push(this.Markers[i]);// stopgap for bug fix
    }
	
	for(var j = 0; j < this.ResultsListElement.childNodes.length;) {
        this.ResultsListElement.removeChild(this.ResultsListElement.childNodes[j]);
    }
	
    if(this.UserLocationMarker) { this.UserLocationMarker.hide(); }
    this.Map.setCenter(this.StartPoint, this.MinZoomLevel);
    this.Map.getInfoWindow().hide();
    this.latestFilter = null;
    
    var n = document.getElementById("results");
	var t1 = document.getElementById("PrintLink");
	if(t1) n.removeChild(t1);
	t1 = document.getElementById("ResultsPageLinks");
	if(t1) n.removeChild(t1);
	t1 = document.getElementById("NoResults");
	if(t1) n.removeChild(t1);
	t1 = document.getElementById("SortByLinks");
	if(t1) n.removeChild(t1);
	/*
    for(var j=1; j < n.childNodes.length; ) {
        n.removeChild(n.childNodes[j]);
    }*/
    document.getElementById("ResultsPageLinksIntro").innerHTML = "Search Results"
}

SchoolSearchApp.prototype.PrintList = function() {
    this.pwindow = window.open("", "SearchResults");
    var ol = this.pwindow.document.createElement("ol");
    var li;
    
    this.pwindow.document.write("<html><head><title>Archdiocese of Chicago Elementary School Search Results</title></head><body></body></html>");
    var pintro = this.pwindow.document.createElement("p");
    if(this.latestFilter == this.DistanceFilter) {
        pintro.innerHTML = "Archdiocese of Chicago high schools within " +
            document.getElementById("miles").value + " miles of " +
            document.getElementById("UserLocationTextbox").value + ".<br />" + this.Results.length + " results sorted by " +
            this.SortBy + ".";
        this.pwindow.document.body.appendChild(pintro);
    }
    for(var i = 0; i < this.Results.length; i++) {
       li = this.pwindow.document.createElement("p"); 

       var t;
       if ( this.latestFilter == this.DistanceFilter ) {
           t = (this.Results[i].distanceFromUserLoc*0.000621371192).toFixed(1) + ""; 
           t += " mi";
       } else {
           t = "";
       }
       var sch = this.Results[i];
       li.innerHTML = '<strong>' + sch.schoolName + "</strong>" +
                      "<br />" + sch.address1 +
                      "<br />" + sch.city + ", " + sch.state + " " + sch.zip + 
                      "<br />" + t;
       this.pwindow.document.body.appendChild(li);
    }
    this.pwindow.document.close();
    this.pwindow.print();
}

/***************** ALERT! ********************************
 This function is an awful mess.  Needs much reworking.
 Seems to function as intended though :)
*********************************************************/
SchoolSearchApp.prototype.UpdateResultsPane = function(page) {
    // this function is a mess, needs rewrite badly
    var n = document.getElementById("results");
    if(!page) page=1;
    //do this stuff so we only create the maximum amount of nodes we need and then
    //reuse them as needed.
    for(var j = 0; j < this.ResultsListElement.childNodes.length;) {
        this.ResultsListElement.removeChild(this.ResultsListElement.childNodes[j]);
    }
	var t1 = document.getElementById("PrintLink");
	if(t1) n.removeChild(t1);
	t1 = document.getElementById("ResultsPageLinks");
	if(t1) n.removeChild(t1);
	t1 = document.getElementById("NoResults");
	if(t1) n.removeChild(t1);
	t1 = document.getElementById("SortByLinks");
	if(t1) n.removeChild(t1);
    /*for(j = 1;j < n.childNodes.length;) {
        n.removeChild(n.childNodes[j]);
    }*/
    // doing this stuff here i think probably creates many excess elements when this function
    // is run over many times.  Not sure about that though with garbage collection.  Needs to be 
    // totally redone in any event.
    var p1 = document.getElementById("ResultsPageLinksIntro");
    //var p1 = document.createElement("p");
    //p1.id = "ResultsPageLinksIntro";
    //n.appendChild(p1);
    if(this.Results.length) {
        var plink = document.createElement("p");
        plink.id = "PrintLink";
        
        var plink_a = document.createElement("a");
        plink_a.href = "#";
        plink_a.onclick = google.maps.Event.callback(this, function() { this.PrintList(); return false; });
        plink_a.innerHTML = "Print";
        plink.appendChild(plink_a);
        n.appendChild(plink);
    }
    if(this.latestFilter == this.DistanceFilter && this.Results.length > 1) {
        var p3 = document.createElement("p");
        p3.id = "SortByLinks";
        p3.innerHTML = 'Sort by: ';
        var dist_a = document.createElement("a");
        dist_a.innerHTML = "distance";
        dist_a.href = "#";
        dist_a.onclick = google.maps.Event.callback(this, function() { this.Results.sort(this.DistanceSort); this.SortBy = "distance"; this.UpdateResultsPane(); return false; });
        var alpha_a = document.createElement("a");
        alpha_a.innerHTML = "alphabetical";
        alpha_a.href = "#";
        alpha_a.onclick = google.maps.Event.callback(this, function() { this.Results.sort(this.AlphaSort); this.SortBy = "name"; this.UpdateResultsPane(); return false; });
        p3.appendChild(dist_a); p3.appendChild(document.createTextNode(" | ")); p3.appendChild(alpha_a);  
        n.appendChild(p3);
    }
    if(this.Results.length) {
        p1.innerHTML = "Search Results:";
        if (this.Results.length > 1) {
            p1.innerHTML += ' <span style="font-weight:normal">' + (this.MaxResultsViewable*(page - 1) + 1) + "&ndash;" + 
                           ((this.Results.length > this.MaxResultsViewable*page) ? this.MaxResultsViewable*page : this.Results.length) + " of " +
                           this.Results.length + "</span>";
        }
        
        var limit = (this.Results.length < this.MaxResultsViewable*page) ? this.Results.length - (this.MaxResultsViewable*(page-1)) : this.MaxResultsViewable
        for(var i = 0; i < limit; i++) {
            var t;
            if ( this.latestFilter == this.DistanceFilter ) {
                t = (this.Results[this.MaxResultsViewable*(page-1)+i].distanceFromUserLoc*0.000621371192).toFixed(1) + ""; 
                t += " mi";
            } else {
                t = "";
            }
            this.ResultsNodes[i].innerHTML = '<p class="address"><a href="#" class="' + this.Results[this.MaxResultsViewable*(page-1) + i].gender + '">' + this.Results[this.MaxResultsViewable*(page-1) + i].schoolName + "</a>" +
                                             "<span>" + this.Results[this.MaxResultsViewable*(page-1) + i].address1 + "</span>" +
                                             "<span>" + this.Results[this.MaxResultsViewable*(page-1) + i].city + ", " + this.Results[this.MaxResultsViewable*(page-1) + i].state + " " + this.Results[this.MaxResultsViewable*(page-1) + i].zip + "</span>" + 
                                             t + "</p";
            this.ResultsListElement.appendChild(this.ResultsNodes[i]);
            this.ResultsNodes[i].getElementsByTagName("a")[0].onclick = 
                                google.maps.Event.callback(this.Results[this.MaxResultsViewable*(page-1) + i], this.Results[this.MaxResultsViewable*(page-1) + i].OnHighSchoolMarkerClick);
        }
        n.appendChild(this.ResultsListElement);
    } else {
        var p2 = document.createElement("p");
		p2.id = "NoResults"; //stopgap for bugfix
        p2.innerHTML = "Your search did not return any results";
        n.appendChild(p2);
        p1.innerHTML = "Search Results";
    }
    if(this.Results.length > this.MaxResultsViewable) {
        var p2 = document.createElement("p");
        p2.id = "ResultsPageLinks";
        for(i=0; i<this.Results.length/this.MaxResultsViewable; i++) {
            if(i != page-1) {
                var a = document.createElement("a");
                a.setAttribute("href", "#"); a.innerHTML = i+1;
                a.onclick = google.maps.Event.callbackArgs(this, this.UpdateResultsPane, i+1);
                p2.appendChild(a);
            } else {
                p2.appendChild(document.createTextNode(i+1));
            }            
        }
        n.appendChild(p2);
        n.scrollTop = 0;
    }
    return false;
}

SchoolSearchApp.prototype.NameSearch = function() {
    this.SearchString = document.getElementById("SchoolNameTextbox").value.replace(/^\s+|\s+$/g, ""); //trim whitespace
    this.SearchString = this.SearchString.replace(/ {2,}/g, " ");
    for (var syn in this.Synonyms) {
        var expr = new RegExp("\\b"+syn+"(?=\\s|$)", "gi");
        this.SearchString = this.SearchString.replace(expr, this.Synonyms[syn]);
        
    }
    if(this.SearchString != "") {
        this.latestFilter = this.SearchSchoolName;
        //document.getElementById("SchoolTypeFilterControls").scrollIntoView();
        this.Filter();
    } else {
      
    }
}

SchoolSearchApp.prototype.SearchSchoolName = function() {
    this.Results.length = 0;
    var bounds = new google.maps.LatLngBounds();
    var expr = new RegExp("\\b" + this.SearchString, "i");
    var schoolname;
    var expr2;
    for(var i = 0; i < this.Markers.length; i++) {
        schoolname = this.Markers[i].schoolName;
        for (var syn in this.Synonyms) {
            expr2 = new RegExp("\\b"+syn+"(?=\\s|$)", "gi");
            schoolname = schoolname.replace(expr2, this.Synonyms[syn]);
        }
        if(schoolname.search(expr) != -1 && this.MarkerIsVisible(this.Markers[i])) {
            this.Markers[i].marker.show();
            this.Results.push(this.Markers[i]);
            bounds.extend(this.Markers[i].marker.getLatLng());
        } else {
            this.Markers[i].marker.hide();
        }
    }
    if(this.Results.length) {
        var z = this.Map.getBoundsZoomLevel(bounds) - 1;
        if(z < this.MinZoomLevel) { z = this.MinZoomLevel; }
        else if( z > this.MaxZoomLevel) { z = this.MaxZoomLevel; }
        this.Map.setCenter(bounds.getCenter(), z);
    }
}

SchoolSearchApp.prototype.GetUserLocation = function() {
    if(document.getElementById("UserLocationTextbox").value != "" && document.getElementById("miles").value != "") {
        this.AddressFinder.getLocations(document.getElementById("UserLocationTextbox").value, google.maps.Event.callback(this, this.SetUserLocationMarker));
    }
}

SchoolSearchApp.prototype.SetUserLocationMarker = function(response) {
    if(response && response.Status.code == "200") {
        //document.getElementById("SchoolTypeFilterControls").scrollIntoView();
        var userloc = new google.maps.LatLng(response.Placemark[0].Point.coordinates[1],
                                             response.Placemark[0].Point.coordinates[0]);
        if(this.UserLocationMarker) {
            this.UserLocationMarker.setLatLng(userloc);
        } else {
            var yicon = new google.maps.Icon(G_DEFAULT_ICON);
            yicon.image = "../images/icons/marker-yellow-dot.png";
            this.UserLocationMarker = new google.maps.Marker(userloc, { icon: yicon });
            this.Map.addOverlay(this.UserLocationMarker);
        }
        var miles = parseFloat(document.getElementById("miles").value);
        if(!isNaN(miles)) {
            this.FilterRadius = miles*1609.344; //convert to meters
            this.latestFilter = this.DistanceFilter;
            this.Filter();
        } else {
            alert("Please enter a valid number for the filter radius");
        }
    
    }
    else {
        alert("Could not find the address specified");
    }
}

SchoolSearchApp.prototype.Filter = function() {   
    this.Map.getInfoWindow().hide(); // Kill the info window    
    if(this.latestFilter) {
        this.latestFilter();    
        this.UpdateResultsPane();
    } else {
        for(var i=0; i < this.Results.length; i++) { 
            if(this.MarkerIsVisible(this.Results[i])) {
                this.Results[i].marker.show();
            } else {
                this.Results[i].marker.hide();
            }
        }
    }
}

/****************************ALERT!!!*************************
    Filtering method will have to change when more 
    complicated filters are possible
*************************************************************/
SchoolSearchApp.prototype.MarkerIsVisible = function(m) {
    var filtername = "gender";
    return !this.Filters[filtername][m[filtername]];
}

SchoolSearchApp.prototype.DistanceFilter = function() {
    this.Results.length = 0;
    var bounds = new google.maps.LatLngBounds();
    bounds.extend(this.UserLocationMarker.getLatLng());
    for(var i=0; i < this.Markers.length; i++) {
        this.Markers[i].distanceFromUserLoc = this.Markers[i].marker.getLatLng().distanceFrom(this.UserLocationMarker.getLatLng());
        if (this.Markers[i].distanceFromUserLoc <= this.FilterRadius && this.MarkerIsVisible(this.Markers[i])) {
            this.Results.push(this.Markers[i]);
            this.Markers[i].marker.show();
            bounds.extend(this.Markers[i].marker.getLatLng());
       } else {
            this.Markers[i].marker.hide();
        }
    }
    var z = this.Map.getBoundsZoomLevel(bounds) - 1;
    if(z < this.MinZoomLevel) { z = this.MinZoomLevel; }
    else if( z > this.MaxZoomLevel) { z = this.MaxZoomLevel; }
    this.Map.setCenter(bounds.getCenter(), z);
    this.Results.sort(this.DistanceSort);
}

SchoolSearchApp.prototype.AddFilter = function(event) {
    if(event.target.checked) {
        this.Filters[event.target.name][event.target.value] = false;
    } else {
        this.Filters[event.target.name][event.target.value] = true;
    }
    this.Filter();
}

function HighSchoolMarker(schoolID, schoolName, address, city, state, zip, gender, marker, iw) {
    this.dataLoaded = false;
    this.schoolID = schoolID;
    this.schoolName = schoolName;
    this.address1 = address;
    this.city = city;
    this.state = state;
    this.zip = zip;
    this.gender = gender;
    this.marker = marker;
    this.iw = iw;
    google.maps.Event.bind(this.marker, "click", this, this.OnHighSchoolMarkerClick);
}

HighSchoolMarker.prototype.OnHighSchoolMarkerClick = function() {
    if(this.dataLoaded == true) {
       this.SetInfoWindow();
    } else {
       google.maps.DownloadUrl("/schoolsxml.aspx?hsid=" + this.schoolID, google.maps.Event.callback(this, this.SetInfoWindow));
    }
    return false;
}

HighSchoolMarker.prototype.SetInfoWindow = function(xmlstring, responsecode) {
    if(xmlstring) {
        if(responsecode == 200) {
            var xmldoc = google.maps.Xml.parse(xmlstring);
            this.vicariate = xmldoc.getElementsByTagName("SchoolID")[0].childNodes[0].nodeValue;
            this.deanery = xmldoc.getElementsByTagName("Deanery")[0].childNodes[0].nodeValue;
            this.phone = xmldoc.getElementsByTagName("Phone")[0].childNodes[0].nodeValue;
            this.fax = xmldoc.getElementsByTagName("Fax")[0].childNodes[0].nodeValue;
            this.website = xmldoc.getElementsByTagName("Website")[0].childNodes[0].nodeValue;
            this.dataLoaded = true;
        } else {
            alert("Could not load school data");
        }
    }
    var _gender;
    switch (this.gender) {
        case "C":
            _gender = "Coed";
            break;
        case "B":
            _gender = "Boys";
            break;
        case "G":
            _gender = "Girls";
            break;
    }
    this.marker.openInfoWindowHtml( '<div id="HSInfoWindow"><h2>' + this.schoolName + " (" + _gender + ")" + "</h2>" +
                                    '<p class="address"><span class="address1">' + this.address1 + "</span>" +
                                    '<span class="address2">' + this.city + ", " + 
                                                                    this.state + " " + 
                                                                    this.zip +"</span></p>" +
                                    '<p class="phone">' + this.phone + "</p>" +
                                    '<a href="http://' + this.website + '">' + this.website + "</a></div>" );
}

var app;

google.setOnLoadCallback( function(){ app = new SchoolSearchApp(); } );
