window.param_provIso = 'on';

var _cm_map = null;
var cm_mapMarkers = [];
var cm_markersByBrokerageIdent = {};
var cm_mapHTMLS = [];

var cm_canadaCodes = {};
cm_canadaCodes['ns'] = new GLatLng(44.646160, -63.573919);
cm_canadaCodes['ab'] = new GLatLng(53.54622, -113.490374);
cm_canadaCodes['on'] = new GLatLng(48.253775,-83.323214);

cm_canadaCodes['qc'] = new GLatLng(48.253775,-83.323214);
cm_canadaCodes['nb'] = new GLatLng(48.253775,-83.323214);
cm_canadaCodes['mb'] = new GLatLng(48.253775,-83.323214);
cm_canadaCodes['bc'] = new GLatLng(48.253775,-83.323214);
cm_canadaCodes['pe'] = new GLatLng(48.253775,-83.323214);
cm_canadaCodes['sk'] = new GLatLng(48.253775, -83.323214);
cm_canadaCodes['nl'] = new GLatLng(48.253775,-83.323214);
cm_canadaCodes['nt'] = new GLatLng(48.253775,-83.323214);
cm_canadaCodes['yt'] = new GLatLng(48.253775,-83.323214);
cm_canadaCodes['nu'] = new GLatLng(48.253775,-83.323214);

// global storage object for debug data to hang off.
window.misDebugStash = {
  // The show method displays any data hanging off this object.
  show: function() {
    var msg = '';
    for(var i in this) {
      if (this[i] != this.alert)
        msg += i + ': ' + this[i] + '\n';
    }
    alert(msg);
  }
}

/* Create a base icon for all of our markers that specifies the
 shadow, icon dimensions, etc. */
var cm_baseIcon = new GIcon();
cm_baseIcon.shadow = "http://www.google.com/mapfiles/shadow50.png";
cm_baseIcon.iconSize = new GSize(20, 34);
cm_baseIcon.shadowSize = new GSize(37, 34);
cm_baseIcon.iconAnchor = new GPoint(9, 34);
cm_baseIcon.infoWindowAnchor = new GPoint(9, 2);
cm_baseIcon.infoShadowAnchor = new GPoint(18, 25);


/* Change these parameters to customize map
 This is the Google spreadsheet information to acquire map points from */
var param_wsId = "od6";

//var param_publishKeyBrief = "pnRwzbVGvlHCbviv8Wa8tWw";
//var param_publishKeyDetailed = "pnRwzbVGvlHA3jIGvLKYFBg";

var param_publishKeyCanada = "pnRwzbVGvlHBzevKmciVkYA"; // "canada"
var param_publishKeyBrief = "pnRwzbVGvlHAWkC-jKVW3ew"; // "brief"
var param_publishKeyDetailed = "pnRwzbVGvlHD11TrpBw8vVg"; // "detail"

// ****************************
// *** Canada Codes GSX 
//
// CodeDbId	IsoCode	Description	 Lat	Lng
// canada_codes - http://spreadsheets.google.com/ccc?key=pnRwzbVGvlHBzevKmciVkYA
// FEED@ http://spreadsheets.google.com/feeds/list/pnRwzbVGvlHBzevKmciVkYA/od6/public/values

// ****************************
// *** Brief GSX 
//
// ID	COMPANY	ADDRESS_1	ADDRESS_2	longitude	latitude	MISFlag	PROVINCE_ISO
// mis_brief - http://spreadsheets.google.com/ccc?key=pnRwzbVGvlHAWkC-jKVW3ew
// FEED@ http://spreadsheets.google.com/feeds/list/pnRwzbVGvlHAWkC-jKVW3ew/od6/public/values

// ****************************
// *** Detail GSX 
//
// ID	COMPANY	ADDRESS_1	ADDRESS_2	CITY	ZIP	WORK_PHONE	TOLL_FREE	WEBSITE	IDUnique	PROVINCE_ISO
// mis_details - http://spreadsheets.google.com/ccc?key=pnRwzbVGvlHD11TrpBw8vVg
// FEED@ http://spreadsheets.google.com/feeds/list/pnRwzbVGvlHD11TrpBw8vVg/od6/public/values

var param_useSidebar = false;
var param_titleColumn = "company";
var param_identColumn = "identity";
var param_descriptionColumn = "description";
var param_latColumn = "latitude";
var param_lngColumn = "longitude";
var param_rankColumn = "";
var param_cmIconType = "green";
var param_cmIconOverType = "orange";
var param_srchIconType = "red";
var param_srchIconOverType = "pink";
var param_brokerageId = "bid"; // Key name to used for brokerage ID values in any collection.
var param_address = "adr"; // Key name used to access address value on a marker.
var param_markerVisibilityZoomLevel = 10; // The zoom level at which markers are made visible
var param_markerSelectZoomLevel = 17; // When a company listing is selected, zoom the marker to this level
var param_mapStartZoom = 5; // This zoom shows most of Ontario


var param_companyUpdateWaitMilli = 0; /* To force a waiting period between when the uesr finishes scrolling the map 
and when the company list update begins. A waiting period allows the user time to scroll the map again without being
interrupted by an immediate company listing update.
*/
var param_postalLookupZoomLevel = 11;

var param_limitCoUpdateToMarkerVis = true; /* If true, will update the company listing only when markers are visible,
otherwise the company listing will always be updated even when markers are not yet visible. */
var param_lockToVisibleZoomLevel  = true; /* If true, once the threshold is passed where markers start to show,
the user cannot back out of the map further and is limited to zooming within the visible marker ranges.
*/
var param_retainInfoWindowData = true;
var param_ibaoQuotingUrl = '/html/find_a_broker/locator.asp?p=[iso]&id=[id]&CmdAdvancedSearch=AdvancedSearch&CmdLookupPieces=Search';
var param_ibaoUrlIdentPlaceholder = '[id]';
var param_ibaoUrlIsoPlaceholder = '[iso]';


var briefCol_id = 'id';
var briefCol_company = 'company';	
var briefCol_address1 = 'address1';
var briefCol_address2 = 'address2';
var briefCol_longitude = 'longitude';
var briefCol_latitude = 'latitude';
var briefCol_misFlag = 'misflag';
var misEnabledValue = 'y';
var briefCol_provIso = 'provinceiso'

var detailCol_id = 'id';
var detailCol_provIso = 'provinceiso';
var detailCol_company = 'company';	
var detailCol_address1 = 'address1';
var detailCol_address2 = 'address2';
var detailCol_city = 'city';
var detailCol_zip = 'zip';
var detailCol_workPhone = 'work_phone';
var detailCol_tollFree = 'toll_free';
var detailCol_website = 'website';

var canadaCol_CodeDbId = 'codedbid';
var canadaCol_IsoCode = 'isocode';
var canadaCol_Description = 'description';
var canadaCol_Latitude = 'lat';
var canadaCol_Longitude = 'lng';

var _brokerInfoWindowOpts = {  
    selectedTab: null,
    maxWidth: 250,
    noCloseOnClick: false,
    onOpenFn: null,
    onCloseFn: null,
    zoomLevel: null,
    mapType: null,
    maxContent: null,
    maxTitle: null, 
    pixelOffset: null
};

var _searchInfoWindowOpts = {  
    selectedTab: null,
    maxWidth: null,
    noCloseOnClick: false,
    onOpenFn: null,
    onCloseFn: null,
    zoomLevel: null,
    mapType: null,
    maxContent: null,
    maxTitle: null, 
    pixelOffset: null
};


/* Creates a string showing properties of the given object.
*/
function GetJsObjectInfo(o) {
    
    var arr = new Array();
    for(var p in o)
        arr[arr.length] = p;
    arr.sort();
    
    var msg = '';
    for (var i in arr) {
        msg += arr[i] + '\n';
    }
    return msg;
}


var _soughtLocation = '';

/* Callback 
*/
function OnSearchBarCompleted(gsrch) { //http://code.google.com/apis/ajaxsearch/documentation/reference.html#_class_GlocalResult
    NixInstructions();
    var msg = '';
    if (gsrch.results.length > 0) {
        var point = null;
        for(var i = 0; i < gsrch.results.length; ++i) {
            var gLocResult = gsrch.results[i];
            msg += gLocResult.title + '\n';
            _soughtLocation = gLocResult.title;
            point = new GLatLng(parseFloat(gLocResult.lat), parseFloat(gLocResult.lng));
            _recentSearchPoint = point;            
        }        
        if (point) {
            save_map();
            _cm_map.setCenter(point, param_markerVisibilityZoomLevel);
        }
    }
    
}

function restore_map() {
    var vLat = get_cookie("cooklat");
    if (vLat) {
        var vLng = get_cookie("cooklng");
        _soughtLocation = get_cookie("cookloc");
        point = new GLatLng(parseFloat(vLat), parseFloat(vLng));
        var m = srch_createMarker(point, _soughtLocation);
        _cm_map.addOverlay(m);
        _searchMarkers.push(m);
        _cm_map.setCenter(point, param_markerVisibilityZoomLevel);
    }
}

_noRestore = false;

function clear_saved_map() {
    _resettingMapNow = true;
    _noRestore = true;
    document.cookie="cooklat=;expires=Fri, 27 Jul 2001 02:47:11 UTC; path=/";
    document.cookie="cooklng=;expires=Fri, 27 Jul 2001 02:47:11 UTC; path=/";
    document.cookie="cookloc=;expires=Fri, 27 Jul 2001 02:47:11 UTC; path=/";
    
    _cm_map.setCenter(cm_canadaCodes[param_provIso], param_mapStartZoom); 
    ClearSearchMarkers();
    ClearCompaniesList();
    _resettingMapNow = false;
    
    MakeInstructions();
}

function save_map() {
    document.cookie="cooklat=" + _recentSearchPoint.lat();
    document.cookie="cooklng=" + _recentSearchPoint.lng();
    document.cookie="cookloc=" + _soughtLocation;
}

var _recentSearchPoint = null;
var _searchMarkers = [];

function ClearSearchMarkers() {
    for(i in _searchMarkers) {
        var m = _searchMarkers[i];
        _cm_map.removeOverlay(m);
    }
    _searchMarkers = [];
}

function OnMarkersSet(arr) { // each array element is {result: GlocalSearch, marker: GMarker}
    ClearSearchMarkers();
    
    if (arr.length == 0)
        return;

    // Replace default markers generated by Search with custom markers.
    for (i = 0; i < arr.length; ++i) {
        var m = arr[i].marker;
        m.hide(); // hide search marker
        // Put a custom marker in the same place.
        AddNewSearchMarker(m.getLatLng(), _soughtLocation);
    }
    
}

function AddNewSearchMarker(location, text) {
    var marker2 = srch_createMarker(location, text);
    _cm_map.addOverlay(marker2);
    _searchMarkers.push(marker2);
}

function OnMarkerHtmlCallback(marker, el, glocalSchResult) {
    //alert(GetJsObjectInfo(glocalSchResult));
    marker.openInfoWindowHtml('Point of reference: ' + _soughtLocation, _brokerInfoWindowOpts);
}


var _markerMgr = null;



function OnManagedMarkersChanged(bounds, markerCount) {
//    _isMarkerManagerDone = true;
    //alert('mmc');
    InitUpdateCompanyList();
}



var _coUpdateCancelerFn = function() {
    if (_coUpdateTimer != null) {
        clearTimeout(_coUpdateTimer);
        _coUpdateTimer = null;
    }
    _coUpdateIsCanceled = true;
}
var _coUpdateTimer = null;
var _coUpdateIsCanceled = false;

function InitUpdateCompanyList() {
    _coUpdateCancelerFn();
    
    _coUpdateIsCanceled = false; // in preparation for initiating update of company list
    _coUpdateTimer = setTimeout('UpdateCompanyList()', param_companyUpdateWaitMilli);    
}

var _aHrefBrokerageTargeterFn = function() {
                    var bkgId = this[param_brokerageId];
                    if (! bkgId)
                        return;
                    var m = cm_markersByBrokerageIdent[bkgId];
                    if (!m)
                        return;
                    _cm_map.setCenter(
                        m.getLatLng(), 
                        (_cm_map.getZoom() < param_markerSelectZoomLevel ? param_markerSelectZoomLevel : _cm_map.getZoom())
                    );
                    Init_LoadBrokerageInfoWindowDetail(bkgId);
                    return false;
                    };

// Returns a random integer between min and max
// Using Math.round() will give you a non-uniform distribution!
function getRandomInt(min, max) {
  return Math.floor(Math.random() * (max - min + 1)) + min;
}

var _randomSortMax = 1;
var _randomSortCurrent = 0;

function initSortRandom(maxTimes) {
    _randomSortMax = maxTimes;
    _randomSortCurrent = 0;
}

function sortRandom(a,b) {
    if (_randomSortCurrent >= _randomSortMax)
        return 0;
    _randomSortCurrent++;
    var n = getRandomInt(-1, 1);
    return n;
}

function CountedObject() {

    // Set a property of the object and count it.
    this.set = function(key, value) {
        this.count++;
        this[key] = value;
    }
    
    // How many times set was called.
    this.count = 0;
}

var _previousVisMarkers = new CountedObject();
var _currentVisMarkers = new CountedObject();

// Compares previous and current set of visible markers and tells if there has been any change.
function HasUnchangedMarkerSet() {
    if (_previousVisMarkers.count != _currentVisMarkers.count)
        return false;
    for(var m in _currentVisMarkers) {
        if (! isGMarker(m))
            continue; //skip
        if (! _previousVisMarkers[m])
            return false;
    }
    return true; // no differences detected
}

// Tells if the given object is a GMarker.
function isGMarker(m) {
    return m && m.getTitle && m.getIcon && m.getLatLng; //check for known method existences
}

function UpdateCompanyList()
{
    if (_coUpdateIsCanceled)
        return;
        
    var hashVisMarkers = new CountedObject();
    var arrVisMarkers = [];
    
    var ctr = 0;
    var mapGeoBounds = _cm_map.getBounds();

    // Find visible markers for inclusion in the company list.
    for(var i in cm_mapMarkers) {

        if (_coUpdateIsCanceled )
            return;
            
        var m = cm_mapMarkers[i];
        var geoPt = m.getLatLng();

        if (
            // check visiblity settings
            ( ! param_limitCoUpdateToMarkerVis || (param_limitCoUpdateToMarkerVis && _cm_map.getZoom() >= param_markerVisibilityZoomLevel) )
            // and ensure marker is in map viewport boundary
            && mapGeoBounds.contains(geoPt)
            ) {
            
            ++ctr;
            hashVisMarkers.set(m, 1);
            arrVisMarkers.push(m);
                        
        } //end map viewport check
    } //end for marker

    /* There's no need to display the company list if the markers haven't changed.
    Return now if there have been no changes.
    */
    // Track state of markers.
    _previousVisMarkers = _currentVisMarkers;
        _currentVisMarkers = hashVisMarkers;

    // Test for change.
    if ( ! HasUnchangedMarkerSet() ) {

        // Display the HTML listing of companies again.
        var divResultList = document.createElement('div');
        
        var maxSort = arrVisMarkers.length * 3;
        initSortRandom(maxSort);
        arrVisMarkers.sort(sortRandom);
        
        for (var i in arrVisMarkers) {
                var m = arrVisMarkers[i];
                
                // build html for listing
                var aHrefCo = document.createElement('a');
                aHrefCo.className = 'PageCompanyName';
                aHrefCo[param_brokerageId] = m[param_brokerageId];
                aHrefCo.href='javascript:void()';
                GEvent.addDomListener(aHrefCo, "click", _aHrefBrokerageTargeterFn);
                aHrefCo.innerHTML = m.getTitle();
                
                var divAdr = document.createElement('div');
                divAdr.className = 'PageCompanyAddress';
                divAdr.innerHTML = m[param_address];
                
                var divCoBlock = document.createElement('div');
                divCoBlock.className = 'PageCompanyBlock';
                divCoBlock.appendChild(aHrefCo);
                divCoBlock.appendChild(divAdr);
                
                divResultList.appendChild(divCoBlock);
                
//                // Randomize the placement of the company in the result list
//                var posInsert = getRandomInt(0, divResultList.childNodes.length);
//                if (posInsert == ctr) { //append to end of list
//                    alert('insert at beginning');
//                    divResultList.appendChild(divCoBlock);
//                }
//                else { // insert before another company
//                    alert('insert before ' +  posInsert + ' of 0..' + divResultList.childNodes.length + ' obj: ' + divResultList.childNodes[posInsert] );
//                    var refEl = divResultList.childNodes[posInsert];
//                    divResultList.insertBefore(divCoBlock, refEl);
//                }
                
        } //end for marker (html gen)
        
        var elCompanyListing = document.getElementById('divCompanyList');
        while (elCompanyListing.childNodes.length != 0)
            elCompanyListing.removeChild(elCompanyListing.childNodes[0]);
        elCompanyListing.appendChild(divResultList);

        var divHeader = document.getElementById('divListHeader');
        divHeader.innerHTML = 'There are ' + ctr + ' brokerages in visible proximity.';

    } //end check for change in listing
    
    arrVisMarkers = null;
    hashVisMarkers = null;
    
    _coUpdateCancelerFn();
}

function sortNumber(a,b) {
    return a - b;
}

function ClearCompaniesList() {
    var elCompanyListing = document.getElementById('divCompanyList');
    elCompanyListing.innerHTML = '';
}

function MakeInstructions() {
    var divInstruction = document.createElement('div');
    //divInstruction.innerHTML = '<img src="map/instruct.png" border="0" />';   
    var html = '';
    html += '<img src="map/arrow.png" border="0" style="position:absolute;top:100px;left:0px" />'
    html += '<div onClick="NixInstructions()" style="border:1px solid black;background-color:white;padding:10px;padding-top:15px;width:225px;height:110px;overflow:hidden;font-size:14px;font-weight:bold;font-family:Verdana;text-align:center;vertical-align:middle">';
    html += 'Enter your postal code or street address with city name to locate insurance brokerages near you!' 
    html += '</div>';
    divInstruction.innerHTML = html;
    instructionOverlay = CreateHtmlOverlay( divInstruction, true, new GScreenPoint(90, 235) );
    _cm_map.addOverlay(instructionOverlay);
}

function NixInstructions() {
    if (instructionOverlay) {
        _cm_map.removeOverlay(instructionOverlay);    
        instructionOverlay = null;
    }
}

//var _isMapMoveEnded = false;
//var _isMarkerManagerDone = false;

function OnMapMoveStarted() {
    //_isMapMoveEnded = false;
    //_isMarkerManagerDone = false;
    _coUpdateCancelerFn();
    return;
}

var _resettingMapNow = false;
var _zoomStickLow = false;
function OnZoomEnded(oldLevel, newLevel) {
    if ( param_lockToVisibleZoomLevel && ! _resettingMapNow ) {
        if (oldLevel >= param_markerVisibilityZoomLevel && newLevel < param_markerVisibilityZoomLevel) {
            _cm_map.setZoom(param_markerVisibilityZoomLevel);
            _zoomStickLow = true;
        }
    }
}

var _firstMove = true;

function OnMapMoveEnded() {
    if (_firstMove)
        _firstMove = false;
    else
        NixInstructions();
        
    InitUpdateCompanyList();
    return;
}

function CreateHtmlOverlay(element, isAbsolute, screenXY) {

    // Define HTML overlay object.
    function HtmlOverlay(element, isAbsolute, screenXY) {
        GOverlay();
        
        var _element = element; // HTML DOM element
        var _screenXY = screenXY; //GScreenPoint       
        var _map = null; // GMap2
        var _isAbsolute = isAbsolute; // boolean
        
        var _getOverlayContainer = function() {
            if (_isAbsolute)
                return _map.getContainer();
            return _map.getPane(G_MAP_MAP_PANE);
        }
        
        this.initialize = function (map) {
            _map = map;
            _getOverlayContainer().appendChild(_element);
            _element.style.position = _isAbsolute ? 'absolute' : 'relative';
            var domLeft = _screenXY.point.x;
            var domTop = _map.getSize().height - _screenXY.point.y; // calculate y from Gmap origin (bottom/left corner of viewport)
            if (isAbsolute) {
                _element.style.top = domTop;
                _element.style.left = domLeft;
            }
        }
        this.remove = function () {
            _getOverlayContainer().removeChild(_element);
        }
        this.copy = function () { //GOverlay
            alert('copy GHtmlOverlay');
            return null;
        }
        this.redraw = function(force) {
        }
    }
    
    // Create an instance of HTML overlay (using prototypical inheritance) and return it;
    var go = new GOverlay();
    HtmlOverlay.prototype = go;
    return new HtmlOverlay(element, isAbsolute, screenXY);
}

    
var instructionOverlay = null;
var _keyboardHandler = null;

/**
 * Loads map and calls function to load in worksheet data.
 */
function cm_load() {  
  if (GBrowserIsCompatible()) {

    // create the map
    var divResults = document.getElementById('divResults');
    var emptyResultList = document.createElement('div'); // or G_GOOGLEBAR_RESULT_LIST_SUPPRESS
    var barOptions = { resultList: emptyResultList, suppressInitialResultSelection: true, suppressZoomToBounds: true, showOnLoad: true, onSearchCompleteCallback: OnSearchBarCompleted, onMarkersSetCallback: OnMarkersSet, onGenerateMarkerHtmlCallback: OnMarkerHtmlCallback };
    
    var mapOptions = { googleBarOptions: barOptions };

    _cm_map = new GMap2( document.getElementById("cm_mapDiv"), mapOptions );
    _keyboardHandler = new GKeyboardHandler(_cm_map);
    _cm_map.addControl(new GLargeMapControl());
    
    var positionScaleControl = new GControlPosition(G_ANCHOR_BOTTOM_RIGHT, new GSize(10, 20));
    _cm_map.addControl(new GScaleControl(), positionScaleControl);

    var logo = new GScreenOverlay('bipper.png',
			    new GScreenPoint(10, .1, 'pixels', 'fraction'),  // screenXY
			    new GScreenPoint(0, 0),  // overlayXY
			    new GScreenSize(50, 50)  // size on screen
		    );
    _cm_map.addOverlay(logo);    
    
    _cm_map.enableGoogleBar();
    GEvent.addListener(_cm_map, 'movestart', OnMapMoveStarted);
    GEvent.addListener(_cm_map, 'moveend', OnMapMoveEnded);
    GEvent.addListener(_cm_map, 'zoomend', OnZoomEnded);
    
    
    _cm_map.setCenter(cm_canadaCodes[param_provIso], param_mapStartZoom); // middle of ontario
    InitGetJsonProvBriefs();

    if(! _noRestore)
        restore_map();

    if (! fnJumpToLookupLocation ) 
        MakeInstructions();
        

  } else {
    alert("Sorry, the Google Maps API is not compatible with this browser");
  } 

  _loadRan = true;  
  
  if (fnJumpToLookupLocation)
    JumpToLocation(fnJumpToLookupLocation());
}

var _loadRan = false;

function InitManageAllMarkers() {
    var mgrOptions = { borderPadding: 50, maxZoom: 15, trackMarkers: true };
    _markerMgr = new MarkerManager(_cm_map, mgrOptions);
    
    for (var i in cm_mapMarkers) {
        var m = cm_mapMarkers[i];
    }
    _markerMgr.addMarkers(cm_mapMarkers, param_markerVisibilityZoomLevel);
    GEvent.addListener(_markerMgr, 'changed', OnManagedMarkersChanged);

    setTimeout('_markerMgr.refresh()', 0);
    
    /*
    var gmaptype = cm_map.getCurrentMapType();
    var maxRes = gmaptype.getMaximumResolution();
    var minRes = gmaptype.getMinimumResolution();
    */
}


/**
 * Function that sorts 2 worksheet rows from JSON feed
 * based on their rank column. Only called if column is defined.
 * @param {rowA} Object Represents row in JSON feed
 * @param {rowB} Object Represents row in JSON feed
 * @return {Number} Difference between row values
 */
function cm_sortRows(rowA, rowB) {
  var rowAValue = parseFloat(rowA["gsx$" + param_rankColumn].$t);
  var rowBValue = parseFloat(rowB["gsx$" + param_rankColumn].$t);

  return rowAValue - rowBValue;
}


function InitGetJsonCanadaCodes() {
  alert('2');
  var script = document.createElement('script');

  script.setAttribute('src', 'http://spreadsheets.google.com/feeds/list'
                        + '/' + param_publishKeyCanada + '/' + param_wsId + '/public/values'
                        + '?'
                        + '&alt=json-in-script&callback=LoadMapJsonCanada'
                        + '&stamp=' + (new Date()).valueOf() );
  script.setAttribute('id', 'jsonScriptCanCodes');
  script.setAttribute('type', 'text/javascript');
  
  var node = document.getElementById("jsonScriptCanCodes");
  if (node)
    node.parentNode.replaceChild(script, node);
  else
    document.documentElement.firstChild.appendChild(script);

}


/**
 * Creates a script tag in the page that loads in the 
 * JSON feed for the specified key/ID. 
 * Once loaded, it calls cm_loadMapJSON.
 */
function InitGetJsonProvBriefs() {

  // Retrieve the JSON feed.
  var script = document.createElement('script');

  script.setAttribute('src', 'http://spreadsheets.google.com/feeds/list'
                        + '/' + param_publishKeyBrief + '/' + param_wsId + '/public/values'
                        + '?sq=' + escape(briefCol_misFlag + '=' + misEnabledValue + '&&' + briefCol_provIso + '=' + param_provIso)
                        + '&alt=json-in-script&callback=LoadMapJSONBriefs'
                        + '&stamp=' + (new Date()).valueOf() );
  script.setAttribute('id', 'jsonScriptBrief');
  script.setAttribute('type', 'text/javascript');
  
  var node = document.getElementById("jsonScriptBrief");
  if (node)
    node.parentNode.replaceChild(script, node);
  else
    document.documentElement.firstChild.appendChild(script);

}

/** 
 * Called when JSON is loaded. Creates sidebar if param_sideBar is true.
 * Sorts rows if param_rankColumn is valid column. Iterates through worksheet rows, 
 * creating marker and sidebar entries for each row.
 * @param {JSON} json Worksheet feed
 */       
function LoadMapJSONBriefs(json) {

  var bounds = new GLatLngBounds();	  

  if (!json.feed.entry) {
    alert('No data available for province "' + param_provIso + '".');
    return;
  }

  var trapIt = false;
  var gotAnother = false;
  var soughtThing = '';
  var count = 0;
  var processed = 0;
  for (var i = 0; i < json.feed.entry.length; i++) {
    count++;
    var entry = json.feed.entry[i];

    if(entry["gsx$" + briefCol_latitude]) {
      processed++;
      var lat = parseFloat(entry["gsx$" + briefCol_latitude].$t);
      var lng = parseFloat(entry["gsx$" + briefCol_longitude].$t);
      var brokerage_ident = parseInt(entry["gsx$" + briefCol_id].$t);
      var adr1 = CleanXCellValue(entry["gsx$" + briefCol_address1].$t);
      var adr2 = CleanXCellValue(entry["gsx$" + briefCol_address2].$t);
      var fullAdr = (adr1) ? ( adr1 + (adr2 ? (' ' + adr2) : '')) : adr2;
      var point = new GLatLng(lat,lng);
      var label = CleanXCellValue(entry["gsx$"+ briefCol_company].$t);

      if (label && label.indexOf('ASK') != -1 ) {
        trapIt = true;
      }
      else if (! gotAnother && count > 25) {
        gotAnother = true;
        trapIt = true;
      }
      if (trapIt) {
         soughtThing += "\n" + [lat, lng, brokerage_ident, adr1, adr2, fullAdr, point, label].join("|");
         trapIt = false;
      }

      // create the marker
      var marker = cm_createMarker(point,label,fullAdr,brokerage_ident);
    // Keep track of all markers in global collection.
      cm_mapMarkers.push(marker);
      cm_markersByBrokerageIdent[brokerage_ident] = marker;
	  
      if(param_useSidebar == true) {
        var markerA = document.createElement("a");
        markerA.style.color = "#000000";
        var sidebarText= "";
        if(usingRank) {
          sidebarText += rank + ") ";
        } 
        sidebarText += label;
        markerA.appendChild(document.createTextNode(sidebarText));
        sidebarDIV.appendChild(markerA);
        sidebarDIV.appendChild(document.createElement("br"));
        sidebarDIV.appendChild(document.createElement("br"));
      } 
    }
  }
  
  window.misDebugStash.soughtThing = soughtThing;
  window.misDebugStash.briefsCount = count;
  window.misDebugStash.processedCount = processed;

  InitManageAllMarkers();
}

function LoadMapJsonCanada(json) {

  var bounds = new GLatLngBounds();	  

  if (!json.feed.entry) {
    alert('Canada codes - data not available.');
    return;
  }

  cm_canadaCodes = {};

  var count = 0;
  var processed = 0;
  for (var i = 0; i < json.feed.entry.length; i++) {
    count++;
    var entry = json.feed.entry[i];
    if(entry["gsx$" + canadaCol_Latitude]) {
          processed++;
          var lat = parseFloat(entry["gsx$" + canadaCol_Latitude].$t);
          var lng = parseFloat(entry["gsx$" + canadaCol_Longitude].$t);
          var iso = entry["gsx$" + canadaCol_IsoCode].$t;
          // save the GPoint for the province
          cm_canadaCodes[iso] = new GLatLng(lat, lng);	  
    }
  }

  window.misDebugStash.canadaCodesCount = count;
  window.misDebugStash.processedCanadaCodes = processed;
  
}


var _infoWindowDataKey = 'infoWindowContents';

/*
Takes the JSON structure that represents a brokerage, parses out
the brokerage data into an HTML blurb and displays an info window
on the brokerage map marker.
*/
function LoadJSONInfoWindowDetail(json) {

  var bounds = new GLatLngBounds();	  
  var html = 'not found';
  
  if (json.feed.entry) {
      for (var i = 0; i < json.feed.entry.length; i++) {
        var entry = json.feed.entry[i];
        var company_name = '';
        var bkgId = 0;
        
        if(entry["gsx$" + detailCol_id]) {
          bkgId = CleanXCellValue(entry["gsx$" + detailCol_id].$t);
          company_name = CleanXCellValue(entry["gsx$"+detailCol_company].$t);
          
          var brokerage_ident = parseInt(entry["gsx$" + detailCol_id].$t);
          html = "<div style='font-size:12px'>";
          html += "<div style='height:9px;'></div>";
          html += "<strong>" + company_name + "</strong>";
          var label = entry["gsx$"+ detailCol_company].$t;
          var rank = 0;
          if (entry["gsx$"+detailCol_address1])
              html += "<div>" + CleanXCellValue(entry["gsx$"+detailCol_address1].$t) + "</div>";
          if (entry["gsx$"+detailCol_address2])
            html += "<div>" + CleanXCellValue(entry["gsx$"+detailCol_address2].$t) + "</div>";
          if (entry["gsx$"+detailCol_city])
            html += "<div>" + CleanXCellValue(entry["gsx$"+detailCol_city].$t) + "</div>";
          if (entry["gsx$"+detailCol_zip])
            html += "<div>" + CleanXCellValue(entry["gsx$"+detailCol_zip].$t) + "</div>";
          if (entry["gsx$"+detailCol_website]) {
            var webadr = CleanXCellValue(entry["gsx$"+detailCol_website].$t);
            html += "<div><a href='http://" + webadr + "' target='_blank'>" + webadr + "</a></div>";
          }
          if (entry["gsx$"+detailCol_tollFree])
            html += "<div>" + CleanXCellValue(entry["gsx$"+detailCol_tollFree].$t) + "</div>";
          
          var brokerageLookupUrl = param_ibaoQuotingUrl.replace(param_ibaoUrlIdentPlaceholder, bkgId);
          brokerageLookupUrl = brokerageLookupUrl.replace(param_ibaoUrlIsoPlaceholder, window.param_provIso);
          html += '<div style="height:8px"></div>';
          html += '<table width="100%" cellpadding=0 cellspacing=0 border=0>';
          html += '<tr><td align=left>';
          html += '<form action="' + brokerageLookupUrl + '" method=post style="display:inline">';
          html += '<input name="moreInfo" id="moreInfo" type="image" src="mis_2008_oct/bn_info.jpg" onmouseover="MouseMoreInfo(\'moreInfo\', 1);" onmouseout="MouseMoreInfo(\'moreInfo\', 0)" alt="More Info" value="More Info" />';
          html += '</form>'
          html += '</td><td align="right">';
          html += '<form action="' + brokerageLookupUrl + '" method=post style="display:inline">';
          html += '<input name="getAQuote" id="getAQuote" type="image" src="mis_2008_oct/bn_quote.jpg" onmouseover="MouseGetAQuote(\'getAQuote\', 1);" onmouseout="MouseGetAQuote(\'getAQuote\', 0)" alt="Get a Quote" value="Get a Quote" />';
          html += '</form>'
          html += '</td></tr>';
          html += '</table>';
          html += '<div style="height:10px"></div>';
          
          html += "</div>"; //outer

        }
      }//for

    } //if json.feed.entry
    
    var marker = cm_markersByBrokerageIdent[brokerage_ident];
    if (marker) {
        marker.openInfoWindowHtml(html, _brokerInfoWindowOpts);
        if (param_retainInfoWindowData)
            marker[_infoWindowDataKey] = html;
        else
            marker[_infoWindowDataKey] = null;
    }
    else {
        alert('no marker?');
    }
    
}

//Get cookie routine by Shelley Powers 
function get_cookie(Name) {
  var search = Name + "="
  var returnvalue = "";
  if (document.cookie.length > 0) {
    offset = document.cookie.indexOf(search)
    // if cookie exists
    if (offset != -1) { 
      offset += search.length
      // set index of beginning of value
      end = document.cookie.indexOf(";", offset);
      // set index of end of cookie value
      if (end == -1) end = document.cookie.length;
      returnvalue=unescape(document.cookie.substring(offset, end))
      }
   }
  return returnvalue;
}

function srch_createMarker(point, title) {
    var markerOpts = {};
    var nIcon = new GIcon(cm_baseIcon);
    
    nIcon.imageOut = "http://gmaps-samples.googlecode.com/svn/trunk/" +
        "markers/" + param_srchIconType + "/blank.png";
    nIcon.imageOver = "http://gmaps-samples.googlecode.com/svn/trunk/" +
        "markers/" + param_srchIconOverType + "/blank.png";
    nIcon.image = nIcon.imageOut;

    markerOpts.icon = nIcon;
    markerOpts.title = title;		 
    
    var marker = new GMarker(point, markerOpts);
    
    GEvent.addListener(marker, "click", function() {
        marker.openInfoWindowHtml(title, _searchInfoWindowOpts );
    });
    GEvent.addListener(marker, "mouseover", function() {
        marker.setImage(marker.getIcon().imageOver);
    });
    GEvent.addListener(marker, "mouseout", function() {
        marker.setImage(marker.getIcon().imageOut);
    });
    GEvent.addListener(marker, "infowindowopen", function() {
        marker.setImage(marker.getIcon().imageOver);
    });
    GEvent.addListener(marker, "infowindowclose", function() {
    try {
        var icn = marker.getIcon();
        var imgOut = icn.imageOut;
        marker.setImage(imgOut);
    }
    catch(err) { ; }
    });


    return marker;
}

/**
 * Creates marker with ranked Icon or blank icon,
 * depending if rank is defined. Assigns onclick function.
 * @param {GLatLng} point Point to create marker at
 * @param {String} title Tooltip title to display for marker
 * @param {String} html HTML to display in InfoWindow
 * @param {Number} rank Number rank of marker, used in creating icon
 * @return {GMarker} Marker created
 */
function cm_createMarker(point, title, adr, brokerage_ident) {
  var markerOpts = {};
  var nIcon = new GIcon(cm_baseIcon);

    nIcon.imageOut = "http://gmaps-samples.googlecode.com/svn/trunk/" +
        "markers/" + param_cmIconType + "/blank.png";
    nIcon.imageOver = "http://gmaps-samples.googlecode.com/svn/trunk/" +
        "markers/" + param_cmIconOverType + "/blank.png";
    nIcon.image = nIcon.imageOut;

  markerOpts.icon = nIcon;
  markerOpts.title = title;		 
  var marker = new GMarker(point, markerOpts);
  marker[param_brokerageId] = brokerage_ident;
  marker[param_address] = adr;
  
  GEvent.addListener(marker, "click", function() {
    Init_LoadBrokerageInfoWindowDetail(brokerage_ident);
  });
  GEvent.addListener(marker, "mouseover", function() {
    marker.setImage(marker.getIcon().imageOver);
  });
  GEvent.addListener(marker, "mouseout", function() {
    marker.setImage(marker.getIcon().imageOut);
  });
  GEvent.addListener(marker, "infowindowopen", function() {
    marker.setImage(marker.getIcon().imageOver);
  });
  GEvent.addListener(marker, "infowindowclose", function() {
    try {
        var icn = marker.getIcon();
        var imgOut = icn.imageOut;
        marker.setImage(imgOut);
    }
    catch(err) { ; }
  });
  return marker;
}

function CleanXCellValue(v) {
    return v ? v.replace(/^\'/, '') : v;
}

//var _fnIsMarkerManagerReady = function() {
//            return !(_isMapMoveEnded && ! _isMarkerManagerDone);
//        }

var _JSON_DetailBkgId = null;

function Init_LoadBrokerageInfoWindowDetail(argBkgId) {
    // store args in global variables in case this function calls itself on a timer.
    if (argBkgId)
        _JSON_DetailBkgId = argBkgId;
    if (! _JSON_DetailBkgId)
        return;

    var marker = cm_markersByBrokerageIdent[_JSON_DetailBkgId];
    if (!marker)
        return;
        
    if ( param_retainInfoWindowData && marker[_infoWindowDataKey] ) {
        marker.openInfoWindowHtml(marker[_infoWindowDataKey], _brokerInfoWindowOpts);
        return; // Return to skip loading of the JSON details again.
    }
    else 
        marker[_infoWindowDataKey] = null;
        
    marker.openInfoWindowHtml("<em style='font-size:xx-small'>" + "<b>LOADING</b> " + marker.getTitle() + " ...</em>", _brokerInfoWindowOpts);

    // Retrieve the JSON feed.
    var script = document.createElement('script');

    // The function name to call back when the JSON brokerage loads is passed here &callback=).
    script.setAttribute('src', 'http://spreadsheets.google.com/feeds/list'
                        + '/' + param_publishKeyDetailed + '/' + param_wsId + '/public/values' 
                        + '?alt=json-in-script'
                        + '&sq=' + escape(detailCol_id + '=' + _JSON_DetailBkgId)
                        + '&callback=LoadJSONInfoWindowDetail' 
                        + '&stamp=' + (new Date()).valueOf() );
                        
    script.setAttribute('id', 'jsonScriptDetailed');
    script.setAttribute('type', 'text/javascript');
  
    var node = document.getElementById("jsonScriptDetailed");
    if (node)
        node.parentNode.removeChild(node);
    node = null;  
    document.documentElement.firstChild.appendChild(script);    
}

var _locateQueryArg = null;
var queryWaiter = null;

function JumpToLocation(locationQuery) {
    NixInstructions();
    if (locationQuery)
        _locateQueryArg = locationQuery;
        
    var glocalsearch = new google.search.LocalSearch(); //GlocalSearch;
    glocalsearch.setCenterPoint(_cm_map);
    glocalsearch.execute(_locateQueryArg);
    glocalsearch.setSearchCompleteCallback(null, 
        function() {
            if (! glocalsearch.results || ! glocalsearch.results.length)
                alert('No results, cannot target ' + _locateQueryArg);
            else {
                for (var i = 0; i < glocalsearch.results.length; i++) { 
                    var glocalresult = glocalsearch.results[i]; 
                    var point = new GLatLng(glocalresult.lat, glocalresult.lng)
                    _cm_map.setCenter(point, param_postalLookupZoomLevel);
                    AddNewSearchMarker(point, locationQuery);
                    break;
                }
            }
        }//fn
    );        

}
    
