var Map = function()
{
    var map, geocoder;
    var markers; //property push pins
    var searchMarker;
    var urlBase;
    var poly; //polygon points clicked by user (raw data lat/long)
    var censusTracts;
    var showCounty;

    var congressPoints, compPoints;
    var radius, earthRadius, polygonList;

    var radiusPoints ;
    var currentView = "";
    var circleOverlay, polygonOverlay, countyOverlay;
    var currentMarker;
    var maxZoom;
    var excludedCensusTracts, excludedCongDistricts, excludedComps;
    var zoomLevel;
    var timer;
    var compsDataSource, compsDataTable;
    var mapBounds;

    var drawnMarkers = [];
    var lastMapType = "";

    var gPoly = null; //google polygon object. An javascript object representing a polygon
    var gPolyLast = null; //google polygon object representing the last vertex of the polygon (has different color)
    var gPolyPoints = []; //google polygon marker objects

    var colors = [
        '#ff0000', '#00ff00', '#0000ff',
        '#ffff00', '#ff00ff', '#00ffff','#7fff00',
        '#7f00ff', '#ff7f00', '#ff007f',
        '#007fff', '#00ff7f', '#7f7f7f' ];

    // BLUE ICON
    var BLUE_ICON ;
    var ORANGE_ICON ;
    var PURPLE_ICON;

    var usedUrlParams = "";
    var useRadius = false;
    var pg;

    return{
        init: function(url)
        {
            markers = [];
            poly = [];
            // BLUE ICON
            BLUE_ICON = new GIcon(G_DEFAULT_ICON, 'images/markers/blank_blue.png');
            ORANGE_ICON = new GIcon(G_DEFAULT_ICON, 'images/markers/blank_orange.png');
            PURPLE_ICON = new GIcon(G_DEFAULT_ICON, 'images/markers/blank_purple.png');
            excludedCensusTracts = [];
            excludedCongDistricts = [];
            excludedComps = []
            censusTracts = [];
            //	censusTractMarkers = [];
            map = new GMap2(document.getElementById("map"));
            map.disableDoubleClickZoom();
            map.addControl(new GSmallMapControl());
            map.addControl(new GMapTypeControl());

            var control = new GOverviewMapControl();
            map.addControl(control);
            control.hide(true);

            map.setCenter(new GLatLng(41.178654, -95.800781), 4);
            Map.goToInvalidState();
            geocoder = new GClientGeocoder();
            urlBase = url;
            circleOverlay = null;

            maxZoom = 4;

            compsDataSource = new YAHOO.util.DataSource(urlBase + 'gis_search.m');
            compsDataSource.responseType = YAHOO.util.DataSource.TYPE_JSON;
            compsDataSource.connMethodPost = true;
            compsDataSource.responseSchema = {
                resultsList : 'nearbyComps',
                fields : [
                    { key: "id" },                    // simple location
                    { key: "lat" },
                    { key: "lng" },
                    { key: "compNumber"},
                    { key: "isComplete"},
                    { key: "image" },
                    { key: "name" },
                    { key: "county" },
                    { key: "type" },
                    { key: "unitsProgram"},
                    { key: "completeAddress" },
                    { key: "effectiveRentDate" },
                    { key: "taxCreditProperty" },
                    { key: "elderly" },
                    { key: "mixLabels" },
                    { key: "accessStatusString" }
                ]
            };

            var compsDataTableCols = [{key:"id", label:"", minWidth:150, formatter: function(elCell, oRecord, oColumn, sData)
            {
                var dispHTML = "<a onclick='propertyClicked(" + oRecord.getData("id") + "); return false'>" ;


                var id = oRecord.getData("id");
                var imgCode = "";

                if (markers && markers[id])
                {
                    imgCode = markers[id].getIcon().image;
                }
                else
                {
                    var compNumber = 1;
                    compNumber += oRecord.getData("compNumber");

                    imgCode = (oRecord.getData("isComplete") == true) ? urlBase + "/images/markers/" + compNumber + "_green.png" : urlBase + "/images/markers/" + compNumber + ".png";
                }

                dispHTML += " <img src='" + imgCode + "'/> <br/> Find on map </a> ";
                elCell.innerHTML = dispHTML;
            }},
                {key:"image", label: "Photo", formatter:function(elCell, oRecord, oColumn, sData)
                {
                    elCell.innerHTML = "<img src='" + oRecord.getData("image") + "'/>";

                }},
                {key:"completeAddress",  sortOptions:{sortFunction: function(a, b, desc)
                {
                    var zipCode = Dom.get('address').value;
                    if (a.getData("completeAddress").indexOf(zipCode) != -1)
                    {
                        return -1;
                    }
                    else
                    {
                        return 1;
                    }
                }

                },  minWidth: "450", label: "Address", formatter:function(elCell, oRecord, oColumn, sData)
                {
                    var dispHTML = "<div style='font-family:verdana,arial,sans-serif; font-size:11px'>"
                            + "<b>" + oRecord.getData("name") + "</b> <br>"
                            + "<i>" + oRecord.getData("county") + "</i> <br>"
                            + oRecord.getData("completeAddress") + "<br/>" ;

                    var detailHTML = "";
                    var mixLabels = oRecord.getData("mixLabels");
                    var mixText = "";
                    if (mixLabels && mixLabels.length != 0)
                    {
                        for (var i = 0; i < mixLabels.length; i++)
                        {
                            mixText += "" + mixLabels[i].mixtype + "<br/>";
                        }
                    }

                    detailHTML += "<div style='display:none; background:white; border: 1px dashed silver;padding:4px;font-family:verdana,arial,sans-serif; font-size:11px' id='rent_details_" + oRecord.getData("id") + "'> "
                            + "<b>" + oRecord.getData("unitsProgram") + "</b><br/><br/>"
                            + "<label class='listViewLabel'>  Type </label> : " + oRecord.getData("type") + "<br/>"
                            + "<label class='listViewLabel'> Tax-Credit </label> : " + ((oRecord.getData("taxCreditProperty") == "true") ? "Yes" : "No") + "<br/>"
                            + "<label class='listViewLabel'> Age-Restricted </label> : " + ((oRecord.getData("elderly") == "true") ? "Yes" : "No") + "<br/><br/>"
                    detailHTML += mixText + "</div>";

                    var linkHTML = "<a id='link" + oRecord.getData("id") + "' onclick='toggleDetails(" + oRecord.getData("id") + ")'> Show details </a><br style='clear:both'/>";

                    elCell.innerHTML = dispHTML + detailHTML + linkHTML;

                }},
                {key:"effectiveRentDate", minWidth: 50, label: "Effective Rent Date", type:"date"},
                { key: "accessStatusString",  label: "Purchase", formatter:function(elCell, oRecord, oColumn, sData)
                {
                    var dispHTML = "";
                    if (oRecord.getData("accessStatusString") == "Standard")
                    {
                        dispHTML += " <img src='" + urlBase + "images/shopcart.png' "
                                + " onclick=\"return addPropertyReportToCart('" + oRecord.getData("id") + "')\"/>"
                    }
                    else
                    {
                        dispHTML += " <div style='font-family:verdana,arial,sans-serif; font-size:11px; text-align: center; font-style:italic'>" + oRecord.getData("accessStatusString")
                                + "<br>To find out more about this property, <br/> <a href='#' onclick=' javascript:popupgis(\"" + urlBase + "/gis/contact.html\")'>Click Here</a></div>";
                    }
                    elCell.innerHTML = dispHTML;
                }}
            ];

            pg = new YAHOO.widget.Paginator({
                rowsPerPage: 4,
                template :"{CurrentPageReport} Showing{RowsPerPageDropdown}comps per page  <br/> <br/> [{FirstPageLink}/{PreviousPageLink}] {PageLinks} [{NextPageLink}/{LastPageLink}]",

                pageReportTemplate : "Found {totalRecords} comps." ,
                alwaysVisible: true,
                firstPageLinkLabel : "First",
                lastPageLinkLabel : "Last",
                previousPageLinkLabel : "Previous",
                nextPageLinkLabel : "Next", // default

                rowsPerPageOptions       : [
                    { value : 4, text : "4" },
                    { value : 10, text : "10" },
                    { value : 20, text : "20" },
                    { value : 100, text: "100"}
                ]
            });
            var oConfigs = {
                paginator   : pg,
                sortedBy:{
                    key: 'completeAddress',
                    dir:'asc'
                },
                initialLoad  : false
            }
            //			compsDataTable = new YAHOO.widget.DataTable("divRentContainer", compsDataTableCols,  compsDataSource, oConfigs);
            compsDataTable = new YAHOO.widget.DataTable(document.createElement('div'), compsDataTableCols, compsDataSource, oConfigs);
            compsDataTable.subscribe('initEvent', function()
            {
                var d = document.getElementById('divRentContainer'); // CHANGE THIS -- match the id of the container you want.
                while (d.firstChild)
                { d.removeChild(d.firstChild); }
                ; // remove previous DataTables
                d.appendChild(this._elContainer);
            });

            Map.resetView();
            GEvent.addListener(map, "click", function(overlay, point)
            {
                if (overlay)
                {
                    return;
                }
                if (!Map.isValid())
                { return}
                ;
                Map.newUserPoint(point);
                Map.drawPolygon();
            });

            GEvent.addListener(map, "moveend", function()
            {
                if (!Map.isValid())
                { return}
                ;

                if (!polygonOverlay || ( polygonOverlay && !Map.isPolygonOnScreen(polygonOverlay["polygon"])   ))
                {
                    // If some portion of user-defined polygon is still on screen, don't refresh entire list
                    if (polygonOverlay)
                    {
                        map.removeOverlay(polygonOverlay["polygon"]);
                        polygonOverlay = null;
                    }
                    clearTimeout(timer);
                    useRadius = true;
                    timer = setTimeout("  Map.findByBounds()    ", 1000);
                }
                else
                {
                    useRadius = false;
                }


            });

            GEvent.addListener(map, "zoomend", function(oldLevel, newLevel)
            {


                if (newLevel < oldLevel)
                {
                    //zoomed out
                    if (newLevel < maxZoom)
                    {
                        alert("You have zoomed too far out. New information will not be loaded until you zoom back in.");
                        Map.goToInvalidState();
                    }
                }

            });
        },

        isPolygonOnScreen: function(polygon)
        {
            if (!polygon) return false;
            var mapBounds = map.getBounds();
            var polyBounds = polygon.getBounds();
            return ( mapBounds.containsBounds(polyBounds) || mapBounds.intersects(polyBounds)   )
        },
        //Based on user points
        drawPolygon: function()
        {
            if (!poly.length || poly.length == 0)
            {
                tooltip('addPoints');
            }
            else if (poly.length >= 3)
            {
                tooltip('threePoints');
                resetQuickFactsTable();
            }
            else
            {
                tooltip('removePoints');
            }

            //Remove polygon
            if (null != gPoly)
            {
                map.removeOverlay(gPoly);
            }
            if (null != gPolyLast)
            {
                map.removeOverlay(gPolyLast);
            }

            //Remove all polygon markers
            if (null != gPolyPoints || gPolyPoints.length)
            {
                for (i = 0; i < gPolyPoints.length; i++)
                {
                    map.removeOverlay(gPolyPoints[i]);
                }
            }

            (poly.length >= 3) ? Dom.setStyle('btnPolySearch', 'display', '') : Dom.setStyle('btnPolySearch', 'display', 'none');
            (poly.length > 0) ? Dom.setStyle('btnClear', 'display', '') : Dom.setStyle('btnClear', 'display', 'none');
            //  document.getElementById('btnPolygonDefine').style.display = display;

            if (poly.length > 0)
            {
                var icon = new GIcon();
                icon.image = 'http://labs.google.com/ridefinder/images/mm_20_yellow.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.infoWindowAnchor = new GPoint(6, 20);

                for (j in poly)
                {
                    Map.createPolygonCornerMarkers(j, icon);
                }

                gPoly = new GPolyline(poly);
                map.addOverlay(gPoly);
                if (poly.length >= 3)
                {
                    gPolyLast = new GPolyline([poly[0],poly[poly.length - 1]]);
                    map.addOverlay(gPolyLast);
                }
            }
        },

        removePolygonPoint: function(p)
        {
            map.closeInfoWindow();
            poly.splice(p, 1);
            Map.drawPolygon();
        },

        createPolygonCornerMarkers: function(corner, icon)
        {
            var marker = new GMarker(poly[corner], icon);
            gPolyPoints[corner] = marker;
            GEvent.addListener(marker, "click", function()
            {
                marker.openInfoWindowHtml('<br>&nbsp;<br><center><button onclick=\"Map.removePolygonPoint(' + corner + ');return false;\" >Remove Point</button></center>');
            });
            map.addOverlay(marker);
        },

        getPolyPoint: function(i)
        {
            return poly[i % poly.length];
        },

        newUserPoint: function(point)
        {
            // THIS CODE IS COPYRIGHTED TO NOVOGRADAC & COMPANY LLP http://www.novoco.com
            // IF YOU WANT TO USE THIS CODE, YOU NEED WRITTEN PERMISSION FROM NOVOGRADAC & COMPANY LLP
            if (poly.length < 3)
            {
                poly.push(point);
                return;
            }

            // calculuate point-vertex projection distance
            var vertexmin;
            var vertexminindex;
            var cornermin;
            var cornerminindex;
            for (i = 0; i < poly.length; i++)
            {
                var x0 = poly[i].x;
                var y0 = poly[i].y;
                var x1 = Map.getPolyPoint(i + 1).x;
                var y1 = Map.getPolyPoint(i + 1).y;
                var vertex_d_sqr = Math.abs((x1 - x0) * (y0 - point.y) - (x0 - point.x) * (y1 - y0)) / Math.sqrt(Math.pow(x1 - x0, 2) + Math.pow(y1 - y0, 2));
                if (vertex_d_sqr < vertexmin || (null == vertexmin))
                {
                    vertexminindex = i;
                    vertexmin = vertex_d_sqr;
                }
                var point_d_sqr = Math.pow(x0 - point.x, 2) + Math.pow(y0 - point.y, 2);
                if (point_d_sqr < cornermin || (null == cornermin))
                {
                    cornerminindex = i;
                    cornermin = point_d_sqr;
                }
            }
            // was the shortest distance outside [x0,x1]?
            // find out by projecting (p0 p)' onto (p0 p1)'
            var p0 = [poly[vertexminindex].x, poly[vertexminindex].y];
            var p1 = [Map.getPolyPoint(vertexminindex + 1).x, Map.getPolyPoint(vertexminindex + 1).y];
            var p = [point.x, point.y];
            var p0_p = vectorsubstract(p, p0);
            var p0_p1 = vectorsubstract(p1, p0);
            // the actual projection
            var r = vectormultiply(vectorproduct(p0_p, p0_p1) / Math.pow(vectorlength(p0_p1), 2), p0_p1);
            var x = p0[0] + r[0];
            if ((x >= p0[0] && x <= p1[0]) || (x >= p1[0] && x <= p0[0]))
            {
                // shortest vertex distance was inside [x0,x1]
                poly.splice(vertexminindex + 1, 0, point);
                return;
            }
            // get the closest corner
            p0 = [poly[cornerminindex].x, poly[cornerminindex].y];
            p1 = [Map.getPolyPoint(cornerminindex + 1).x, Map.getPolyPoint(cornerminindex + 1).y];
            var previous = cornerminindex - 1;
            if (previous < 0)
            {
                previous = poly.length - 1;
            }
            var p_1 = [poly[previous].x, poly[previous].y];
            var v0 = vectorsubstract(p0, p1);
            var v_1 = vectorsubstract(p0, p_1);
            r = vectorsubstract(p0, p);
            var a0 = Math.abs(vectorangle(v0, r));
            var a_1 = Math.abs(vectorangle(v_1, r));
            if (a0 < a_1)
            {
                poly.splice(cornerminindex + 1, 0, point);
            }
            else
            {
                poly.splice(cornerminindex, 0, point);
            }
        },

        clearPolygon: function()
        {
            poly = [];
            Map.drawPolygon();
        },

        populateReports: function()
        {
            Dom.setStyle('tblNoReports', 'display', 'none');
            Dom.setStyle('tblReports', 'display', '');
        },

        goToInvalidState: function()
        {
            Dom.setStyle('tblNoReports', 'display', '');
            Dom.setStyle('tblReports', 'display', 'none');
        },

        isValid: function()
        {
            var status = true;
            if (Dom.get('address').value == "")
            {
                status = false;
            }
            if (map.getZoom() < maxZoom)
            {
                status = false;
            }
            var radius = Dom.get('radius').value;
            if (radius == "" || radius <= "0" || isNaN(radius))
            {
                status = false;
            }
            return status;
        },

        loadCensusTracts: function(urlParams, doZoom)
        {
            urlParams += "&excludedIds=" + excludedCensusTracts;
            Map.showLoading();
            var callback = {
                success: function(response)
                {
                    currentView = "census";
                    var jsonText = YAHOO.lang.JSON.parse(response.responseText);
                    if (!jsonText)
                    {
                        alert("error parsing data");
                        Map.goToInvalidState();
                        Map.hideLoading();
                        return;
                    }
                    if (jsonText.errormessage && jsonText.errormessage != "")
                    {
                        alert(jsonText.errormessage);
                        Map.goToInvalidState();
                        Map.hideLoading();
                        return;
                    }
                    var latlng = new GLatLng(jsonText.latitude, jsonText.longitude);
                    if (doZoom)
                    {
                        Map.zoomToLatLng(latlng);
                        return;
                    }
                    Map.drawCensusTracts(jsonText.censustracts);
                    Map.populateReports();
                    Map.hideLoading();
                },
                failure: function(response)
                {
                }
            }
            resetQuickFactsTable();
            var conn = YAHOO.util.Connect.asyncRequest('POST', urlBase + 'gis_search.m', callback, urlParams);
        },

        //Loads comps within selected user-defined polyon
        loadSelectedPolygon: function(urlparams, searchTerm)
        {
            Map.showLoading();
            var callback = {
                success: function(response)
                {
                    var jsonText = YAHOO.lang.JSON.parse(response.responseText);
                    if (!jsonText)
                    {
                        alert("error parsing data");
                        Map.goToInvalidState();
                        Map.hideLoading();
                        return;
                    }
                    if (jsonText.errormessage && jsonText.errormessage != "")
                    {
                        alert(jsonText.errormessage);
                        Map.goToInvalidState();
                        Map.hideLoading();
                        return;
                    }

                    polygonList = jsonText.polygons;
                    Map.clear();
                    Map.drawSelectedRegion(polygonList);
                    //    console.log("Search " + searchTerm);
                    switch (searchTerm)
                            {
                        case "showcomps":
                            compList = jsonText.nearby_comps;
                            Map.drawMarkers(compList);
                            break;
                        case "showcongress":
                            Map.drawCongressDisctricts(jsonText.congressdistrict);
                            break;
                        case  "showcensus":
                            Map.drawCensusTracts(jsonText.censustracts);
                            break;
                    }

                    Map.populateReports();
                    Map.hideLoading();
                },
                failure: function(response)
                {
                }
            }
            resetQuickFactsTable();
            var conn = YAHOO.util.Connect.asyncRequest('POST', urlBase + 'gis_search.m', callback, urlparams);
        },


        resetView: function()
        {
            var option = Dom.get('lstMapType').value;
            Map.clear();
            (option == "showcomps") ? Dom.setStyle('divFilterComp', 'display', '') : Dom.setStyle('divFilterComp', 'display', 'none');
            if (Dom.get('hiddenTotal') && Dom.get('hiddenTotal').innerHTML != "")
            {
                var hiddenTotal = Dom.get('hiddenTotal').innerHTML;
                if (hiddenTotal == " $0" || hiddenTotal == " " || hiddenTotal == "-")
                {
                    Dom.setStyle('tdCheckout', 'display', 'none');
                    Dom.get('tdTotal').innerHTML = "-";
                }
                else
                {
                    Dom.get('tdTotal').innerHTML = hiddenTotal;
                    Dom.setStyle('tdCheckout', 'display', '')
                }
            }
        },

        loadCongressDistrict: function(urlparams, doZoom)
        {
            urlparams += "&excludedIds=" + excludedCongDistricts;
            var callback = {
                success: function(response)
                {
                    var jsonText = YAHOO.lang.JSON.parse(response.responseText);
                    if (!jsonText)
                    {
                        alert("error parsing data");
                        Map.goToInvalidState();
                        Map.hideLoading();
                        return;
                    }
                    if (jsonText.errormessage && jsonText.errormessage != "")
                    {
                        alert(jsonText.errormessage);
                        Map.goToInvalidState();
                        Map.hideLoading();
                        return;
                    }
                    var latlng = new GLatLng(jsonText.latitude, jsonText.longitude);
                    if (doZoom)
                    {
                        Map.zoomToLatLng(latlng);
                        return;
                    }
                    congressPoints = jsonText.congressdistrict;
                    compPoints = jsonText.nearby_comps;

                    Map.drawCongressDisctricts(congressPoints);
                    Map.populateReports();
                    Map.hideLoading();
                },
                failure: function(response)
                {
                }
            }
            Map.showLoading();
            resetQuickFactsTable();
            var conn = YAHOO.util.Connect.asyncRequest('POST', urlBase + 'gis_search.m', callback, urlparams);
        },

        loadComps: function(urlParams, doZoom)
        {
            var params = urlParams + "&tax_credit=" + Dom.get('chkTaxCredit').checked +
                         "&elderly=" + Dom.get('chkElderly').checked +
                         "&building_type=" + Dom.get('lstCompType').value;
            Map.showLoading();
            var callback = {
                success: function(response)
                {
                    var jsonText = YAHOO.lang.JSON.parse(response.responseText);
                    if (!jsonText)
                    {
                        alert("error parsing data");
                        Map.goToInvalidState();
                        Map.hideLoading();
                        return;
                    }
                    if (jsonText.errormessage && jsonText.errormessage != "")
                    {
                        alert(jsonText.errormessage);
                        Map.goToInvalidState();
                        Map.hideLoading();
                        return;
                    }
                    var latlng = new GLatLng(jsonText.latitude, jsonText.longitude);
                    if (doZoom)
                    {
                        Map.zoomToLatLng(latlng);
                        return;
                    }
                    compPoints = jsonText.nearby_comps;
                    polygonList = jsonText.polygons;

                    Map.drawMarkers(compPoints);
                    Map.populateReports();
                    Map.hideLoading();
//                    Map.populateCompsTab();
                },
                failure: function(response)
                {
                }
            }
            resetQuickFactsTable();
            var conn = YAHOO.util.Connect.asyncRequest('POST', urlBase + 'gis_search.m', callback, params);
        },

        addSearchMarker: function(latlng, dispText)
        {
            searchMarker = new GMarker(latlng);
            GEvent.addListener(searchMarker, "click", function()
            {
                this.openInfoWindowHtml(dispText);
            });
            map.addOverlay(searchMarker);
            GEvent.trigger(searchMarker, "click");
        },

        showLoading: function()
        {
            Dom.setStyle('divLoadIndicator', 'display', '');
        },

        hideLoading: function()
        {
            Dom.setStyle('divLoadIndicator', 'display', 'none');
        },

        zoomToLatLng: function(latlng)
        {
            //alert(latlng.lat());
            map.setCenter(latlng);
            map.setZoom(13);
            Map.drawCircle();
            if (searchMarker)
            {
                map.removeOverlay(searchMarker);
            }
        },

        getZoom: function()
        {
            return map.getZoom();

        },
        zoomToLatLng2: function(lat, lng)
        {
            //alert(latlng.lat());

            var latlng = new GLatLng(parseFloat(lat), parseFloat(lng));
            Map.zoomzoomToLatLng(latlng);
            //  map.setCenter(latlng);
            //  map.setZoom(13);
        },


        //Shows outline of custom polygon defined
        drawSelectedRegion: function(vertexList)
        {

            Map.showLoading();
            var points = [];
            var color = '#000000';
            var bounds = new GLatLngBounds();

            for (var i = 0; i < vertexList.length; i++)
            {
                var thisLatLng = new GLatLng(vertexList[i].y, vertexList[i].x)
                points.push(thisLatLng);
                bounds.extend(thisLatLng);
            }

            if (points.length > 0)
            {
                if (polygonOverlay)
                {
                    //If there was already a custom polygon defined, remove it
                    map.removeOverlay(polygonOverlay["polygon"]);
                    polygonOverlay = null;
                }
                polygonOverlay = {};
                polygonOverlay["polygon"] = new GPolyline(points, color);
                polygonOverlay["points"] = poly;
                map.addOverlay(polygonOverlay["polygon"]);
            }
            if (0 == points.length)
            {
                Map.drawCircle();
            }

            Map.clearPolygon();
            Map.hideLoading();
            map.setZoom(map.getBoundsZoomLevel(bounds)); //
        },

        //Shows outline of custom polygon defined
        drawCounty: function(vertexList)
        {
            Map.showLoading();
            var color = '#537799';
            var bounds = new GLatLngBounds();
            var countyPoints = [];

            for (var i = 0; i < vertexList.length; i++)
            {
                var thisLatLng = new GLatLng(vertexList[i].y, vertexList[i].x)
                countyPoints.push(thisLatLng);
                bounds.extend(thisLatLng);
            }

            if (countyOverlay)
            {
                //If there was already a county polygon defined, remove it
                map.removeOverlay(countyOverlay);
                countyOverlay = null;
            }
            countyOverlay = new GPolyline(countyPoints, color, 5);
            map.addOverlay(countyOverlay);

            Map.hideLoading();
            map.setZoom(map.getBoundsZoomLevel(bounds)); //
        },

        //Filters displayed comps based on criteria
        doCompFilter: function()
        {
            if (!Map.isValid())
            { return false}
            ;

            //clear only markers. leave other overlays
            Map.clear(true);

            if (!polygonOverlay || ( polygonOverlay && !Map.isPolygonOnScreen(polygonOverlay["polygon"])   ))
            {
                var address = Dom.get('address').value;
                if (address.match(/[a-z\ \'-]+\s+(County|Parish)/i))
                {
                    var county = address.match(/[a-z\ \'-]+\s+(County|Parish)/i)[0];
                    var state = "";
                    var stateTest = address.match(/,\s*([a-z\ ]+)\s*/i);
                    if (stateTest)
                    {
                        state = stateTest[1];
                    }
                    Map.findByCounty(county, state);
                }
                else
                {
                    Map.findByBounds();
                }
            }
            else
            {
                Map.findByBounds();
            }
        },

        // Populates radius text box with value in drop-down
        handleRadiusDropDownChange: function(e)
        {
            var target = YAHOO.util.Event.getTarget(e);
            Dom.get('radius').value = target.value;
            Map.drawCircle();
        }  ,

        handleRadiusChange: function()
        {
            if (!Map.validateRadius())
            {
                Map.drawCircle();
            }
            else
            {
                alert("invalid radius");
            }
        },

        drawCenter: function(latitude, longitude)
        {
            var icon = new GIcon();
            icon.image = 'images/home.gif';
            icon.iconSize = new GSize(10, 8);
            icon.shadowSize = new GSize(10, 8);
            icon.iconAnchor = new GPoint(0, 0);
            map.addOverlay(new GMarker(new GLatLng(latitude, longitude), icon));
        },

        // Shown when radius is changed;
        drawCircle: function(noZoom)
        {
            if (!Map.isValid())
            {return;}

            var center = map.getCenter();
            var circlePoints = Array();
            radiusPoints = [];
            var bounds = new GLatLngBounds();
            var circleRadius = parseFloat(Dom.get('radius').value);
            var rLat = circleRadius / 3963.189 * (180 / Math.PI);
            var rLng = rLat / Math.cos(center.lat() * (Math.PI / 180));
            for (var a = 0; a < 361; a += 1)
            {

                var aRad = a * (Math.PI / 180);
                var x = center.lng() + rLng * Math.cos(aRad);
                var y = center.lat() + rLat * Math.sin(aRad);
                var point = new GLatLng(parseFloat(y), parseFloat(x));
                bounds.extend(point);
                circlePoints.push(point);

                if (a % 7 == 0) radiusPoints.push(point);
                // Get 50 points from the circle for quick facts
            }
            // console.log(radiusPoints.length);
            if (circleOverlay != null)
            {
                map.removeOverlay(circleOverlay);
            }
            circleOverlay = new GPolyline(circlePoints, '#444444');
            map.addOverlay(circleOverlay);

            if (noZoom === true) return; // IF called by quickfacts dont change the zoom
            map.setZoom(map.getBoundsZoomLevel(bounds)); // This produces inconsistent zoom;
            /*
             switch(circleRadius){
             case 0.25:
             map.setZoom(16);
             break;
             case 0.50:
             map.setZoom(15);
             break;
             case 1:
             map.setZoom(14);
             break;
             case 5:
             map.setZoom(12);
             break;
             case 10:
             map.setZoom(11);
             break;

             }
             *
             */
        },

        // Markers for comps
        createMarker: function(latLong, id, i, complete)
        {
            var icon = new GIcon();
            (complete == "true") ? icon.image = 'images/markers/' + (parseInt(i) + 1) + '_green.png' : icon.image = 'images/markers/' + (parseInt(i) + 1) + '.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(9, 34);
            icon.infoWindowAnchor = new GPoint(10, 15);

            var marker = new GMarker(latLong, icon);
            // Show this marker's index in the info window when it is clicked
            markers[id] = marker;
            GEvent.addListener(marker, "click", function()
            {
                currentMarker = id;
                Map.showPopup(id);
            });
            return marker;
        },

        //Displayed when user clicks on a comp marker- displays property summary
        openPopup: function(id, text)
        {
            if (markers && markers[id])
            {
                markers[id].openInfoWindowHtml(text);
            }
            else
            {
                // comp many not be loaded yet
                setTimeout("Map.openPopup(" + id + ")", 200);
            }
        },

        showPopup: function(id)
        {
            Map.showLoading();
            var callback = {
                success: function(response)
                {
                    Map.openPopup(id, response.responseText);
                    Map.hideLoading();
                },
                failure: function()
                {
                    alert('Could not connect to server');
                }
            }
            var conn = YAHOO.util.Connect.asyncRequest('POST', urlBase + 'gis_lookup.m', callback, 'id=' + id + '&showsummary=true');
        },

        setBounds: function(bounds)
        {
            mapBounds = bounds;
        },

        getBounds: function()
        {
            return mapBounds;
        },

        validateRadius: function()
        {
            var radius = Dom.get('radius').value;
            if (radius == "" || radius <= "0" || isNaN(radius))
            {
                alert("Please enter a valid radius");
                return false;
            }
        },
        parseAddress: function()
        {
            var radius = Dom.get('radius').value;
            if (countyOverlay)
            {
                //If there was already a county polygon defined, remove it
                map.removeOverlay(countyOverlay);
                countyOverlay = null;
            }

            if (!Map.validateRadius)
            {
                alert("invalid radius");
                return false;
            }
            var address = Dom.get('address').value;
            if (!isNaN(address))
            {
                if (address.length != 11)
                {
                    (address.length == 5) ? Map.findByAddress(address) : alert('Could not find ' + address);
                }
                else
                {
                    Map.findByCensus(address);
                }
            }
            else if (address.match(/[a-z\ \'-]+\s+(County|Parish)/i))
            {
                var county = address.match(/[a-z\ \'-]+\s+(County|Parish)/i)[0];
                var state = "";
                var stateTest = address.match(/,\s*([a-z\ ]+)\s*/i);
                if (stateTest)
                {
                    state = stateTest[1];
                }
                Map.findByCounty(county, state);
            }
            else
            {
                Map.findByAddress(address);
            }
        },

        findByAddress: function(address)
        {
            geocoder.getLatLng(address, function(latlng)
            {
                if (latlng)
                {

                    Map.zoomToLatLng(latlng);
                    Map.addSearchMarker(latlng, address);
                    Map.drawCenter(latlng.lat(), latlng.lng());
                    resetQuickFactsTable();                    
                }
                else
                {
                    alert("Could not locate '" + address + "' ");
                }
            });
        },

        findByCounty: function(county, state)
        {
            usedUrlParams = "county=" + escape(county) +
                            "&stateProvince=" + escape(state) +
                            "&search=true" +
                            "&radius=" + Dom.get('radius').value +
                            "&" + Dom.get('lstMapType').value + "=true";
            var callback = {
                success: function(response)
                {
                    var jsonText = YAHOO.lang.JSON.parse(response.responseText);
                    if (!jsonText)
                    {
                        alert("error parsing data");
                        Map.goToInvalidState();
                        Map.hideLoading();
                        return;
                    }
                    if (jsonText.errormessage && jsonText.errormessage != "")
                    {
                        alert(jsonText.errormessage);
                        Map.goToInvalidState();
                        Map.hideLoading();
                        return;
                    }


                    //	map.setZoom(maxZoom);
                    var latlng = new GLatLng(jsonText.latitude, jsonText.longitude);
                    Map.zoomToLatLng(latlng);
                    Map.hideLoading();
                    var countyPolygons = jsonText.polygons;
                    Map.clear();


                    for (var i = 0; i < countyPolygons.length; i++)
                    {
                        var thisLatLng = new GLatLng(countyPolygons[i].y, countyPolygons[i].x)
                        poly.push(thisLatLng);
                    }

                    //    Map.drawCounty(countyPolygons);
                    Map.drawSelectedRegion(countyPolygons);
                    Map.loadComps(usedUrlParams, false);
                },
                failure: function(response)
                {

                }
            }
            resetQuickFactsTable();
            var conn = YAHOO.util.Connect.asyncRequest('POST', urlBase + 'gis_search.m', callback, usedUrlParams);
        },

        // Just zoom to point on map and let findByBounds called by the map move listener take care of the rest
        findByCensus: function(tractNumber)
        {
            var urlparams = "censustractNumber=" + tractNumber +
                            "&search=true" +
                            "&showpolygon=true" +
                            "&radius=" + Dom.get('radius').value;
            var callback = {
                success: function(response)
                {
                    currentView = "census";
                    var jsonText = YAHOO.lang.JSON.parse(response.responseText);
                    if (!jsonText)
                    {
                        alert("error parsing data");
                        Map.goToInvalidState();
                        Map.hideLoading();
                        return;
                    }
                    if (jsonText.errormessage && jsonText.errormessage != "")
                    {
                        alert(jsonText.errormessage);
                        Map.goToInvalidState();
                        Map.hideLoading();
                        return;
                    }
                    var latlng = new GLatLng(jsonText.latitude, jsonText.longitude);
                    Map.zoomToLatLng(latlng);
                    Map.addSearchMarker(latlng, tractNumber);
                    Map.hideLoading();

                },
                failure: function(response)
                {
                }
            }
            resetQuickFactsTable();
            var conn = YAHOO.util.Connect.asyncRequest('POST', urlBase + 'gis_search.m', callback, urlparams);
        },

        findByBounds: function()
        {
            var bounds = map.getBounds();
            //            var urlparams = "";
            if (polygonOverlay)
            {
                var ovPoints = polygonOverlay["points"];
                usedUrlParams = "findByPolygon=true" +
                                "&zoomlevel=" + map.getZoom() +
                                "&pn=" + ovPoints.length +
                                "&radius=" + Dom.get('radius').value +
                                "&" + Dom.get('lstMapType').value + "=true" +
                                "&searchterm=" + encodeURI(Dom.get('address').value)

                for (i = 0; i < ovPoints.length; i++)
                {
                    usedUrlParams += "&px[" + i + "]=" + ovPoints[i].x;
                    usedUrlParams += "&py[" + i + "]=" + ovPoints[i].y;
                }
                //      console.log(urlparams);
            }
            else
            {
                var minY = bounds.getSouthWest().lat();
                var minX = bounds.getSouthWest().lng();
                var maxY = bounds.getNorthEast().lat();
                var maxX = bounds.getNorthEast().lng();

                usedUrlParams = "findByBounds=true" +
                                "&maxX=" + maxX +
                                "&minX=" + minX +
                                "&maxY=" + maxY +
                                "&minY=" + minY +
                                "&radius=" + Dom.get('radius').value +
                                "&" + Dom.get('lstMapType').value + "=true" +
                                "&searchterm=" + encodeURI(Dom.get('address').value);
            }

            switch (Dom.get('lstMapType').value)
                    {
                case 'showcomps':
                    tooltip('addPoints');

                    if(!polygonOverlay)
                        Map.drawCircle(true);

                    Map.loadComps(usedUrlParams);
                    break;
                case 'showcensus':
                    Map.loadCensusTracts(usedUrlParams);
                    break;
                case 'showcongress':
                    Map.loadCongressDistrict(usedUrlParams);
                    break;
            }
        },

        populateQuickFacts: function(doAddReport)
        {
            //    console.log(polygonOverlay);
            var urlparams = "loadquickfacts=true" +
                            "&byPolygon=true" +
                            "&radius=" + Dom.get('radius').value +
                            "&zoomlevel=" + map.getZoom() ;
            //Check if user has a polygon which hasn't been searched for yet
            if (poly.length >= 3)
            {
                urlparams += "&pn=" + poly.length;
                for (i = 0; i < poly.length; i++)
                {
                    urlparams += "&px[" + i + "]=" + poly[i].x;
                    urlparams += "&py[" + i + "]=" + poly[i].y;
                }
                Map.findByPolygon();
            }
            //Check if user already has a saved polgon
            else  if (polygonOverlay != null)
            {
                var ovPoints = polygonOverlay["points"];

                urlparams += "&pn=" + ovPoints.length;
                for (i = 0; i < ovPoints.length; i++)
                {
                    urlparams += "&px[" + i + "]=" + ovPoints[i].x;
                    urlparams += "&py[" + i + "]=" + ovPoints[i].y;
                }
            }

            //Load it for entire circle
            else
            {
                Map.drawCircle(true);
                urlparams += "&pn=" + radiusPoints.length;
                for (i = 0; i < radiusPoints.length; i++)
                {
                    urlparams += "&px[" + i + "]=" + radiusPoints[i].x;
                    urlparams += "&py[" + i + "]=" + radiusPoints[i].y;
                }
            }
            Dom.get('contQuickFacts').innerHTML =
            "<table class='RightPaneModule'  id='quickfacts' style='height: 199px;'>" +
            " <tr> <td colspan=2 style='width:25%'></td> <td> Retrieving area data... <img src='images/wait_wheel.gif'></td> </td>";
            "</tr> </table>";
            var callback = {
                success: function(response)
                {
                    Dom.get('contQuickFacts').innerHTML = response.responseText;
                    if (doAddReport === true)
                    {
                        addDemandReportToCart2();
                    }
                }
            }
            var conn = YAHOO.util.Connect.asyncRequest('POST', urlBase + 'gis_search.m', callback, urlparams);

        },

        isListView: function()
        {
            var view = Dom.hasClass('listli', 'selected') ;
            return view;
        },

        populateCompsTab: function()
        {
            if (!Map.isValid())
            { return}
            ;
            Map.showLoading();

            usedUrlParams += "&tax_credit=" + Dom.get('chkTaxCredit').checked +
                             "&elderly=" + Dom.get('chkElderly').checked +
                             "&building_type=" + Dom.get('lstCompType').value +
                             "&loadrentinfo=true";
            var callback = {
                success : function(oRequest, oResponse, oPayload)
                {
                    //if search is by radius only
                    if (useRadius)
                    {
                        //miles to meters
                        var radiusInMeters = Dom.get("radius").value * 1609.344;

                        //filter out items that are out radius range
                        var results = oResponse.results;

                        for (var i = results.length - 1; i >= 0; i--)
                        {
                            var result = results[i];
                            var latlng = new GLatLng(result.lat, result.lng);

                            if (map.getBounds().getCenter().distanceFrom(latlng) > radiusInMeters)
                            {
                                //remove from list
                                results.splice(i, 1);
                            }
                        }
                    }

                    var sortCol = compsDataTable.getColumn('completeAddress');
                    compsDataTable.onDataReturnInitializeTable(oRequest, oResponse, oPayload);
                    pg.setTotalRecords(oResponse.results.length);
                    pg.setPage(1);
                    if (parseInt(Dom.get('address').value) && Dom.get('address').value.length == 5)
                    {
                        compsDataTable.sortColumn(sortCol, 'asc');
                    }
                    Map.populateReports();
                    Map.hideLoading();
                },
                failure : function(o)
                {
                    alert("Too many items found. Please try searching again for a smaller radius.");
                    Map.hideLoading();
                },
                scope : compsDataTable
            };

            compsDataSource.sendRequest(usedUrlParams, callback);
        },

        //Called when user clicks on "Find within polygon"
        findByPolygon: function()
        {

            usedUrlParams = "findByPolygon=true" +
                            "&zoomlevel=" + map.getZoom() +
                            "&pn=" + poly.length +
                            "&radius=" + Dom.get('radius').value +
                            "&" + Dom.get('lstMapType').value + "=true" +
                            "&excludedIds=" +
                            "&searchterm=" + encodeURI(Dom.get('address').value)

            for (i = 0; i < poly.length; i++)
            {
                usedUrlParams += "&px[" + i + "]=" + poly[i].x;
                usedUrlParams += "&py[" + i + "]=" + poly[i].y;
            }
            Map.clear();
            Map.loadSelectedPolygon(usedUrlParams, Dom.get('lstMapType').value);
        },

        addOverlays: function(overlays)
        {
            for (var i = 0; i < overlays.length; i++)
            {
                map.addOverlay(overlays[i]);
            }
        },

        handleViewChange: function(noRefresh)
        {
            var option = Dom.get('lstMapType').value;
            //            if (! (noRefresh === true))
            //            {
            //                Map.clear();
            //            }
            switch (option)
            {
                case 'showcomps':
                    Dom.setStyle('divFilterComp', 'display', '');
                    if (!Map.isValid())
                    { return};

                    //clear only markers is currently showing comps
                    Map.clear(lastMapType == option);
                    Map.doCompFilter();
                    break;
                case 'showcensus':
                    Dom.setStyle('divFilterComp', 'display', 'none');
                    if (!Map.isValid())
                    { return};
                    Dom.setStyle('btnPolySearch', 'display', 'none');
                    Dom.setStyle('btnClear', 'display', 'none');

                    Map.clear();

                    Map.findByBounds();
                    break;
                case 'showcongress':
                    Dom.setStyle('divFilterComp', 'display', 'none');
                    if (!Map.isValid())
                    { return};
                    Dom.setStyle('btnPolySearch', 'display', 'none');
                    Dom.setStyle('btnClear', 'display', 'none');

                    Map.clear();
                        
                    Map.findByBounds();
                    break;
            }
            
            Map.populateCompsTab();
            lastMapType = option;
        },


        clear: function(clearMarkersOnly)
        {
            if (clearMarkersOnly)
            {
                for (var i = 0; i < drawnMarkers.length; i++)
                {
                    map.removeOverlay(drawnMarkers[i]);
                }

                drawnMarkers = [];
            }
            else
            {
                map.clearOverlays();
                drawnMarkers = [];
                Map.resetMaxZoom();
                excludedCensusTracts = [];
                excludedCongDistricts = [];
                excludedComps = [];
                circleOverlay = null;
                polygonOverlay = null;
                radiusPoints = [];
                //     gPoly = null;
                //    gPolyLast = null;
                //    gPolyPoints = [];
            }

        },

        drawMarkers: function(nearbyComps)
        {
            Map.showLoading();
            Map.resetMaxZoom();
            if (map.getZoom() < maxZoom)
            {
                map.setZoom(maxZoom);
            }

            if(nearbyComps)
            {
                for (var i = 0; i < nearbyComps.length; i++)
                {
                    var comp = nearbyComps[i];

                    var newMarker = Map.createMarker(new GLatLng(comp.latitude, comp.longitude),
                            comp.id,
                            comp.loop_index,
                            comp.complete);
                    //   if(findInArray(excludedComps,  comp.id) === false){
                    // 	     excludedComps.push(comp.id);
                    map.addOverlay(newMarker);
                    drawnMarkers.push(newMarker);
                    //   }
                }
            }

            var nearby_list = document.getElementById('nearby_list_section');
            if (nearby_list && isShowMarkers())
            {
                displayOther(1, 1, nearby_list);
            }
            else if (nearby_list)
            {
                displayOther(1, 0, nearby_list);
            }
            Map.hideLoading();
        },

        resetMaxZoom: function()
        {
            maxZoom = 10;
            //map.setZoom(maxZoom);
        },

        drawCensusTracts: function(censuspoints)
        {
            Map.showLoading();
            tooltip('censuslegend');
            var censusTracts = [];
            var censusTractMarkers = [];
            var color_i = 0;
            var ct_points, polygon, points;

            if (censuspoints.length < 30)
            {
                // If lesser than 30 tracts can be displayed on screen, allow zoom out till you can display more
                var currentZoom = map.getZoom();
                //   .log(currentZoom, maxZoom);
                if (currentZoom == maxZoom)
                {
                    maxZoom --;
                }
            }
            else
            {
                Map.resetMaxZoom();
            }

            for (var i = 0; i < censuspoints.length; i++)
            {
                polygon = censuspoints[i].polygon;

                var gpolygon = new GPolygon.fromEncoded({
                    polylines: [
                        {
                            points: polygon.enctrack.encodedPoints,
                            levels: polygon.enctrack.encodedLevels,
                            color: "#9900cc",
                            opacity:1,
                            shadow: false,
                            weight: 2,
                            numLevels: 18,
                            zoomFactor: 2
                        }
                    ],
                    fill: false,
                    color: "#9900cc",
                    opacity: 1.0,
                    outline: true
                });
                censusTracts.push(gpolygon);
                if (findInArray(excludedCensusTracts, polygon.referenceId) === false)
                {
                    excludedCensusTracts.push(polygon.referenceId);
                    Map.createPolygonAreaMarker(
                            polygon.center.y,
                            polygon.center.x,
                            censusTracts[censusTracts.length - 1],
                            polygon.desc,
                            true,
                            censusTractMarkers,
                            PURPLE_ICON
                            );
                }
            }
            Map.hideLoading();
        },

        drawCongressDisctricts: function(congdistricts)
        {
            Map.resetMaxZoom();

            if (map.getZoom() < maxZoom)
            {
                map.setZoom(maxZoom);
            }
            Map.showLoading();
            tooltip('congresslegend');
            var congressionalDistricts = [];
            var congressionalDistrictMarkers = [];
            var color_i = 0;
            for (var i = 0; i < congdistricts.length; i++)
            {
                var cg_points = [];
                var polygon = congdistricts[i].polygon;

                var gpolygon = new GPolygon.fromEncoded({
                    polylines: [
                        {
                            points: polygon.enctrack.encodedPoints,
                            levels: polygon.enctrack.encodedLevels,
                            color: "#0000ff",
                            opacity:1,
                            shadow: false,
                            weight: 2,
                            numLevels: 18,
                            zoomFactor: 2
                        }
                    ],
                    fill: false,
                    color: "#0000ff",
                    opacity: 1.0,
                    outline: true
                });

                congressionalDistricts.push(gpolygon);
                if (findInArray(excludedCongDistricts, polygon.districtId) === false)
                {
                    excludedCongDistricts.push(polygon.districtId);
                    Map.createPolygonAreaMarker(
                            polygon.center.y,
                            polygon.center.x,
                            congressionalDistricts[congressionalDistricts.length - 1],
                            polygon.desc,
                            true,
                            congressionalDistrictMarkers,
                            BLUE_ICON
                            );
                }

            }
            Map.hideLoading();
        },

        createPolygonAreaMarker: function(lat, lng, gPolygon, desc, isShow, markers, icon)
        {
            //			      console.log("createPolygonAreaMarker")
            var marker = new GMarker(new GLatLng(lat, lng), icon);
            markers.push(marker);
            GEvent.addListener(marker, 'mouseover', function()
            {
                gPolygon.opacity = 0.5;
                gPolygon.fill = true;
                gPolygon.redraw(true);
            });
            GEvent.addListener(marker, 'mouseout', function()
            {
                gPolygon.opacity = 0.25;
                gPolygon.fill = false;
                gPolygon.redraw(true);
            });
            GEvent.addListener(marker, 'click', function()
            {
                marker.openInfoWindowHtml('<h4>' + desc + '</h4>');
            });
            (isShow) ? Map.addOverlays([gPolygon, marker]) : {};
        }

    }
}();


function findInArray(ipArray, value)
{
    for (var i = 0; i < ipArray.length; i++)
    {
        if (ipArray[i] == value)
        {
            return i;
        }
    }
    return false;
}


function selectListOption(elemId, elemText)
{
    var lstElem = Dom.get(elemId);
    for (var j = 0; j < lstElem.options.length; j++)
    {
        if (lstElem.options[j].value == elemText)
        {
            //			    console.log(lstElem.options[j].value, elemText);
            lstElem.selectedIndex = j;
            break;
        }
    }
}
	

