<!-- 
//<![CDATA[
var mapviewer, searcher, loading, markers, search;
var search, search_form, search_qs, max_results, search_submitbtn;
var message, search_point, search_address, search_sales, search_aftersales;
var directions, route_form, route_qs, routeSteps, selected_dealer, route_point, route_address;
var pan_zoom_widget, map_type_widget;
var container;
var initDealer = false;

// Funciton references
var initDealerFuncRef;
var funcRef = resultsLoaded;
var dirFuncRef = dirResultsLoaded;
var ambigFuncRef;

var max_zindex = 1000;
var dotw = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'];
var sections = ['searchDiv', 'recordListDiv', 'detailsDiv', 'routeStepsDiv', 'messageDiv'];
var activeSections = [];
var red_colour = '#F02933';
var grey_colour = '#6A6A6A';
var route_colour = grey_colour;
var page_loaded = false;
var data_source = 'mm.clients.halfords_01';
var search_params = [];

/* var rfs = ['client_id', 'name', 'street', 'address2', 'address3', 'town', 'county', 'pc', 'phone', 'dealerphoto', 'sales_text', 'parts_text', 'service_text', 'sales', 'service', 'lat', 'lon'];

for (var i=0; i<dotw.length; i++) {
  rfs.push('sales_' + dotw[i].toLowerCase() + '_open');
  rfs.push('sales_' + dotw[i].toLowerCase() + '_close');
} */

function readQueryString() {
	var url_bits = window.location.href.split('?');
	if (url_bits.length>1) {
		var param_strings = url_bits[1].split('&');
		var url_params = [];
		for (var i=0; i<param_strings.length; i++) {
			var split = param_strings[i].split('=');
			url_params[split[0]] = split[1];
		}
		if (url_params.area == 'small') {
			loadjscssfile("css/storelocator2_780.css", "css");
			loadjscssfile("css/style_780.css", "css"); 
		}
		else {
			loadjscssfile("css/storelocator2_960.css", "css");
			loadjscssfile("css/style_960.css", "css"); 
		}
		if (url_params.client_id) {
			initDealer = true;
			initDealerFuncRef = showInitialDealer;
			searcher = new MMSearchRequester( initDealerFuncRef );
			search = createSearchObject();
			search.filters.push(new MMSearchFilter('client_id', 'eq', url_params.client_id) );
			searcher.search( search );
		}
	}
	else {
		loadjscssfile("css/storelocator2_960.css", "css");
		loadjscssfile("css/style_960.css", "css"); 
	}

}

function showInitialDealer() {
  if (!page_loaded) {
    setTimeout('showInitialDealer()', 1000);
  } else {
    markers = new Array();
    if (resultsLoaded()) {
      result_id = markers[0].getAttribute('result_id');
      //console.log(typeof(result_id));
      if (typeof(result_id) != 'undefined') {
        //console.log('Dealer marker clicked.');
        selected_dealer = result_id;
        contextMenuItems = ['search', 'route'];
      }
      zoomToDealer(0, 0);
    }
  }
}

function loadjscssfile(filename, filetype) {
	if (filetype=="css") { //if filename is an external CSS file
		ensure( { css: filename }, function()
		{
			document.getElementById('html').style.display="block";	
		});
	}

}

function onLoad() {
	readQueryString();
  page_loaded = true;
  // Remove any old maps
  var mv = document.getElementById( 'mapviewer' );
  while (mv.firstChild) {
    mv.removeChild(mv.firstChild);
  }
  
  // & show intial map
  mapviewer = new MultimapViewer( document.getElementById( 'mapviewer' ) );
  showOverviewMap();
  container = document.getElementById ('widgetcontainer');
  
  // Add widgets
  // Pan/Zoom
  mapviewer.removeWidget ( pan_zoom_widget );
  pan_zoom_widget = new MMPanZoomWidget ( new MMBox( 10, 10 ), 'RipspeedPanZoomWidget', true );
  mapviewer.addWidget ( pan_zoom_widget );
  // Map Type
  mapviewer.removeWidget ( map_type_widget );
  map_type_widget = new MMMapTypeWidget ( undefined, undefined, 'RipspeedMapTypeWidget');
  mapviewer.addWidget ( map_type_widget );
  
  // get form elements
  search_form = document.getElementById( 'search_form' );
  search_qs = document.getElementById( 'qs' );
  search_sales = document.getElementById( 'sales_store' );
  search_aftersales = document.getElementById( 'aftersales_store' );
  max_results = document.getElementById( 'count' );
  search_submitbtn = document.getElementById( 'search_submitbtn' );
  loading = document.getElementById( 'loading' );
  message = document.getElementById( 'message' );
  directions = document.getElementById( 'getRouteDiv' );
  route_form = document.getElementById( 'route_form' );
  route_qs = document.getElementById( 'route_qs' );
  routeSteps = document.getElementById( 'routeStepsDiv' );
  
  if (!initDealer) showOnly('searchDiv');
  
  loadingStatus(false, search_form);
  loadingStatus(false, route_form);
  
  // This line adds support for contect menus (not tested)
  //addContextMenuSupport()
  
  // check for url search term
  var urlq = gup('q');
  if (urlq != '') {
  	search_qs.value = decodeURI(urlq);
  	
  	// kick off search automatically
  	initSearch();
  }
}

function showOverviewMap() {
  mapviewer.goToPosition( new MMLatLon( 54.7, -4.5 ), 6 );
}

function loadingStatus(bool, what) {
  // If we're loading values we want to disable the form elements
  // and display a spinning icon to show activity
  inputs = what.getElementsByTagName( 'input' );
  for (i=0; i<inputs.length; i++) {
    inputs[i].disabled = bool;
  }
  loading.style.display = bool ? 'block' : 'none';
}

function createSearchObject() {
  var search = new MMSearch();
  //search.return_fields = rfs;
  search.data_source = 'mm.clients.'+ data_source.replace('mm.clients.', '');
  search.filters = new Array();
  return search;
}

function openInfoBox(type, target) {
  if( target.infoBoxOpened() ) {
    target.closeInfoBox();
  }
  else {
    target.openInfoBox( );
  }
}

function createGoecodeMarker(location, display_name, num) {
  var marker = mapviewer.createMarker(location, {'text': num});
  //var marker = mapviewer.createMarker(location, {'zIndex': (99-num) , 'text': num});
  marker.setInfoBoxContent('<p>' + display_name + ' <a href="#" onclick="clickedGeocodeMarker(' + num + '); return false;">(select)</a></p>');
  return marker;
}

function clickedGeocodeMarker(no) {
  var sel = document.getElementById('ambiguous_geocode_dropdown');
  sel.value = no-1;
  ambigFuncRef();
}

function createMarker(record, num) {
  // 3rd argument hides dealer details link in InfoBox
  
  var hideDetailLink = false;
  if (arguments.length > 2) hideDetailLink = arguments[2];
  
  var location = record.point;
  //console.log('record.storetype=' + record.storetype);
  if (record.storetype && record.storetype != '') {
    //console.log('Using custom icon');
    var iconURL = 'assets/static/icon_' + record.storetype.toLowerCase().replace(/ /g, '') + '.gif';
  } else {
    //console.log('Using default icon');
    var iconURL = 'assets/static/icon_highstreetstore.gif';
  }

  var icon = new MMIcon(iconURL);
  icon.iconSize = new MMDimensions(75, 28);
  icon.iconAnchor = new MMPoint(38, 14);
  icon.textAnchor = new MMPoint(53, 4);
  icon.infoBoxAnchor = new MMPoint(48, 0);
  
  //var marker = mapviewer.createMarker(location, { 'text': num });
  var marker = mapviewer.createMarker(location, { 'icon': icon, 'text': num });
  marker.setAttribute('result_id', num-1);
  var overviewText, openingTimesText;
  overviewText = '<div class="infoBoxContent">\n';
  overviewText += '<div class="infoBoxDetails">\n';
  // Display  address...
  overviewText += record.address + '\n';
  // Display  phone no...
  overviewText += '<p>' + record.telephone + '</p>';
  // Display icons if valid...
  overviewText += '<div id="ibIcons">' + record.iconsHTML + '</div>';
  // Display links...
  //overviewText += '<a href="#" onclick="displayDealerDetails(0, ' + (num-1) + '); requestDirections(' + (num-1) + '); return false;">Get directions to this store</a> <br />\n';   // Travel Directions link - Removed due to directions form moving to stroe details page
  if (!hideDetailLink) overviewText += '<a href="#" onclick="zoomToDealer(0, ' + (num-1) + ')">More store details &amp; directions</a>.\n';   // Zoom to dealer link
  overviewText += '</div>\n';
  overviewText += '</div>\n';
  //overviewText +=  + '<br />\n';
  openingTimesText = '<div class="infoBoxContent">\n';
  openingTimesText += '<h2>Opening hours</h2>\n';
  openingTimesText += '<div class="opening_hours_div">\n';
  openingTimesText += record.openingTimesTable;
  openingTimesText += '</div>\n';
  var tabs = [
    new MMInfoBoxTab( record.storeshortname, overviewText ),
    new MMInfoBoxTab( 'Opening hours', openingTimesText )
  ];
  marker.setInfoBoxContent( tabs, { className: 'RipspeedInfoBox' } );
  // Original infoBox line
  //marker.setInfoBoxContent('<p>' + record.name + '</p>');
  return marker;
}

function gup(name) {
	var regexS = "[\\?&]"+name+"=([^&#]*)";
	var regex = new RegExp( regexS );
	var tmpURL = window.location.href;
	var results = regex.exec( tmpURL );
	if (results == null)
	return "";
	else
	return results[1];
}

function initSearch() {
  // This function is called with no arguments when initial search form is submitted
  // It is called with an address as the 1st arguement when resolving an ambiguous address
  showOnly('searchDiv');
  cleanUp();
  searcher = new MMSearchRequester( funcRef );
  
  // Set return fields and maximum number of records to return from search:
  search = createSearchObject();
  search.count = max_results.value;
  
  if (arguments.length == 0) {  // Default search
    search.address = new MMAddress({ qs : search_qs.value, country_code: 'GB' });
    // Clear saved location information
    search_point = false;
    search_address = false;
  } else {                      // coords passed in
    search.address = new MMLocation(arguments[0]);
  }
  
  search.filters.push(new MMSearchFilter('countrycode', 'eq', 'GB') );
  loadingStatus(true, search_form);
  searcher.search( search );
}

function cleanUp() {
  // Clean up the HTML containers
  while (message.firstChild) {
    message.removeChild(message.firstChild);
  }
  var record_list_div = document.getElementById('recordListDiv');
  var clear = ['recordList', 'routeSteps', 'routeStepsInfo'];
  for (var i=0; i<clear.length; i++) {
    var a = document.getElementById(clear[i]);
    while (a.firstChild) {
      a.removeChild(a.firstChild);
    }
  }
  mapviewer.removeAllOverlays();
  
  markers = new Array();
}

function showOnly() {
  // First argument is a string or array of sections to display
  // Second argument is a string of which element of the breadcrumb to display up to
  
  var what = false;
  var bc = false;
  if (arguments.length > 0) {
    what = arguments[0];
    if (typeof(what) == 'string') {
      what = [what];
    }
  }
  if (what) { // Check we have a valid section
    for (var i=0; i<what.length; i++) {
      if (!sections.inArray(what[i])) {
        return false;
      }
    }
  }
  // Do we have a 'display up to'?
  if (arguments.length > 1) {
    bc = arguments[1];
  }
  
  // Check if only message div is displayed & show at least the search breadcrumb (unless other supplied)
  if ((!bc && what.length == 1 && what[0] == 'messageDiv') || !what) bc = 'recordListDiv';
  
  // Display breadcrumb trail
  // Work out the latest section shown
  $('breadcrumbDiv').style.display = 'none';
  var lastDiv = false;
  if (bc) {
    lastDiv = sections.indexOf(bc);
  } else {
    for (var i=0; i<what.length; i++) {
      // Ignore 'messageDiv'
      if (what[i] != 'messageDiv' && (!lastDiv || sections.indexOf(what[i]) > lastDiv)) lastDiv = sections.indexOf(what[i]);
    }
  }
  for (var i=0; i<sections.length; i++) {
    if ($(sections[i] + 'Link')) {
      if (i < lastDiv) {
        $(sections[i] + 'Link').addClassName('breadcrumbLinkActive');
        $(sections[i] + 'Link').removeClassName('breadcrumbLinkInactive');
        $(sections[i] + 'Link').removeClassName('breadcrumbLinkHidden');
        $('breadcrumbDiv').style.display = 'block';
      } else if (i== lastDiv) {
        $(sections[i] + 'Link').removeClassName('breadcrumbLinkActive');
        $(sections[i] + 'Link').addClassName('breadcrumbLinkInactive');
        $(sections[i] + 'Link').removeClassName('breadcrumbLinkHidden');
        $('breadcrumbDiv').style.display = 'block';
      } else {
        $(sections[i] + 'Link').removeClassName('breadcrumbLinkActive');
        $(sections[i] + 'Link').removeClassName('breadcrumbLinkInactive');
        $(sections[i] + 'Link').addClassName('breadcrumbLinkHidden');
        //$(sections[i] + 'Link').style.display = 'none';
      }
    }
  }
  
  var a;
  for (var i=0; i<sections.length; i++) {
    a = document.getElementById(sections[i]);
    if (!what || !what.inArray(sections[i])) {
      a.style.display = 'none';
    } else {
      a.style.display = 'block';
    }
  }
}

function resultsLoaded() {
  //console.log('resultsLoaded()');
  var container = document.getElementById('recordListDiv');
  // Results are now loaded, so re-enable form elements, and remove spinning icon:
  loadingStatus(false, search_form);
  
  // If an error code has been produced, display the explanation:
  if ( searcher.error_code ) {
    processSearchGeocodingErrors(searcher, 'search');
    return false;
  }
  
  var results_returned = true;
  var start_index_value = 1;
  
  var sections_to_show = new Array();
  // Loop through each record set:
  for ( var count=0, l = searcher.record_sets.length; count < l; count++ ) {
    // If an error was returned for the record set, display details and return:
    if ( searcher.record_sets[count].error ) {
      var err =  '';
      if ( searcher.record_sets[count].error.error_explanation ) {
        err =  searcher.record_sets[count].error.error_explanation;
      } else {
        err =  translate_error_code(searcher.record_sets[count].error.error_code);
      }
      message.innerHTML = [message.innerHTML, err].join('<br />');
      showOnly(['searchDiv', 'messageDiv']);
      return;
    }
    // If not, check to see if individual records have been returned:
    var total = searcher.record_sets[count].totalRecordCount;
    if ( searcher.record_sets[count].records ) {
      var el = document.getElementById('recordList');
      var table = document.createElement('table');
      table.className = 'resultsTable';
      table.setAttribute('cellpadding', '0');
      table.setAttribute('cellspacing', '0');
      table.id = 'storelist';
      el.appendChild(table);
      var tbody = document.createElement('tbody');
      table.appendChild(tbody);
      // Add header row...
      var thead = document.createElement('tr');
      
      var th = document.createElement('th');
      th.className = 'rec_num';
      th.appendChild(document.createTextNode(' '));
      thead.appendChild(th);
      
      var th = document.createElement('th');
      th.className = 'type';
      th.appendChild(document.createTextNode('Store Type & Specialist Areas'));
      thead.appendChild(th);
      
      var th = document.createElement('th');
      th.className = 'location';
      th.appendChild(document.createTextNode('Store Location'));
      thead.appendChild(th);
      
      var th = document.createElement('th');
      th.className = 'buttons';
      th.appendChild(document.createTextNode('Distance'));
      thead.appendChild(th);
      
      var th = document.createElement('th');
      th.className = 'buttons';
      th.appendChild(document.createTextNode('\u00a0'));
      thead.appendChild(th);
      
      tbody.appendChild(thead);
      // Loop through each record in the record set, and add it to the list below the map,
      //  and populate the infobox text:
      for (var record_count = 0, rl = searcher.record_sets[count].records.length; record_count < rl; record_count++ ) {
        var record = searcher.record_sets[count].records[record_count];
        // Check for store name
        if (!record.storeshortname || record.storeshortname == '') record.storeshortname = '???';
        
        // Build address HTML
        record.address = '<address>\n';
        if (record.street != '') record.address += record.street + '<br />\n';
        if (record.town != '') record.address += record.town + '<br />\n';
        if (record.county != '') record.address += record.county + '<br />\n';
        if (record.pc != '') record.address += record.pc + '<br />\n';
        record.address += '</address>';
        
        // Build opening times table HTML
        record.openingTimesTable = '<table class="opening_hours">\n';
        record.openingTimesTable += '<tbody>\n';
        for (var i=0; i<dotw.length; i++) {
          record.openingTimesTable += '<tr>\n';
          record.openingTimesTable += '<td>\n';
          record.openingTimesTable += dotw[i] + ': ';
          record.openingTimesTable += '</td>\n';
          record.openingTimesTable += '<td class="opening_time">\n';
          record.openingTimesTable += record[dotw[i].substr(0, 3).toLowerCase() + 'hours'];
          record.openingTimesTable += '</td>\n';
          record.openingTimesTable += '</tr>\n';
        }
        var spOpenTimes = new Array();
        for (var i=1; i<15; i++) {
          var iStr = new String(i);
          while (iStr.length < 3) iStr = '0' + iStr;
          var baseFieldNameStr = 'specialday' + iStr;
          if (record[baseFieldNameStr] != '' &&
          record[baseFieldNameStr + 'date'] != '0000-00-00' &&
          record[baseFieldNameStr + 'hours'] != '00:00 - 00:00' &&
          record[baseFieldNameStr + 'show_date_from'] != '0000-00-00' &&
          record[baseFieldNameStr + 'show_date_to'] != '0000-00-00') {
            var specialDate = record[baseFieldNameStr + 'date'].split('-');
            var specialDate = new Date(specialDate[0].valueOf(), specialDate[1].valueOf()-1, specialDate[2].valueOf());
            
            var fromDate = record[baseFieldNameStr + 'show_date_from'].split('-');
            var showFrom = new Date(fromDate[0].valueOf(), fromDate[1].valueOf()-1, fromDate[2].valueOf());
            var toDate = record[baseFieldNameStr + 'show_date_to'].split('-');
            var showTo = new Date(toDate[0].valueOf(), toDate[1].valueOf()-1, toDate[2].valueOf());
            var now = new Date();
            //var now = new Date(2007, 11, 18);   // To test specific date display
            if (showFrom < now && showTo > now) {
              var spOpenTimesStr = '<tr>\n';
              spOpenTimesStr += '<td>\n';
              spOpenTimesStr += record['specialday' + iStr] + ': ';
              spOpenTimesStr += '</td>\n';
              spOpenTimesStr += '<td class="opening_time">\n';
              spOpenTimesStr += record['specialday' + iStr + 'hours'];
              spOpenTimesStr += '</td>\n';
              spOpenTimesStr += '</tr>\n';
              spOpenTimes.push({date: specialDate, HTML: spOpenTimesStr});
            }
          }
        }
        var spOrderedOpenTimes = new Array();
        while (spOpenTimes.length > 0) {
          var first = {};
          for (var i=0; i<spOpenTimes.length; i++) {
            if (!first.index || spOpenTimes[i].date < first.date) first = {index: i, date: spOpenTimes[i]};
          }
          spOrderedOpenTimes.push(spOpenTimes[first.index]);
          spOpenTimes[first.index] = null;
          spOpenTimes = spOpenTimes.compact();
        }
        for (var i=0; i<spOrderedOpenTimes.length; i++) {
          record.openingTimesTable += spOrderedOpenTimes[i].HTML;
        }
        record.openingTimesTable += '</tbody>\n';
        record.openingTimesTable += '</table>\n';
        
        // Build icon HTML...
        var iconTypes = [
          {field: 'ripspeed', title: 'Specialist Ripspeed area offering the complete range of performance styling products'},
          {field: 'ripspeedx', title: 'Ripspeed X area offering specialist modification services.'},
          {field: 'wellfitit', title: 'Halfords\' fitting service on a wide range of products.'}
        ];
        var iconsToShow = [];
        for (var i=0; i<iconTypes.length; i++) {
          if (record[iconTypes[i].field] && record[iconTypes[i].field].substr(0, 1).toUpperCase() == 'Y') {
            var imgStr = '<img class="serviceIcon" src="assets/static/icon_' +  iconTypes[i].field+ '.gif" alt="' + iconTypes[i].title + '" title="' + iconTypes[i].title + '"/>\n';
            iconsToShow.push(imgStr);
          }
        }
        record.iconsHTML = '';
        if (iconsToShow.length>0) {
          record.iconsHTML = '<span class="icons">' + iconsToShow.join('') + '</span>';
        }
        
        var tr = handleRecord(record, start_index_value + record_count);
        tbody.appendChild ( tr );
      }
      sections_to_show.push('recordListDiv');
      var p1 = document.createElement('p');
      p1.appendChild(document.createTextNode('The 5 closest stores are shown on the map and listed below.'));
      var p2 = document.createElement('p');
      p2.appendChild(document.createTextNode('Click on a store details button below for a more detailed map and store information.'));
      message.appendChild(p1);
      message.appendChild(p2);
      sections_to_show.push('messageDiv');
    } else {
      // No records have been returned. If a record count has been returned, display it,
      // otherwise display a message noting that no records were returned by the search:
      var el = document.getElementById('message');
      el.appendChild ( document.createTextNode( 'No results returned' ) );
      results_returned = false;
      sections_to_show.push('messageDiv');
    }
  }
  
  // Display the results
  showOnly(sections_to_show);
  
  if ( sections_to_show.inArray('recordListDiv') ) {
    mapviewer.goToPosition ( mapviewer.getAutoScaleLocation( markers ) );
  }
  
  return results_returned;
  
}

function translate_error_code(err_code) {
  var errors = {
    'MM_API_ERROR_DATA_SOURCE_NOT_PROVISIONED':               'The data source is not provisioned or set up yet.',
    'MM_API_ERROR_DATABASE_QUERY_FAILED':                     'The search request has failed.',
    'MM_API_ERROR_START_INDEX_GREATER_THAN_RESULT_SET_SIZE':  'The startIndex value passed in the request is greater than the total number of records returned in the result.',
    'MM_API_ERROR_UNSUPPORTED_SEARCH_TYPE':                   'An incorrect search parameter is being passed in the URL.',
    'MM_ERROR_SERVICE_NOT_PROVISIONED':                       'You not have access rights to this module of the Multimap API.',
    'MM_SEARCH_DIRECTION_REQUEST_FAILED':                     'Request has failed.',
    'MM_SEARCH_ERROR':                                        'Your search returned an error.',
    'MM_SEARCH_ERROR_UNSUPPORTED_SEARCH_TYPE':                'The submitted search parameters are not supported by the Multimap API web services.',
    'MM_SEARCH_START_INDEX_GREATER_THAN_RESULT_SET_SIZE':     'The search returned an error because the startIndex value passed in the request is greater than the total number of records returned in the result.',
    'MM_GEOCODE_NO_MATCHES':                                  'The address given cannot be geocoded.',
    'MM_ROUTE_ERROR_NO_ROUTE':                                'We could not generate navigation between the specified points.',
    'MM_ROUTE_ERROR_POINT_OUTSIDE_NETWORK':                   'One or more points are outside the coverage zone.',
    'MM_ROUTE_ERROR_SERVER_BUSY':                             'The request cannot be processed as the server is busy.',
    'MM_ROUTE_ERROR_START_END_POINTS_SAME':                   'The start and end points entered are the same, so a route cannot be generated.',
    'MM_SEARCH_MULTIPLE_MATCHES':                             'The search found multiple matches.',
    'MM_SEARCH_NO_MATCHES':                                   'Your search found no matches.',
    'MM_API_ERROR_REQUIRED_PARAMETERS_MISSING':               'A required parameter was missing from the request.'
  };
  if (typeof(errors[err_code]) != 'undefined') {
    return 'We\'re sorry, but there was a problem with the requested route. ' + errors[err_code];
  } else {
    //console.log(err_code);
    return 'We\'re sorry, but there was a problem with the requested route.';
  }
}

function processSearchGeocodingErrors(type) {
  var err =  '';
  if ( searcher.error_explanation ) {
    err =  searcher.error_explanation;
  } else {
    err =  'Your request failed. Error code: ' + searcher.error_code;
  }
  if (searcher.error_code != 'MM_GEOCODE_MULTIPLE_MATCHES') {
    message.innerHTML = translate_error_code(searcher.error_code);
  } else {
    message.innerHTML = 'Multiple matches found for ' + search_qs.value + '.<br />Please select one from the list below.<br />';
    
    sel = generateAmbiguousSelect(searcher.result_set);
    sel.setAttribute('id', 'ambiguous_geocode_dropdown');
    ambigFuncRef = goToAmbiguousAddress;
    sel.onchange = ambigFuncRef;
    message.appendChild(sel);
    mapviewer.goToPosition(mapviewer.getAutoScaleLocation(searcher.result_set));
  }
  showOnly(['searchDiv', 'messageDiv']);
}

function generateAmbiguousSelect(results) {
  sel = document.createElement('select');
  
  var blank_opt = document.createElement('option');
  blank_opt.setAttribute('value', '');
  blank_opt.appendChild(document.createTextNode('Please select...'));
  sel.appendChild(blank_opt);
  
  //loop through the result set
  for (var count=0; count < results.length; count++) {
    var address = results[count].address;
    var opt = document.createElement('option');
    opt.setAttribute('value', count);
    optText = count+1 + '. ' + address.display_name;
    var optTextTooLong = (optText.length > 40);
    var optText = optText.substr(0, 40);
    if (optTextTooLong) optText += '...';
    opt.appendChild(document.createTextNode(optText));
    sel.appendChild(opt);
    createGoecodeMarker(results[count].coords, results[count].address.display_name, count+1);
  }
  return sel;
}

function goToAmbiguousAddress() {
  //console.log('goToAmbiguousAddress()');
  var sel = document.getElementById('ambiguous_geocode_dropdown');
  search_point = searcher.result_set[sel.value].coords;
  search_address = searcher.result_set[sel.value].address.display_name;
  search_qs.value = searcher.result_set[sel.value].address.display_name;
  initSearch(search_point);
}

function goToRouteAmbiguousAddress() {
  //console.log('goToRouteAmbiguousAddress()');
  var sel = document.getElementById('ambiguous_geocode_dropdown');
  route_point = route.geocoding_errors[0].results[sel.value].coords;
  route_qs.value = route.geocoding_errors[0].results[sel.value].address.display_name;
  callRoute(route_point);
}

function handleRecord( record, num ) {
  // 3rd argument hides dealer details link in InfoBox
  
  var hideDetailLink = false;
  if (arguments.length > 2) hideDetailLink = arguments[2];
  
  if ( record.point ) {
    var marker = createMarker( record, num, hideDetailLink );
    markers.push(marker);
  }
  
  if (!hideDetailLink) {
    // Show the name in our records list. When the name is clicked, open
    //  our info box:
    var tr = document.createElement ( 'tr' );
    tr.id = 'row' + num;
    tr.className = (num % 2 != 0 ? 'lightGray' : 'whiterow');
    
    // Number column
    var tdn = document.createElement('td');
    tdn.className = 'rec_num';
    tdn.appendChild(document.createTextNode(num));
    tr.appendChild(tdn);
    
    // First column
    var td1 = document.createElement('td');
    td1.className = 'type';
    tr.appendChild(td1);
    // This next if is to guard against storetype = null.
    if (record.storetype) {
      td1.innerHTML = '<img src="assets/static/icon_' + record.storetype.toLowerCase().replace(/ /g, '') + '_key.gif" />' + record.iconsHTML;
    } else {
      td1.innerHTML = '<img src="assets/static/icon_highstreetstore_key.gif" />' + record.iconsHTML;
    }
    
    // Second column
    var td2 = document.createElement('td');
    td2.className = 'location';
    // Add address
    var address = document.createElement ( 'address' );
    var add1 = document.createElement('span');
    add1.className = 'title greyTextBig';
    add1.appendChild(document.createTextNode(record.street));
    address.appendChild(add1);
    address.appendChild(document.createElement('br'));
    address.appendChild(document.createTextNode(record.town + ', ' + record.county + ', ' + record.pc));
    td2.appendChild(address);
    td2.appendChild(document.createElement('br'));
    // Add phone no
    var phoneAbrv = document.createElement('abbr');
    phoneAbrv.title = 'Telephone Number';
    phoneAbrv.appendChild(document.createTextNode('T.'));
    td2.appendChild(phoneAbrv);
    td2.appendChild(document.createTextNode(record.telephone));
    tr.appendChild(td2);
    
    // Third column
    var td3 = document.createElement('td');
    td3.className = 'distance';
    if (record.distance) {
      var distSpan = document.createElement('span');
      distSpan.className = 'title greyTextBig';
      distSpan.appendChild(document.createTextNode(parseFloat(record.distance.miles).toFixed(2) + ' miles'));
      td3.appendChild(distSpan);
    }
    tr.appendChild(td3);
    
    // Forth column
    var td4 = document.createElement('td');
    td4.className = 'buttons';
    var a = document.createElement('a');
    a.className = 'detailbutton';
    a.href = '#';
    a.onclick = function () { zoomToDealer(0, num-1); return false; };
    a.appendChild(document.createTextNode('Details & Map'));
    td4.appendChild(a);
    tr.appendChild(td4);
    
    return tr;
  }
}

function zoomToDealer(set, rec) {
  // Optional 3rd argument is the ZL
  
  selected_dealer = rec;
  cleanUp();
  showOnly();
  var record = searcher.record_sets[set].records[rec];
  //markers = [];
  handleRecord(record, (rec+1), true);
  loc = record.point;
  if (arguments.length < 3) {
    mapviewer.goToPosition(loc, 17);
  } else {
    mapviewer.goToPosition(loc, arguments[2]);
  }
  openInfoBox( 'click', markers[0] );
  
  displayDealerDetails(set, rec);
  showOnly('detailsDiv');
}

function displayDealerDetails(set, rec) {
  var record = searcher.record_sets[set].records[rec];
  var detailsText = '';
  detailsText += '<h3>' + record.storeshortname + '</h3>';
  detailsText += '<h4>Opening Times</h4>';
  detailsText += '<div id="OpeningTimesDiv" class="dealerInfoSection">';
  detailsText += record.openingTimesTable;
  detailsText += '</div>';
  if (record.iconsHTML != '') {
    detailsText += '<h4>Store information</h4>';
    detailsText += '<div id="ServicesDiv" class="dealerInfoSection">';
    detailsText += record.iconsHTML;
    detailsText += '</div>';
  }
  document.getElementById('dealerInfo').innerHTML = detailsText;
}

function displayGetDirectionsDiv() {
  requestDirections(selected_dealer);
}

function requestDirections(rec) {
  // Populate route from hidden parameter identifying dealer
  selected_dealer = rec;
  var toDiv = document.getElementById('toDiv');
  // Clear To info before re-populating
  while (toDiv.firstChild) {
    toDiv.removeChild(toDiv.firstChild);
  }
  var toDivLabel = document.createElement('label');
  toDivLabel.setAttribute('for', 'toDealerName');
  toDivLabel.appendChild(document.createTextNode('To: '));
  toDiv.appendChild(toDivLabel);
  toDealerName = document.createElement('div');
  toDealerName.setAttribute('id', 'toDealerName');
  toDealerName.appendChild(document.createTextNode(searcher.record_sets[0].records[rec].storeshortname))
  toDiv.appendChild(toDealerName);
  toDiv.appendChild(document.createElement('br'));
  route_qs.value = search_qs.value;
  
  if (search_point) route_point = search_point;
  // Ensure search form is enabled
  loadingStatus(false, route_form);
  // Display route request form
  showOnly(['getRouteDiv']);
  helper_direct_to_directions();
}

function callRoute() {
  var f_latlon;
  route_point = false;
  route_address = false;
  if (search_point && search_qs.value == route_qs.value) {
    //console.log('Using previous search geocode result of ambiguous search.');
    f_latlon = search_point.toString().match(/-{0,1}[\d\.]+,-{0,1}[\d\.]+/);
  }
  //var route_qs = document.getElementById('route_qs');
  var qs = route_qs.value;
  var t_lat = searcher.record_sets[0].records[selected_dealer].point.lat;
  var t_lon = searcher.record_sets[0].records[selected_dealer].point.lon;
  var dealer_name = searcher.record_sets[0].records[selected_dealer].storeshortname;
  var dir_string = 'to_latlon=' + t_lat + ',' + t_lon;
  dir_string += '&from_qs=' + escape(qs);
  if (f_latlon) dir_string += '&from_latlon=' + f_latlon;
  dir_string += '&dealer_name=' + escape(dealer_name);

  fetchRoute(dir_string);
}

function breadcrumbClick(what) {
  if ($(what + 'DivLink').hasClassName('breadcrumbLinkInactive')) {
  console.log('stopping');
    return false;
  }
  cleanUp();
  var show = [what + 'Div'];
  switch (what) {
    case 'search':
      showOverviewMap();
      break;
    case 'recordList':
      showOnly();
      resultsLoaded();
      show.push('messageDiv');
      break;
    default:
  }
  showOnly(show);
}

// Routing functions...
function fetchRoute(dir_string) {
  // Construct the route requester with our callback function:
  route_finder = new MMRouteRequester( dirFuncRef );
  
  // Add each of the selected waypoints. The addLocation function will only add
  //  a location if a selection was made from the corresponding select box:
  var locations = new Array();
  
  var href = dir_string;
  var params = href.split('&');
  for (var i=0; i<params.length; i++) {
    var param = params[i].split('=');
    switch (param[0]) {
      case 'from_qs':
        search_params['from_qs'] = unescape(param[1]);
        break;
      case 'from_latlon':
        search_params['from_latlon'] = unescape(param[1]);
        break;
      case 'to_latlon':
        search_params['to_latlon'] = unescape(param[1]);
        break;
      case 'dealer_name':
        dealer_name = unescape(param[1]);
        break;
    }
  }
  if (typeof(search_params['from_latlon']) != 'undefined') {
    var coords = search_params['from_latlon'].split(',');
    locations[0] = new MMLocation(new MMLatLon(coords[0], coords[1]));
  } else {
    locations[0] = new MMLocation(new MMAddress( { qs: search_params['from_qs'], country_code: 'GB' } ));
  }
  var coords = search_params['to_latlon'].split(',');
  locations[1] = new MMLocation(new MMLatLon(coords[0], coords[1]));
  
  route = new MMRoute( locations );
  route.lang = 'en_gb';
  
  route_finder.request(route);
  
  loadingStatus(true, route_form);
}

function dirResultsLoaded() {
  //console.log('dirResultsLoaded()');
  
  if (route.error_code) {
    if (route.error_code == 'MM_ROUTE_GEOCODING_ERRORS') {
        processRouteGeocodingErrors(route.geocoding_errors);
    } else {
      if (route.error_code != 'MM_GEOCODE_MULTIPLE_MATCHES') {
        message.innerHTML = translate_error_code(route.error_code);
      } else {
        message.innerHTML = 'Multiple matches found for ' + route_qs.value + '.<br />Please select one from the list below.<br />';
        
        sel = generateAmbiguousSelect(route.result_set);
        sel.setAttribute('id', 'ambiguous_geocode_dropdown');
        ambigFuncRef = goToRouteAmbiguousAddress;
        sel.onchange = ambigFuncRef;
        message.appendChild(sel);
        mapviewer.goToPosition(mapviewer.getAutoScaleLocation(route.result_set));
      }
    }
    message.style.display = 'block';
  } else {
    cleanUp();
    showOnly(['routeStepsDiv', 'messageDiv']);
    mapviewer.goToPosition( mapviewer.getAutoScaleLocation( route.bounds ) );
    displayStages(route);
    var p1 = document.createElement('p');
    p1.appendChild(document.createTextNode('Your directions can now be found below the map.'));
    message.appendChild(p1);
    route.polyLine[0].reset( null, { 'color': route_colour } );
    mapviewer.addOverlay(route.polyLine[0]);
    routeSteps.style.display = 'block';
  }
  loadingStatus(false, route_form);
}

function displayStages(route) {
  var curr_step = 1;
  var stages = route.stages;
  
  var start;
  if (typeof(stages[0].start_address.display_name) != 'undefined') {
    start = stages[0].start_address.display_name;
  } else {
    var start = search_params['from_qs'];
  }
  
  var container = document.getElementById('routeStepsInfo');
  var h = document.createElement('h4');
  h.appendChild(document.createTextNode('Overview'));
  container.appendChild(h);
  var summary = document.createElement('p');
  summary.appendChild(document.createTextNode('Start: ' + start));
  summary.appendChild(document.createElement('br'));
  summary.appendChild(document.createTextNode('End: ' + dealer_name)); //stages[stages.length - 1].end_address;
  summary.appendChild(document.createElement('br'));
  summary.appendChild(document.createTextNode('Total Distance: ' + route.distance.miles.toFixed(2) + ' mile(s)'));
  summary.appendChild(document.createElement('br'));
  summary.appendChild(document.createTextNode('Estimated Total Time: '));
  if (route.duration.days > 0) { summary.appendChild(document.createTextNode(route.duration.days + ' day(s) ')); }
  if (route.duration.hours > 0) { summary.appendChild(document.createTextNode(route.duration.hours + ' hour(s) ')); }
  if (route.duration.minutes > 0) { summary.appendChild(document.createTextNode(route.duration.minutes + ' minute(s) ')); }
  container.appendChild(summary);
  var h = document.createElement('h4');
  h.appendChild(document.createTextNode('Summary'));
  container.appendChild(h);
  stage_summary = document.createElement('p');
  stage_summary.appendChild(document.createTextNode(stages[0].summary));
  container.appendChild(stage_summary);
  
  var tBody = document.getElementById('routeSteps');
  
  var tHead = document.createElement('tr');
  
  var th = document.createElement('th');
  th.className = 'type';
  th.appendChild(document.createTextNode('Step'));
  tHead.appendChild(th);
  
  var th = document.createElement('th');
  th.className = 'location';
  th.appendChild(document.createTextNode('Time'));
  tHead.appendChild(th);
  
  var th = document.createElement('th');
  th.className = 'distance';
  th.appendChild(document.createTextNode('Distance so far'));
  tHead.appendChild(th);
  
  var th = document.createElement('th');
  th.className = 'instructions';
  th.appendChild(document.createTextNode('Instructions'));
  tHead.appendChild(th);
  
  var th = document.createElement('th');
  th.className = 'buttons';
  th.appendChild(document.createTextNode('\u00a0'));
  tHead.appendChild(th);
  
  tBody.appendChild(tHead);
  
  var totalDist = 0;
  
  var steps = stages[0].steps;
  for (var stepCount=0; stepCount < steps.length; stepCount++) {
    var text = curr_step;
    var zindex = max_zindex - curr_step + 1;
    if (stepCount  == steps.length - 1) {
      zindex = max_zindex;
    }
    
    var instruction = steps[stepCount].instruction;
    var roadname = steps[stepCount].road_name;
    var roadnumber = steps[stepCount].road_number;
    
    if (roadname && roadnumber) {
      instruction += ' ' + roadname + ' (' + roadnumber + ')';
    } else if (roadname) {
      instruction += ' ' + roadname;
    } else if (roadnumber) {
      instruction += ' ' + roadnumber;
    }
    
    var tr = document.createElement('tr');
    if (stepCount % 2 == 0) tr.className = 'lightGray';
    
    var t1 = document.createElement('td');
    t1.className = 'type';
    t1.appendChild(document.createTextNode(stepCount));
    tr.appendChild(t1);
    
    var t2 = document.createElement('td');
    t2.className = 'location';
    var duration = steps[stepCount].duration;
    var hrs = ((duration.days*24)+duration.hours).toString();
    while (hrs.length < 2) hrs = '0' + hrs;
    var mins = duration.minutes.toString();
    while (mins.length < 2) mins = '0' + mins;
    t2.appendChild(document.createTextNode(hrs + ':' + mins));
    tr.appendChild(t2);
    
    var t3 = document.createElement('td');
    t3.className = 'distance';
    if (steps[stepCount].distance.miles > 0) {
      totalDist = (parseFloat(totalDist) + parseFloat(steps[stepCount].distance.miles)).toFixed(2);
      t3.appendChild(document.createTextNode(totalDist.toString() + ' miles'));
    }
    tr.appendChild(t3);
    
    var t4 = document.createElement('td');
    t4.className = 'instructions';
    t4.appendChild(document.createTextNode(instruction));
    tr.appendChild(t4);
    
    var t5 = document.createElement('td');
    t5.className = 'buttons';
    var a = document.createElement('a');
    a.className = 'detailbutton';
    a.href='#';
    a.onclick = function(stage, step) {
      return function() {
        displaySingleStage(stage, step);
        $('mapviewer').scrollTo();
      }
    }(0, stepCount);
    a.appendChild(document.createTextNode('View Map'));
    t5.appendChild(a);
    tr.appendChild(t5);
    
    tBody.appendChild(tr);
    
    /* var inst_link = document.createElement('a');
    inst_link.setAttribute('href', '#');
    inst_link.onclick = function(stage, step) {
      return function() {
        displaySingleStage(stage, step);
        $('mapviewer').scrollTo();
        return false;
      }
    }(0, stepCount);
    inst_link.appendChild(document.createTextNode(instruction));
    tr.appendChild(inst_link);
    tr.appendChild(document.createTextNode(' ' + distance));
    /* li.innerHTML = '<a href="#" onclick="return false;">' +  + '</a> ' + distance;
    li.onclick = function(stage, step) {
      return function() {
        displaySingleStage(stage, step);
        $('mapviewer').scrollTo();
      }
    }(0, stepCount); */
    tBody.appendChild(tr);
    
    createStepMarker(steps[stepCount].start_point, instruction, text, zindex);
    
    ++curr_step;
  }
  
  //container.style.display = 'block';
  var copyright = '';
  if (route.copyright) {copyright += 'Copyright: ' + route.copyright; }
  if (route.disclaimer)  {copyright += '<br />Disclaimer:  <a href="' + route.disclaimer +'">Please note this disclaimer<' + '/a>.'; }
  
  var p = document.createElement('p');
  $('routeStepsDiv').appendChild(p);
  p.innerHTML = copyright;
}

function displaySingleStage(stage, step) {
  //console.log("Showing stage " + stage + " & step " + step);
  var stepObj = route.stages[stage].steps[step];
  //console.log("Starting from " + stepObj.start_point);
  //console.log("Ending at " + stepObj.end_point);
  mapviewer.drawAndPositionMap(
    mapviewer.getAutoScaleLocation( [ stepObj.start_point, stepObj.end_point ] )
  );
}

function createStepMarker(location, instruction, text, zindex) {
  var marker = mapviewer.createMarker(location, {zIndex: zindex, 'text' : text});
  marker.setInfoBoxContent('<p>' + instruction + '<' + '/p>');
}

function processRouteGeocodingErrors(errors) {
  for (var i = 0; i < errors.length; i++) {
    if (errors[i].error_code == 'MM_GEOCODE_NO_MATCHES') {
      message.innerHTML = [message.innerHTML, '<p>No matching locations for Location ' + errors[i].address.qs + '.</' + 'p>'].join('\n');
    } else if (errors[i].error_code == 'MM_GEOCODE_MULTIPLE_MATCHES') {
      message.innerHTML = [message.innerHTML, '<p>Multiple matches found for ' + errors[i].address.qs + '.<br />Please select one from the list below.</' + 'p>'].join('\n');
      sel = generateAmbiguousSelect(errors[i].results);
      sel.setAttribute('id', 'ambiguous_geocode_dropdown');
      ambigFuncRef = goToRouteAmbiguousAddress;
      sel.onchange = ambigFuncRef;
      message.appendChild(sel);
      mapviewer.goToPosition(mapviewer.getAutoScaleLocation(errors[i].results));
    } else {
      message.innerHTML = [message.innerHTML, 'No matching locations for Location ' + errors[i].address.qs + '.</' + 'p>'].join('\n');
    }
  }
  showOnly(['getRouteDiv', 'messageDiv']);
}


// code to add contect menu items
var contextMenuItems = ['search'];
function addContextMenuSupport() {
  // initSearch => remove route menu
  old_initSearch = initSearch;
  initSearch = function() {
    contextMenuItems = ['search'];
    var args = [];
    for (var i=0; i<arguments.length; i++) {
      args.push('arguments[' + i + ']');
    }
    var argStr = args.join(', ');
    //console.log(argStr);
    return eval('old_initSearch(' + argStr + ');');
  };
  
  // Add eventHandler to marker clicks
  function openInfoBox() {
    //console.log('Opened_marker ' + arguments[1].getAttribute('result_id'));
    result_id = arguments[1].getAttribute('result_id');
    //console.log(typeof(result_id));
    if (typeof(result_id) != 'undefined') {
      //console.log('Dealer marker clicked.');
      selected_dealer = result_id;
      contextMenuItems = ['search', 'route'];
    } else {
      //console.log('Non-Dealer marker clicked.');
    }
  }
  mapviewer.addEventHandler( 'click', openInfoBox );
  
  // Add eventHandler to add context menu items
  function addContextMenuItem( type, target, menu, pos, step ) {
    var menu_items = ['search', 'route'];
    var items = new Array();
    items['search'] = { label : 'Find stores near here', onclick : function() { searchHere(pos); menu.remove(); }, className : 'MMaddmarker' };
    items['route'] = { label : 'Find directions from here', onclick : function() { routeFromHere(pos); menu.remove(); }, className : 'MMaddmarker' };
    var inert_items = new Array();
    inert_items['route'] = { label : 'Find directions from here', onclick : function() { alert('You need to find and click on a dealer marker first.'); }, className : 'MMaddmarkerDisabled' };
    var use_items = [];
    for (var i=0; i<menu_items.length; i++) {
      if (contextMenuItems.inArray(menu_items[i])) {
        use_items.push(items[menu_items[i]]);
      } else {
        use_items.push(inert_items[menu_items[i]]);
      }
    }
    menu.addItemsJSON( use_items );
  }
  mapviewer.removeEventHandler( 'contextMenu', addContextMenuItem );
  mapviewer.addEventHandler( 'contextMenu', addContextMenuItem );
    
  function searchHere(pos) {
    search_qs.value = 'Clicked location';
    search_point = pos;
    initSearch(pos);
  }
  
  function routeFromHere(pos) {
    if (typeof(selected_dealer) != 'undefined') {
      route_qs.value = 'Clicked location';
      route_point = pos;
      callRoute(pos);
    } else {
      //console.log('Attempted to request a route from click before dealer selected.')
    }
  }
}

MMAttachEvent( window, 'load', onLoad );

// Helper functions...
Array.prototype.inArray = function(value) {
  // Returns true if the passed value is found in the
  // array.  Returns false if it is not.
  var i;
  for (i=0; i < this.length; i++) {
    // Matches identical (===), not just similar (==).
    if (this[i] === value) {
      return true;
    }
  }
  return false;
};

Array.prototype.indexOf = function(value) {
  // Returns true if the passed value is found in the
  // array.  Returns false if it is not.
  var i;
  for (i=0; i < this.length; i++) {
    // Matches identical (===), not just similar (==).
    if (this[i] === value) {
      return i;
    }
  }
  return false;
};

function roundNumber(num, dec) {
	var result = Math.round(num*Math.pow(10,dec))/Math.pow(10,dec);
	return result;
}

function helper_direct_to_directions() {
  // Triggered when clicking on the 'Get directions to this dealer' link.
  
  // You may want to add a popup msg or something here?
  
  // Automatically call the route for the original search location,
  // if visitor has not come to page using a dealer_id
  //if (route_qs.value != '') callRoute();
}
//]]> 
// -->
