var map;
var council_locations = typeof(region_locations)=="undefined" ? {} : region_locations;
var elevation_marker;
var default_text = "Enter address";
var autocomplete_path = "http://api.addressfinder.co.nz/autocomplete/address/";
var autocomplete_key = "d1707a90-fd84-012c-d9c3-00e08121877f";
var poi_markers = [];
var ALL_POI_TYPES = ['cycle_rack', 'toilet', 'drinking_fountain','streetlight', //'bus_stop',
  'seat', 'traffic_light', 'zebra_crossing', 'bike_shop', 
  'information', 'library', 'playground', 'pool', 'rec_centre', 
  'reserve', 'school', 'skatepark', 'museum', 'council_building', 
  'church', 'airport', 'landmark', 'park', 'shopping_mall', 'hospital', 'theatre'];
var PRINT_POI_TYPES = ['toilet', 'landmark', 'information'];
var PATH_TYPES = ["shared_sealed", "state_highway", "shared_unsealed", "main_roads", "pedestrian_sealed", "minor_roads", "pedestrian_unsealed", "main_paths", "cycle_lane","tracks"];
var show_print_pois = true;

var POIS_PATH = "/pois";
var POIS_COUNT_PATH = "/pois/count";
var WEATHER_PATH = "/weather_datas/today";
var WELLINGTON_PXID = "F";

var PIXEL_DIST = 7;//px
var BASE_URL = "/routing/jroute";
var WALK = "walking";
var CYCLE = "cycling";
var MAX_VIA = 10;
var JOURNEY = 1; 
var DIRECTIONS = 2;

if (typeof(window.setting_type)=="undefined") {
  window.setting_type = JOURNEY;
}
  
//Setup global loading javascript
var loadingTimeout;
function showGlobalLoading() {
  if (loadingTimeout) {
    clearTimeout(loadingTimeout);
    loadingTimeout = null;
  }
  loadingTimeout = setTimeout("$('#global_loading_indicator').show()", 400);
}
function hideGlobalLoading() {
  if (loadingTimeout) {
    clearTimeout(loadingTimeout);
    loadingTimeout = null;
  }
  setTimeout("$('#global_loading_indicator').hide()", 10);
}
$().ajaxStart(function(){
  showGlobalLoading();
});
$().ajaxStop(function(){
  hideGlobalLoading();
});

// Helper method
Function.prototype.bind = function() {
  var a=[], i=arguments.length;
  while (i--) a[i] = arguments[i];
  var f=this, c=a.shift();
  return function() { f.apply(c, a); };
};
Array.prototype.contains = function(a) {
  var i=this.length;
  while (i--)
    if (this[i]==a)
      return true;
  return false;
};

var is_numeric = function(string) {
  return /(^[0-9.]+$)|(^$)/.test(string);
};

if (!Array.prototype.filter) {
  Array.prototype.filter = function(func) {
    var ary = new Array();
    for (var i=0;i<this.length;i++)
      if ( func( this[i] ) )
        ary.push( this[i] );
    return ary;
  };
}

var fix_svg_printing_counter = 0;
window.fix_svg_printing = function () {
  // Undo Google's disabling of SVG printing in Firefox as the
  // relevant bug no longer exists in modern Firefox versions.
  // Nice work, Google!
  fix_svg_printing_counter += 1;
  $("svg").parent().removeClass("gmnoprint");
  if($("svg").parent().hasClass("gmnoprint") || (fix_svg_printing_counter < 100 && $("svg").size() < 1)) {
    setTimeout("window.fix_svg_printing()", 100);
  }
};

window.getDeltaLat = function() {
        var t = window.getDeltaLat;
        if (t.zoom==map.getZoom())
                return t.delta;
        var c_l = map.getCenter();
        var c_p = map.fromLatLngToDivPixel(c_l);
        var d = Math.pow(2, 0.5)*PIXEL_DIST;
        var d_p = new GPoint(c_p.x+d, c_p.y+d);
        var d_l = map.fromDivPixelToLatLng(d_p);
        t.delta = Math.abs(d_l.lat()-c_l.lat());
        t.zoom = map.getZoom();
        return t.delta;
};

window.update_map_common = function() {
  if (typeof(map)=="undefined")
    return setTimeout(window.update_map_common, 100); // Allow for misordered updates

  // Remove anything added last time
  if (window.routing_polyline!=undefined) {
    map.removeOverlay(window.routing_polyline);
  }

  if (window.waypoints_list!=undefined) {
    var list = window.waypoints_list;
    for (var i=0;i<list.length;i++) {
      map.removeOverlay(list[i]);
    }
  }

  if (window.routing_circle!=undefined) {
    map.removeOverlay(window.routing_circle);
  }
};

var reverse_geocode = {
// public methods
  // Send off the request for the address
  prepare_lookup : function(/*GLatLng*/ latlng) {
    var params = {x:latlng.x, y:latlng.y};
    var key = this._key(latlng);
    var value = this.cache[key];
    if (!value)
      $.get("/routing/reverse_geocode", params, this._wrapper(this._callback, params));
  },

  // Wait for request to finish
  lookup : function(/*GLatLng*/ latlng, /*Function*/ callback) {
    var request = {latlng:latlng, callback:callback};
    this._waiting.push( request );
    this._lookup_request();
  },

// private methods
  // Received address from server
  _callback : function(params, data) {
    reverse_geocode.cache[ reverse_geocode._key(params) ] = data;
    reverse_geocode._lookup_request();
  },

  // Applies a simple wrapper to a function
  _wrapper : function(func, obj1) {
    return function(obj2) {
      func(obj1, obj2);
    };
  },

  // Generate key
  _key : function(params) {
    var scale = 1000000; // 6dp max
    var x = Math.floor(params.x * scale)/scale;
    var y = Math.floor(params.y * scale)/scale;
    return x + "_" + y;
  },

  // Try and satisfy requests
  _lookup_request : function() {
    var ary = this._waiting;
    var unable = new Array();
    for (var i=ary.length;i--;) {
      var key = this._key(ary[i].latlng);
      var value = this.cache[key];
      if (value) {
        ary[i].callback(value);
      } else {        
        unable.push(ary[i]);
      }
    }
    this._waiting = unable;
  },

  cache : new Object(),
  _waiting : new Array()
};

var add_right_click_menu = function() { // Add right click menu to the page
  // Create menu and add to map
  var menu = document.createElement("div");
  var $menu = $(menu);
  $menu.html("<div class=\"rightclickmenu\">\n<div id=\"address0\"  class=\"rightclickitem\">Add&nbsp;to&nbsp;starting&nbsp;address<\/div>\n<div id=\"address1a\" class=\"rightclickitem\">Add&nbsp;to&nbsp;destination&nbsp;address<\/div>\n<div id=\"address1b\" class=\"rightclickitem\">Add&nbsp;to&nbsp;first&nbsp;destination&nbsp;address<\/div>\n<div id=\"address2\"  class=\"rightclickitem\">Add&nbsp;to&nbsp;second&nbsp;destination&nbsp;address<\/div>\n<div id=\"address3\"  class=\"rightclickitem\">Add&nbsp;to&nbsp;third&nbsp;destination&nbsp;address<\/div>\n<div id=\"address4\"  class=\"rightclickitem\">Add&nbsp;to&nbsp;fourth&nbsp;destination&nbsp;address<\/div>\n<div id=\"address5\"  class=\"rightclickitem\">Add&nbsp;to&nbsp;fifth&nbsp;destination&nbsp;address<\/div>\n<div id=\"address6\"  class=\"rightclickitem\">Add&nbsp;to&nbsp;sixth&nbsp;destination&nbsp;address<\/div>\n<div id=\"address7\"  class=\"rightclickitem\">Add&nbsp;to&nbsp;seventh&nbsp;destination&nbsp;address<\/div>\n<div id=\"address8\"  class=\"rightclickitem\">Add&nbsp;to&nbsp;eighth&nbsp;destination&nbsp;address<\/div>\n<div id=\"address9\"  class=\"rightclickitem\">Add&nbsp;to&nbsp;ninth&nbsp;destination&nbsp;address<\/div>\n<\/div>");
  $menu.css({
            display: "none", 
            position: "relative"
           });
  map.getPane(G_MAP_FLOAT_PANE).appendChild(menu);

  // List of input boxes
  var boxes = [
    "dir_from_address",
    "dir_to_address"
  ];
  for (var i=2;i<MAX_VIA;++i)
    boxes.push( "dir_to_address_" + i );

  // Add address to combo box
  var transfer_addr = function(no, address) {
    var box = document.getElementById( boxes[no] );
    if (!box) {      
      return;
    }

    $(box).val(address);
    $(box).css("color", "#000");
    routing.addWayPoint(position2Index_from0(no), latlng, address, false);
  };

  // Wait for AJAX to finish before continuing
  var transfer_addr_prepare = function(latlng, no) {
    reverse_geocode.lookup( latlng, reverse_geocode._wrapper(transfer_addr, no) );
  };

  // Show event
  var latlng = null;
  var right_click_event = function(point) {
    var offset = map.getPane(G_MAP_MARKER_PANE).parentNode.style;
    var d_x = parseInt(offset.left), d_y = parseInt(offset.top);
    point.x -= d_x; point.y -= d_y;

    menu.style.left = point.x + "px";
    menu.style.top  = point.y + "px";
    $menu.show();

    latlng = map.fromDivPixelToLatLng(point);
    reverse_geocode.prepare_lookup(latlng);
  };

  // Hide event
  var clear_menu = function() {
    $menu.hide();
  };

  // Select event
  var item_click = function() {
    var id = this.id;
    var match = id.match(/address(.)(.?)/), no = match[1], type = match[2];

    transfer_addr_prepare(latlng, no);
    clear_menu();
  };

  // Style for initial display and add events
  var items = $(".rightclickitem");
  for (var i=items.length;i--;) {
    var match = items[i].id.match(/address(.)(.?)/), no = match[1], type = match[2];
    if (no>=2||type=="b")
      items[i].style.display = "none";
    $(items[i]).click(item_click);
  }
  $(document).click(clear_menu);
  GEvent.addListener(map, "singlerightclick", right_click_event);
};

var gmap_map_control_styling = function() {
  var ctrl = document.getElementById("menumtctl_main");
  if (ctrl==null) {
    setTimeout(gmap_map_control_styling, 100);
    return;
  }

  var node = ctrl.childNodes[0];
  var arrow, arrow_list = node.getElementsByTagName("img");
  if (arrow_list.length>0)
    arrow = arrow_list[0].parentNode;
  var URL = "url(/images/muttons.png)";

  node.style.backgroundImage = URL;
  node.style.backgroundPosition = "-15px -153px";
  node.style.border = "";
  node.style.height = "30px";
  ctrl.style.width = "153px";
  ctrl.style.border = "";
  ctrl.style.height = "30px";
  ctrl.style.background = "transparent";

  ctrl.style.width = "97px";
  node.style.paddingTop = "4px";
  node.style.paddingLeft = "22px";

  if (arrow) {
    arrow.style.backgroundImage = URL;
    arrow.innerHTML = "&nbsp;";
    arrow.style.backgroundPosition = "-15px -15px";
    arrow.style.width = "15px";
    arrow.style.marginTop = "2px";
    arrow.style.height = "16px";
    arrow.style.width = "18px";
  }

  if (jQuery.browser.msie&&jQuery.browser.version=="6.0") { // if ie6
      node.style.background = "transparent";
      node.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='/images/muttonsetc/mutton-panel.png');";
      if (arrow) {
        arrow.style.background = "transparent";
        arrow.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='/images/muttonsetc/arrow.png');";
      }
  }
};

window.setting_address = new Array();
window.getClosest = function(point, callback) {
        if (window.kd_tree==null||window.get_closest_working==true)
                return false;
        window.get_closest_working = true;
        setTimeout(function(point, callback) {
                var p = null;
                if (window.kd_tree!=null)
                        p = window.kd_tree.nearestPoint([ point.lng() * window.kd_tree_factor, point.lat() ], window.getDeltaLat());
                window.get_closest_working = false;
                if (p==null)
                        callback( null );
                else
                        callback( new GLatLng(p[1], p[0] / window.kd_tree_factor) );
        }.bind(this, point, callback), 0);
        return true;
};

window.draggable_routes_queue = new Array(); // TODO: Does this even need to be a queue?
window.encode_latlng = function(p) {
  if (p==undefined||p==null) {
    return "";
  }
  return p.lat() + "," + p.lng();
};
window.dr_update = function() {
        if (window.dr_update_executing==true||window.draggable_routes_queue.length==0)
                return; 
        window.dr_update_executing = true;
        window.dr_start = new Date();
        var d = window.draggable_routes_queue.pop();
        window.draggable_routes_queue = new Array();
        var first, last;
        var middle = d[0];
        if (window.draggable_primary_start_latlng==undefined) {
                if (d[1]==0) {
                        first = undefined;
                        last = window.encode_latlng(render_list[1]);
                }
                else if (d[1]==render_list.length-1) {
                        first = window.encode_latlng(render_list[render_list.length-2]);
                        last = undefined;
                }
                else if (d[1]==parseInt(d[1])) {
                        first = window.encode_latlng(render_list[d[1]-1]);
                        last = window.encode_latlng(render_list[d[1]+1]);
                }
                else {
                        first = window.encode_latlng(render_list[Math.floor(d[1])]);
                        last = window.encode_latlng(render_list[Math.ceil(d[1])]);
                }
                window.draggable_primary_start_latlng = first;
                window.draggable_primary_end_latlng = last;
        } else {
                first = window.draggable_primary_start_latlng;
                last = window.draggable_primary_end_latlng;
        }
        var partial_url = "?a=" + first + "&b=" + middle + "&c=" + last + "&mode=" + window.setting_mode + "&move=false";
        jQuery.getJSON(BASE_URL + partial_url, [], window.dr_response);
};
window.ajaxError = function(evt, req, opt, err) {
        window.dr_update_executing = false;
};
window.dr_response = function(data, status) {
        window.dr_start = (new Date())-window.dr_start;
        routing.has_results = true;
        if (status!="success") {
                window.dr_update_executing = false;
                return;
        }

        var func = window.replaceLine;
        if (window.draggable_primary_replace==false&&window.draggable_primary_update!=parseInt(window.draggable_primary_update)) {
                func = window.insertLine;
                window.draggable_primary_replace = true;
        }
        var npoint = data.point;
        var nline1 = data.geom_s;
        var nline2 = data.geom_e;
        func(Math.ceil(window.draggable_primary_update), npoint, nline1, nline2);
        window.dr_update_executing = false;
        window.dr_update();
};
window.dr_enqueue = function(data) {
        window.draggable_routes_queue.push(data);
        window.dr_update();
};
window.add_direction_markers = function() {
  $.each(window.direction_markers, add_this_overlay);
};
window.remove_direction_markers = function() {
  if (window.direction_markers_hiding_event) {
    GEvent.removeListener(window.direction_markers_hiding_event);
  }
  $.each(window.direction_markers, remove_this_overlay);
/*  while ( window.direction_markers.length>0 )
    map.removeOverlay( window.direction_markers.pop() );*/
};
window.draggable_routes_begin = function() {
        window.draggable_marker_update = false;
        window.draggable_primary_update = -1;
        window.draggable_primary_start_latlng = undefined;
        window.draggable_primary_end_latlng = undefined;
        window.draggable_primary_replace = false;
        window.dr_update_executing = false;
        $("#placeholder").unbind(); // stop elevation graph hover behaviour
        window.remove_direction_markers();
};
window.draggable_routes_latlng_update = function(p_l) {
        var str = window.encode_latlng(p_l);
        if (window.draggable_primary_update==-1) {
                if (window.kd_tree==null)
                        return; // Error?
                var p = window.kd_tree.nearestPointNode([ p_l.lng() * window.kd_tree_factor, p_l.lat() ], window.getDeltaLat());
                if (p==null||p[RET_NODE]==null)
                        return; // Error?
                var n_id = TreeNNS.getNodeId( p[RET_NODE] )*2;
                for (var i=0;i<window.polyline_lengths.length;i++)
                        if (window.polyline_lengths[i]>n_id)
                                break;
                n_id += i;
                for (var i=0;i<window.polyline_lengths.length;i++)
                        if (window.polyline_lengths[i]>n_id)
                                break;
                window.draggable_primary_update = i+0.5; // Between node i and i+1
        }
        p_l.route_id = window.draggable_primary_update;
        window.dr_enqueue([str, window.draggable_primary_update]);
};
window.draggable_routes_marker_end = function(m) {
        window.draggable_routes_end(m);
        window.draggable_marker_update = true;
};
window.draggable_routes_marker_start = function(m) {
        window.draggable_primary_update = m.route_id;
        window.draggable_marker_update = false;
        window.routing_circle_overlay.style.display = "none";
        window.draggable_primary_start_latlng = undefined;
        window.draggable_primary_end_latlng = undefined;
        window.dr_update_executing = false;
        $("#placeholder").unbind(); // stop elevation graph hover behaviour
        window.remove_direction_markers();
};
window.map_move = function() {
        var offset = $(map.getPane(0)).offset();
        var tmp = new GPoint(offset.left, offset.top);
        window.map_offset = function() { return tmp; };
};
window.map_offset = function() {
        window.map_move();
        return window.map_offset();
};
window.draggable_routes_update = function(d) {
        var x = d.clientX, y = d.clientY;
        x -= window.map_offset().x;
        y -= window.map_offset().y;
        var p_p = new GPoint(x, y);
        var p_l = map.fromDivPixelToLatLng(p_p);
        window.draggable_routes_latlng_update(p_l);
};

window.draggable_routes_end = function(m) {
        window.add_direction_markers();
        if ((m instanceof GLatLng)==false) {
                var x = m.clientX, y = m.clientY;
                x -= window.map_offset().x;
                y -= window.map_offset().y;
                var p_p = new GPoint(x, y);
                m = map.fromDivPixelToLatLng(p_p);
        }
        window.draggable_marker_update = true;
        var make_update = old_routing.clone();
        if (window.draggable_primary_update==parseInt(window.draggable_primary_update)||window.draggable_primary_replace==true) {
          var i = Math.ceil(window.draggable_primary_update), j = true;
          if (i==-1)
            return; // Invalid click, so ignore it
          render_list[i] = m;
          if (window.draggable_primary_update%1==0)
            j = make_update.waypoints[i][VIA];
          else
            make_update.waypoints = make_update.waypoints.slice(0, i).concat(null).concat(make_update.waypoints.slice(i));
          make_update.addWayPoint(i, m, "", j);
        }
        else {
          // Um... do nothing
        }
        var p = make_update.getParams();
        routing = make_update;
        p["move"] = false;
        window.remove_direction_markers();
        $.get("/routing/route", p, function(data){
            window.update_all_social_links();
            routing.has_results = true;
            map.clearOverlays(); // TODO when should we do this?
            eval(data);
        });
};

/* email, social network and print url functions */

/**
 * Modified from iBegin Share 2.44 (Build 1573)
 * MIT Open Source License
 * http://www.ibegin.com/labs/share/
 *
 * Not really big enough to include the whole licence.
 */
var SHARE_SITES = {
    delicious: 'http://del.icio.us/post?&url=__URL__&title=__TITLE__',
    digg: 'http://digg.com/submit/?url=__URL__&title=__TITLE__',
    facebook: 'http://www.facebook.com/share.php?src=bm&u=__URL__&t=__TITLE__&v=3',
    google: 'http://www.google.com/bookmarks/mark?op=add&title=__TITLE__&bkmk=__URL__',
    live: 'http://favorites.live.com/quickadd.aspx?url=__URL__&title=__TITLE__',
    reddit: 'http://reddit.com/submit?url=__URL__&title=__TITLE__',
    stumble: 'http://www.stumbleupon.com/submit?url=__URL__&title=__TITLE__',
    twitter: 'http://twitthis.com/twit?url=__URL__&title=__TITLE__',
    yahoo: 'http://e.my.yahoo.com/config/edit_bookmark?.src=bookmarks&.folder=1&.name=__TITLE__&.url=__URL__&.save=+Save+'
};

window.share_site_url = function(site, title, url) {
    return SHARE_SITES[site].replace('__URL__', encodeURIComponent(url)).replace('__TITLE__', title);
};
/* End of code from iBegin Share */

window.update_all_social_links = function(title, url) {
    var title = "Map from Journey Planner";
    var url = window.create_url("http://www.journeyplanner.org.nz/");
    var social_links = jQuery(".social-share-links");
    for(var i = 0; i < social_links.length; ++i) {
        window.update_social_link(social_links[i], title, url);
    };
};

window.update_social_link = function(elem, title, url) {
    var ext_site = $(elem).attr('id').replace("share-link-", "");
    var share_site_url = window.share_site_url(ext_site, title, url);
    $(elem).attr('href', share_site_url);
};

jQuery(".social-share-links").bind("focus click dblclick mousedown mouseover mouseenter keydown", function(e) {
    var title = "Map from Journey Planner";
    var url = window.create_url("http://www.journeyplanner.org.nz/");
    window.update_social_link(jQuery(e.target), title, url);
});

/* when user clicks "close" or email send completes successfully */
window.drop_box_close = function() {
    var drop_down = jQuery('#drop_down_box');
    drop_down.css('display', 'none');
    jQuery('#email_box_feedback').html("");
    return false;
};

/* when user clicks "contact & feedback */
window.feedback_drop_down_box = function() {
    // Close other popups
    window.drop_down_link_box_close();
    window.drop_box_close();
    window.feedback_resize();
    //$("[name=feedback_message]").width(295);
    $("#feedback_divs").css({display: "block"});
    setTimeout(window.feedback_resize, 100); // Allow for updates to propigate
    return false;
};

/* when user clicks "close" */
window.feedback_drop_down_box_close = function() {
    $("#feedback_divs").css({display: "none"});
    return false;
};
window.feedback_resize = function() {
      var d = $("#feedback_div");
      if (d.length==0)
        return;
      var w = d.width(), h = d.height();
      if (w==0&&h==0) {
        d[0].cache_w = w = d[0].cache_w || 300;
        d[0].cache_h = h = d[0].cache_h || 238;
      }
      var s_w = $(window).width(), s_h = $(window).height();
      var x = (s_w-w)/2, y = (s_h-h)/2;
      d[0].style.left = x + "px";
      d[0].style.top = y + "px";
      var b = $("#feedback_blackout");
      if (b.height()<$(window).height())
        b.height( $(window).height() );
};

/* when user clicks "Share journey: Email" */
window.email_drop_down_box = function() {
    window.drop_down_link_box_close();
    var drop_down = jQuery("#drop_down_box");
    var psb = $('#print_share_box');
    var psb_offset = psb.offset();
    drop_down.css('top', (psb_offset.top + psb.outerHeight(0)).toString());
    drop_down.css('display', 'inline');
};

/* when user clicks "Share journey: Link" */
window.link_drop_down_box = function() {
    window.drop_box_close();
    var drop_down = $("#drop_down_link_box");
    var psb = $('#print_share_box');
    var psb_offset = psb.offset();
    drop_down.css('top', (psb_offset.top + psb.outerHeight(0)).toString() + "px");
    drop_down.css('display', 'inline');
    var a = $("#page_link_a")[0];
    var t = $("#page_link_tb")[0];
    var url = "http://www.journeyplanner.org.nz/" + window.create_url("");
    a.href = url;
    t.value = url;
    t.select();
};

/* when user clicks "close" */
window.drop_down_link_box_close = function() {
    var drop_down = jQuery('#drop_down_link_box');
    drop_down.css('display', 'none');
};

/* when user clicks "Print Map" */
window.print_url = function() {
    window.location = window.create_url("/print");
};

/* when user clicks "send journey map" */
window.email_box_submit = function() {
    var email_box_inputs = jQuery('#email_box_inputs');

    var auth_token = email_box_inputs.find('[name=authenticity_token]').val();
    var p_email_to = email_box_inputs.find('[name=email_to]').val();
    var p_email_from = email_box_inputs.find('[name=email_from]').val();
    var p_sender_name = email_box_inputs.find('[name=sender_name]').val();
    var p_sender_message = email_box_inputs.find('[name=sender_message]').val();

    jQuery.ajax({
        dataType: "text",
        type: "POST",
        url: "/email",
        error: window.email_submit_failure,
        success: window.email_submit_success,
        data: {
            authenticity_token: auth_token,
            email_to: p_email_to,
            email_from: p_email_from,
            sender_name: p_sender_name,
            sender_message: p_sender_message,
            target_path: window.create_url("")
        }
    });
};

/* when user clicks send in feedback box */
window.feedback_submit = function() {
    var inputs = $('#feedback_div');

    var auth_token = inputs.find('[name=authenticity_token]').val();
    var name    = inputs.find('[name=feedback_name]').val();
    var email   = inputs.find('[name=feedback_email]').val();
    var council = inputs.find('[name=feedback_council]').val();
    var message = inputs.find('[name=feedback_message]').val();

    if (name.replace(/[^a-zA-Z]+/, "")=="") {
      $("#feedback_error")[0].innerHTML = "Please enter a valid name";
      $("#feedback_error").show();
      return false;
    }
    if (email == "") {
      email = "no-reply@journeyplanner.org.nz";
    }

    var fail = function() {
      $("#feedback_error")[0].innerHTML = "Please fill in all fields correctly";
      $("#feedback_error").show();
    };
    var pass = function(data) {
      if (data!='ok')
        return fail();
      window.feedback_drop_down_box_close();
    };

    jQuery.ajax({
        dataType: "text",
        type: "POST",
        url: "/email",
        error: fail,
        success: pass,
        data: {
            authenticity_token: auth_token,
            email_to: "support@journeyplanner.org.nz",
            email_from: email,
            sender_name: name,
            sender_message: message,
            council: council,
            target_path: window.create_url("")
        }
    });

    return false;
};

/* if AJAX returns an error */
window.email_submit_failure = function(xhr, status, error) {
    var status_msg;
    var error_msg;

    if(!status) {
        status_msg = "null status";
    } else {
        status_msg = status;
    }

    if(!error) {
        error_msg = "no error";
    } else {
        error_msg = error.toString();
    }

    window.email_not_sent("Could not contact server. Status : " + status_msg + ", Error : " + error_msg);
};

window.email_not_sent = function(message) {
    var feedback = jQuery("#email_box_feedback");
    feedback.removeClass();
    feedback.addClass("email_box_error");
    feedback.html(message);
};

/* when AJAX returns successfully */
window.email_submit_success = function(data, status) {
    if(data == "ok") {
        window.email_sent();
    } else {
        window.email_not_sent(data);
    }
};

window.email_sent = function() {
    var feedback = jQuery("#email_box_feedback");
    feedback.removeClass();
    feedback.addClass("email_box_success");
    feedback.html("Email sent.");
    //setTimeout(window.drop_box_close, 4000);
};

window.create_url = function(prefix) {
        var a = (typeof(old_routing)=="undefined") ? {} : old_routing.getParams(), c=[];
        for(var b in a)
                c.push(b+"="+a[b].toString().replace(/ /g, "+").replace(/&/g, ""));
        return prefix + "?" + c.join("&");
};

window.goHelp = function() {
  window.location = window.create_url("http://www.journeyplanner.org.nz/routing/help");
  return false;
};

var UNPACK_X = 1e6;
var UNPACK_Y = 1e6;
var UNPACK_Z = 1e6;
unpackElevationData = function(minified) {
  var len = Math.floor(minified.length / 3);
  var unpacked = [];

  var unpack = function(val, prev_val, scale) {
    return (val / scale) + prev_val;
  };

  var dist_incr = minified[0];

  unpacked[0] = [
    0,
    unpack(minified[1], 0, UNPACK_Z),
    [
      unpack(minified[2], 0, UNPACK_X),
      unpack(minified[3], 0, UNPACK_Y)
    ]
  ];

  for(var i = 1; i < len; ++i) {
    var min_base = (i * 3) + 1;
    var prev = i - 1;

    unpacked[i] = [
      i * dist_incr,
      unpack(minified[min_base], unpacked[prev][1], UNPACK_Z),
      [
        unpack(minified[min_base + 1], unpacked[prev][2][0], UNPACK_X),
        unpack(minified[min_base + 2], unpacked[prev][2][1], UNPACK_Y)
      ]
    ];
  }
  /*
  UNPACKED = unpacked;

  var latlng = unpacked[unpacked.length - 1][2]
  var x = latlng[0];
  var y = latlng[1];
  */
  return unpacked;
};

// By John Resig (MIT Licensed)
Array.prototype.remove = function(from, to) {
  var rest = this.slice((to || from) + 1 || this.length);
  this.length = from < 0 ? this.length + from : from;
  return this.push.apply(this, rest);
};
var Function_new = function() {
  return function(args){
    if ( this instanceof arguments.callee ) {
      if ( typeof this.init == "function" )
        this.init.apply( this, args.callee ? args : arguments );
    } else
      return new arguments.callee( arguments );
  };
};
// End John Resig

function createCookie(name,value,days) {

        if (days) {
                var date = new Date();
                date.setTime(date.getTime()+(days*24*60*60*1000));
                var expires = "; expires="+date.toGMTString();
        }
        else var expires = "";
        document.cookie = name+"="+value+expires+"; path=/";
}

function readCookie(name) {
        var nameEQ = name + "=";
        var ca = document.cookie.split(';');
        for(var i=0;i < ca.length;i++) {
                var c = ca[i];
                while (c.charAt(0)==' ') c = c.substring(1,c.length);
                if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
        }
        return null;
}

function eraseCookie(name) {
        createCookie(name,"",-1);
}

//Google Maps definitions
GLargeMapControl3D.prototype.getDefaultPosition = GSmallZoomControl3D.prototype.getDefaultPosition = function() {
        return new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(7, 7+21));;
};

function zOrderAlwaysOnTop() {
  return GOverlay.getZIndex(-90);
}
var gwrc_elev_icon = new GIcon(G_DEFAULT_ICON);
gwrc_elev_icon.image = '/images/icon_walker.png';
gwrc_elev_icon.iconSize = new GSize(24,36);
gwrc_elev_icon.shadow = '/images/shadow.png';
gwrc_elev_icon.shadowSize = new GSize(41,36);
gwrc_elev_icon.printShadow = '/images/shadow.gif';
var GWRC_ELEV_ICON = gwrc_elev_icon;

/** Temp for arrows **/
// === The basis of the arrow icon information ===
var arrowIcon = new GIcon();
arrowIcon.iconSize = new GSize(24,24);
arrowIcon.shadowSize = new GSize(1,1);
arrowIcon.iconAnchor = new GPoint(12,12);
arrowIcon.infoWindowAnchor = new GPoint(0,0);
/** Arrows **/

//Map Controls
/*
 * Constructor for MenuControl, which uses an option hash
 * to decide what elements to put in the control.
 * @param {menuName} Name of the menu
 * @param {opts} Optional arguments:
 *   opts.menuContents {String} HTML of expanded menu content (shown when menu is clicked)
 */
function MenuControl(menuName, opts){
  this.menuName_ = menuName;
  this.options = opts || {};
};
MenuControl.prototype = new GControl();
MenuControl.global_contents = new Array();
MenuControl.global_signs    = new Array();
MenuControl.event_count = 0;
MenuControl.id_seq = 0;
MenuControl.event_timeout = null;
MenuControl.prototype.initialize = function(map){
    var me = this;
    var container = document.createElement("div");
    MenuControl.id_seq += 1;

    // TODO: put style info in CSS?
    var menuDiv = document.createElement("div");
    menuDiv.style.background = "transparent";
//    menuDiv.style.border = "1px solid #f89d32";

    menuDiv.style.backgroundImage = "url(/images/muttons.png)";
    menuDiv.style.backgroundPosition = "-15px -153px";
    menuDiv.style.width = "144px"; //154-10
    menuDiv.style.height = "25px";

    menuDiv.style.textAlign = "center";
    menuDiv.setAttribute("valign", "middle");
    menuDiv.style.textAlign = "center";
    menuDiv.style.paddingTop = "5px";
    menuDiv.style.cssFloat = "left";
    menuDiv.style.styleFloat = "left";
    menuDiv.style.cursor = "pointer";
    menuDiv.style.paddingRight = "10px";
    menuDiv.id = "menuDiv" + MenuControl.id_seq;

    var expandedMenuDiv = document.createElement("div");
    expandedMenuDiv.style.clear = "both";
    expandedMenuDiv.style.display = "none";
    expandedMenuDiv.style.width = "154px";//(me.options.width==undefined) ? "110px" : (parseInt(me.options.width) + "px");
    expandedMenuDiv.style.background = "white";
    expandedMenuDiv.style.border = "0px solid #f89d32";
    //expandedMenuDiv.style.borderTop = "0px solid #f89d32";
    expandedMenuDiv.style.position = "absolute";
    expandedMenuDiv.style.top = "30px";
    expandedMenuDiv.id = "expandedMenuDiv" + MenuControl.id_seq;
    if (me.options.menuContents) {
      expandedMenuDiv.innerHTML += me.options.menuContents;
    }
    MenuControl.global_contents.push(expandedMenuDiv);

    var toggleArrow = document.createElement("span");
    toggleArrow.style.position = "absolute";
    toggleArrow.style.right = "8px";
    toggleArrow.style.top = "5px";
    toggleArrow.style.backgroundImage = "url(/images/muttons.png)";
    toggleArrow.style.width = "18px";
    toggleArrow.style.height = "16px";
    toggleArrow.innerHTML = "&nbsp;";
    toggleArrow.style.backgroundPosition = "-15px -213px";
    MenuControl.global_signs.push(toggleArrow);

    if (jQuery.browser.msie&&jQuery.browser.version=="6.0") { // if ie6
      menuDiv.style.background = "transparent";
      menuDiv.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='/images/muttonsetc/mutton-panel.png');";
      toggleArrow.style.background = "transparent";
      toggleArrow.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='/images/muttonsetc/plus.png');";
    }

    GEvent.addDomListener(menuDiv, 'click', function() {
      me.toggleContent_(expandedMenuDiv, toggleArrow);
    });
    GEvent.addDomListener(toggleArrow, 'click', function() {
      me.toggleContent_(expandedMenuDiv, toggleArrow);
    });

    var spanElement = document.createElement("span");
    spanElement.style.position = "relative";
    var b = document.createElement("strong");
    b.appendChild(document.createTextNode(me.menuName_));
    spanElement.appendChild(b);
    menuDiv.appendChild(spanElement);
    container.appendChild(menuDiv);
    container.appendChild(expandedMenuDiv);
    container.appendChild(toggleArrow);

    map.getContainer().appendChild(container);
    me.menuContentsContainer_ = expandedMenuDiv;
    me.container = container;

    return container;
};
//Fast hack for toggle. notice jquery is encapsulated inside
MenuControl.prototype.toggleContent_ = function(contentDiv, toggleArrow) {
  for (var i=0;i<MenuControl.global_contents.length;i++)
    if (contentDiv!=MenuControl.global_contents[i])
      $(MenuControl.global_contents[i]).hide();
  if (contentDiv)
    $(contentDiv).toggle();

  var l = MenuControl.global_signs;
  for (var i=l.length;i--;) {
    if (jQuery.browser.msie&&jQuery.browser.version=="6.0")
      l[i].style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='/images/muttonsetc/plus.png');";
    else
      l[i].style.backgroundPosition = "-15px -213px";
  }
    
  if ( $(contentDiv).is(":visible") ) // Flip between + and - signs
    if (jQuery.browser.msie&&jQuery.browser.version=="6.0")
      toggleArrow.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='/images/muttonsetc/minus.png');";
    else
      toggleArrow.style.backgroundPosition = "-15px -107px";
  else
    if (jQuery.browser.msie&&jQuery.browser.version=="6.0")
      toggleArrow.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='/images/muttonsetc/plus.png');";
    else
      toggleArrow.style.backgroundPosition = "-15px -213px";
};
MenuControl.prototype.setMenuContent = function(contentHTML){
  this.menuContentsContainer_.innerHTML = contentHTML;
};
MenuControl.prototype.redraw = function(){
};
MenuControl.prototype.getDefaultPosition = function(){
  return new GControlPosition(G_ANCHOR_TOP_RIGHT, new GSize(105, 7));
};

//End of On Map controls

//Top-left drop-down
var zoomToCity = function(city_name) {
  var position = council_locations[city_name];
  map.setCenter(new GLatLng(position.y, position.x), position.z);
};

// Weather
var updateWeather = function() {
  $.ajax({
    url: WEATHER_PATH,
    port: "weather",
    success: function(data) {
      $('#weatherContainer').html(data);
      showWeatherFor($('#councils').val());
    }
  });
};

var showWeatherFor = function(city_name) {
  city_name = city_name.toString().replace(/ /g, "_");
  $('.weather_data_container').hide();
  $('#weather-region-' + city_name).show();      //Show only one region's weather
};

// Pois
// TODO Use MarkerClusterer for Street Lights
// TODO Use Ajax Queue
// TODO respect preferences for hiding types in cookie
//  Need to use marker manager
// FIXME - Icons
window.updatePois = function() {
  var z = map.getZoom();
  if (z < 13) {                           //This should be the min of all poi_types
    $('#pois_keys_message').show();
    clearPois();
    return;
  }
  $('#pois_keys_message').hide();
  var sw = map.getBounds().getSouthWest();
  var ne = map.getBounds().getNorthEast();
  var x1 = sw.x, y1 = sw.y;
  var x2 = ne.x, y2 = ne.y;
  showPois(x1, y1, x2, y2, z);
};

window.updatePrintPois = function () {
  if(show_print_pois) {
    var sw = map.getBounds().getSouthWest();
    var ne = map.getBounds().getNorthEast();
    var x1 = sw.x, y1 = sw.y;
    var x2 = ne.x, y2 = ne.y;
    showPrintPois(x1, y1, x2, y2);
  }
};

var findAllHiddenPoiTypes = function () {
  var result = [];
  $.each(ALL_POI_TYPES, function() {
    var cookie_name = 'hide-' + this;
    if (readCookie(cookie_name)) {
      result.push(this);
    }
  });
  return result;
};

//var POINTS_OF_INTEREST = "points_of_interest";
var POINTS_OF_INTEREST = "poi";
var showPois = function(x1, y1, x2, y2, z) {
  var hidden_poi_types = findAllHiddenPoiTypes();
  $.getJSON(POIS_PATH, {x1: x1, y1: y1, x2: x2, y2: y2, z: z}, function(data) {
    clearPois();
    $.each(data, function() {
      var poi = this[POINTS_OF_INTEREST];
      if (hidden_poi_types.contains(poi.poi_type)) {
        return;
      }
	
      var m = new MarkerLight(new GLatLng(poi.y, poi.x),
                        { height: 20, width: 20,
                          image: "/images/poi_icons/" + poi.poi_type + ".png",
                          title: poi.title} );
      poi_markers.push(m);
      map.addOverlay(m);
    });

    var pois_types_numbers = new Object(); 
    for (var i=data.length;i--;) {
      var t = data[i][POINTS_OF_INTEREST].poi_type; 
      if (t in pois_types_numbers)
        pois_types_numbers[t] += 1;
      else
        pois_types_numbers[t] = 1;
    }
    updatePoiIconNumbers(pois_types_numbers);
  });
};

var showPrintPois = function(x1, y1, x2, y2) {
  $.getJSON(POIS_PATH, {x1: x1, y1: y1, x2: x2, y2: y2, filter: 'print'}, function(data) {
    clearPois();
    $.each(data, function() {
      var poi = this[POINTS_OF_INTEREST];
      if (!(PRINT_POI_TYPES.contains(poi.poi_type))) {
        return;
      }
	
      var m = new MarkerLight(new GLatLng(poi.y, poi.x),
                        { height: 20, width: 20,
                          image: "/images/poi_icons/" + poi.poi_type + ".png",
                          title: poi.title} );
      poi_markers.push(m);
      map.addOverlay(m);
      var poi_list_item = document.createElement("li");
      $(poi_list_item).html(poi.title + ", <i>" + poi.address + "</i>");
      $("#print_poi_list").append(poi_list_item);
    });
  });
};
var addPathTypeControls = function(path_types){
	var $path_tile_types = $("#path_tile_types");
	$path_tile_types.empty();
	var $paths_table = $("<table>");
	$paths_table.addClass("layout_table");
	$path_tile_types.append($paths_table);
	var $last_tr;
	$.each(path_types, function(idx,path_type){
		var path_text = path_type.replace("_",' ');
		var $icon = $("<img>").attr({
			'class':'icon', 
			src:"/images/path_icons/"+path_type+".png",
			id:"path-"+path_type,
			title: path_text
			});
		var $descript = $("<span>").addClass("poi_title").text(path_text);
		var $td = $("<td>").append($icon).append($descript);
		
		if (!$last_tr || idx % 2 == 0) {
      $last_tr = $("<tr>");
      $paths_table.append($last_tr);
    }
    $last_tr.append($td);
	});
};


var updatePoiIconNumbers = function(poi_types_numbers) {
  $('#pois_keys span.icon_numbers').empty();
  $.each(poi_types_numbers, function(poi_type, number) {
    $('#icon-number-' + poi_type).text(" (" + number + ")");
  });
};

var updatePoiIconKeys = function(poi_types) {
  var $pois_keys = $('#pois_keys');
  $pois_keys.empty();		
  var pois_table = document.createElement('table');
  $(pois_table).addClass('layout_table');
  $pois_keys.append(pois_table);
  var last_tr;

  $.each(poi_types, function(idx, poi_type) {
    var $icon = $("<img class='icon' src='/images/poi_icons/" +
      poi_type + ".png' title='" + poi_type.replace('_', ' ') + "' id='icon-" + poi_type + "' />" + 
      "<span class='poi_title'>" + poi_type.replace('_', ' ') + "</span><span class='icon_numbers' id='icon-number-" + poi_type +"'></span>");
    if (readCookie('hide-' + poi_type)) {
      $icon.addClass('icon-toggle');
    }
    var td = $(document.createElement('td'));			
    td.html($icon);
    td.click(function(){
      var cookie_name = 'hide-' + poi_type;
      if (readCookie(cookie_name)) {
        eraseCookie(cookie_name);
        $(this).children('.icon').removeClass('icon-toggle');
        window.updatePois();
      } else {
        createCookie('hide-' + poi_type, poi_type, 10);
        $(this).children('.icon').addClass('icon-toggle');
        hidePois(poi_type);
      }
    });
    if (!last_tr || idx % 2 == 0) {
      last_tr = document.createElement("tr");
      $(pois_table).append(last_tr);
    }
    $(last_tr).append(td);
  });
};

var hidePois = function(poi_type) {
  $.each(poi_markers, function() {
    if(this.image_=="/images/poi_icons/" + poi_type + ".png")
      map.removeOverlay(this);
  });
};

var clearPois = function() {
  $.each(poi_markers, function() {
    map.removeOverlay(this);
  });
  poi_markers = [];
  $("#print_poi_list").html("");
};

// ZRoute
/** Ordered array of waypoints **/
var LATLNG = 0, ADDRESS = 1, VIA = 2;
var ZRoute = Function_new();
ZRoute.prototype.WALKING = 'walking';
ZRoute.prototype.CYCLING = 'cycling';
ZRoute.prototype.overlays = new Array();
ZRoute.prototype._overlays_hidden = false;
ZRoute.prototype.init = function(length){
  this.waypoints = new Array(length);
  
  this.current_mode = 'walking';
  this.has_results = false;
};
ZRoute.prototype.addWayPoint = function(idx, g_lat_lng, address, via){
  if (via == false && this.waypoints[idx] && this.waypoints[idx][VIA] == true) {
    idx += 1;
  }
  this.waypoints[idx] = [g_lat_lng, address, via];
};
ZRoute.prototype.removeWayPointN = function(position){
  this.waypoints[position] = null;
};
ZRoute.prototype.substituteWayPointN = function(idx, glatlng, name, via) {
  this.waypoints[idx] = [glatlng, name, via];
};
ZRoute.prototype.clear = function(/*Boolean*/ force) {
  this.waypoints = new Array();
  if (force===true) {
    $.each(this.overlays, remove_this_overlay);
    this.overlays = new Array();
    $.each(polyline_render, remove_this_overlay);
//    polyline_render = new Array();
    if (typeof(window.direction_markers)!="undefined")
      $.each(window.direction_markers, remove_this_overlay);
    window.direction_markers = new Array();
  }
};
ZRoute.prototype.clone = function() {
  var r = new ZRoute(this.waypoints.length);
  r.waypoints = this.waypoints.slice();
  r.current_mode = this.current_mode;
  r.has_results = this.has_results;
  r._overlays_hidden = this._overlays_hidden;
  r.overlays = this.overlays.slice();
  return r;
}
ZRoute.prototype.getParams = function() {
  var params = {};
  var clean_latlng = function(no) {
    return new String(no).replace(/^(.*\..{6}).*$/, "$1"); // round down to 6dp
  };
  for (var i=0;i<this.waypoints.length;i++) {
    var  g_lat_lng = this.waypoints[i][LATLNG],
            address = this.waypoints[i][ADDRESS],
            via = this.waypoints[i][VIA];
    var j = (i==0) ? "" : i;
    if (g_lat_lng) {
      params['x' + j] = clean_latlng(g_lat_lng.x);
      params['y' + j] = clean_latlng(g_lat_lng.y);
      params['a' + j] = address || "";
      params['v' + j] = (via==true) ? "t" : "f";
    }
  }
  params['mode'] = this.current_mode;
  return params;
};
ZRoute.prototype.incomplete = function() {
  for (var i=0;i<this.waypoints.length;i++) {
    if (!this.waypoints[i])
      return true;

    var g_lat_lng = this.waypoints[i][0];
    if (!g_lat_lng)
      return true;
  }
  return false;
};
// geocode the address here
// if one, just assign
// if multiple offer choices
ZRoute.prototype.geocode_all = function() {
  for (var i=0;i<this.waypoints.length;i++) {
    var address;
    if (this.waypoints[i]==undefined) {
      var name = (i==0 ? 'a' : 'a' + i);
      var selector = '[name=' + name + ']';
      address = $(selector).val();
    } else {
      var g_lat_lng = this.waypoints[i][LATLNG];
      address = this.waypoints[i][ADDRESS];
      if (g_lat_lng && address) {          
        continue;
      }
      if (!address) {
        var name = (i == 0 ? 'a' : 'a' + i);
        var selector = '[name=' + name + ']';
        address = $(selector).val();
      }
    }
    if (address) {
      $.getJSON(ZRoute.autocomplete_url(address, autocomplete_path, autocomplete_key, WELLINGTON_PXID), function(data) {
        var results = [];
        $.each(data.results, function(index, val) {
          results.push(val);
        });
        if (results.length==1) {
          var result = results[0];
          routing.addWayPoint(i, new GLatLng(result.y, result.x), result.a, false);
          submit_directions_form();
        } else {                      
          display_directions_choices(results, i, address);
        }
      });
      break;
    }
  }
};
        
ZRoute.autocomplete_url = function(address, path, key, pxid) {
  return (path + address + "?callback=?&key=" + key + "&page=1&q=" + address + "&region=" + pxid);
};
        
ZRoute.prototype.swap = function(){
  if (this.waypoints.length==1)
    this.waypoints.push( [] );
  this.waypoints = this.waypoints.reverse();
  submit_directions_form(true);
};
ZRoute.prototype.setMode = function(mode){
  this.current_mode = mode;
};
ZRoute.prototype.hide_overlays = function() {
  if(!this._overlays_hidden) {
    $.each(this.overlays, remove_this_overlay);
    $.each(polyline_render, remove_this_overlay);
    if (typeof(window.direction_markers)!="undefined")
      $.each(window.direction_markers, remove_this_overlay);
    this._overlays_hidden = true;
  }
};
ZRoute.prototype.show_overlays = function() {
  if(this._overlays_hidden) {
    $.each(this.overlays, add_this_overlay);
    $.each(polyline_render, add_this_overlay);
    if (typeof(window.direction_markers)!="undefined")
      $.each(window.direction_markers, add_this_overlay);
    this._overlays_hidden = false;
  }
};

remove_this_overlay = function() {
  map.removeOverlay(this);
};
add_this_overlay = function() {
  map.addOverlay(this);
};

/*** Startup an instance ***/
var routing = new ZRoute(2);
/** */

var display_directions_choices = function(results, position, query) {
  if (results.length < 1) {
    $('#directions').html("Unable to understand <strong>" + query + "</strong>");
    return;
  }
  var text = "Select an item";
  var name = (position == 0 ? 'a' : 'a' + position);
  var selector = '[name=' + name + ']';
  $.each(results, function(i, result){
    text += "<p><a href=\"#\" onclick=\"routing.addWayPoint(position2Index(" + position + "), new GLatLng(" + result.y + ", " + result.x + "), '" + result.a + "', false);" + "$('" + selector + "').val('" + result.a + "'); submit_directions_form();\">" + result.a + "</a></p>";
  });
  $('#directions').html(text);
};

var submit_directions_form = function(/*Boolean*/ preserve, /*Boolean*/ preserve_journey) {
  if (preserve == undefined) {
    preserve = false;
  }
  if (preserve_journey == undefined) {
    preserve_journey = false;
  }

  $('[name=a]').removeClass('fieldWithErrors');
  $('[name=a1]').removeClass('fieldWithErrors');
  remove_default_text($('[name=a]'));
  remove_default_text($('[name=a1]'));

  routing.waypoints = routing.waypoints.filter( function(x){return x!=null} ); // Remove the nulls...

  //Case: any empty
  if ($.trim($('[name=a]').val())=="") {
    $('[name=a]').addClass('fieldWithErrors');
    $('#directions').html('<p class="fieldWithErrors" style="padding: 3px">Enter your starting address</p>');
    return false;
  }
  if (routing.waypoints[0]==undefined || routing.waypoints[0][LATLNG]==undefined) {
    $('[name=a]').addClass('fieldWithErrors');
    $('#directions').html('<p class="fieldWithErrors" style="padding: 3px">Select a starting address from the list</p>');
    return false;
  }
  if ($.trim($('[name=a1]').val())=="") {
    $('[name=a1]').addClass('fieldWithErrors');
    $('#directions').html('<p class="fieldWithErrors" style="padding: 3px">Enter your destination address</p>');
    return false;
  }
  if (routing.waypoints[1]==undefined || routing.waypoints[1][LATLNG]==undefined) {
    $('[name=a1]').addClass('fieldWithErrors');
    $('#directions').html('<p class="fieldWithErrors" style="padding: 3px">Select a destination address from the list</p>');
    return false;
  }

  if (routing.incomplete()) {
    routing.geocode_all();
  }

  // COMMENTing this out as causing problems, poorly understood, need to refactor: TODO
  // If there are extra points, remove them
  if (preserve == false && destinationCount == 2) {
    //routing.waypoints = [routing.waypoints[0], routing.waypoints[1]];
    //routing.waypoints = [routing.waypoints[0], routing.waypoints[routing.waypoints.length-1]];
  }

  if (!preserve_journey)
    window.setting_type = DIRECTIONS;
    
  show_directions_tab();  
    
  get_ajax_route(routing.getParams());
  return false;
};

var get_ajax_route = function(params) {
  $.get("/routing/route", params, function(data){
    window.update_all_social_links();
    if (window.setting_type==DIRECTIONS)
      map.clearOverlays();
    routing.has_results = true;
    eval(data);
  });
};

var show_directions_tab = function() {
  $('#tab_directions').show();
  $('#gap_tab_directions').hide();
};

var hide_directions_tab = function() {
  $('#tab_directions').hide();
  $('#gap_tab_directions').show();
};

//Autocomplete functions
function position2Index(pos) {
  for (var i=0,j=-1;i<routing.waypoints.length;i++) {
    var address = routing.waypoints[i] && routing.waypoints[i][ADDRESS];
    var via = routing.waypoints[i] && routing.waypoints[i][VIA];
    if (routing.waypoints[i] && routing.waypoints[i][VIA] == false) {
      j += 1;
    }
    if (j==pos) {
      return i;
    }
  }
  return routing.waypoints.length;
}

var position2Index_from0 = position2Index;
  
var selectSearchItem = function(pos_idx_f) {
  return function (selected) {
    var x = selected.x;
    var y = selected.y;
    var a = selected.a;
    var pos_idx = pos_idx_f();
    var pos = position2Index(pos_idx);

    window.setting_address[pos_idx] = a;
    routing.addWayPoint(pos, new GLatLng(y, x), a, false);
  };
};
var start_autocomplete = function(){  
  $("#dir_from_address, #dir_to_address").each(function(idx, elem) {
    af_initialise(elem, selectSearchItem(function() { return idx; }), {
      search_type: 'location',
      pagination: false,
      extraParams: {
        region: function() {
          return WELLINGTON_PXID;
        }
      }
    });
  });

  $("#dir_from_address").change(function(){
    var position = position2Index_from0(0);
    if (routing.waypoints[position] && routing.waypoints[position][ADDRESS] == $(this).val())
      return;
    routing.substituteWayPointN(position, null, $(this).val(), false);
  });
  $("#dir_to_address").change(function(){
    var position = position2Index(1);
    if (routing.waypoints[position] && routing.waypoints[position][ADDRESS] == $(this).val())
      return;
    routing.substituteWayPointN(position, null, $(this).val(), false);
  });

};

var remove_default_text = function(element){
  if ($(element).val() == default_text) {
    $(element).val("");
    $(element).css("color", "#000");
  }
};
var restore_default_text = function(element, /*Optional Boolean*/ override){
  override = override===true;
  if ($(element).val() == ""||override) {
    $(element).val(default_text);
    $(element).css("color", "#aaa");
  }
};

var swap_address = function(){
  var swap = $("input#dir_from_address").val();
  var css_swap = $("input#dir_from_address").css("color");
  $("input#dir_from_address").val($("input#dir_to_address").val());
  $("input#dir_from_address").css("color", $("input#dir_to_address").css("color"));
  $("input#dir_to_address").val(swap);
  $("input#dir_to_address").css("color", css_swap);
  routing.swap();
};

var select_mode_activate = function(mode) {
  $('.mode_switch .' + mode + '_mode').addClass("active");
  $('.mode_switch .' + mode + '_mode').removeClass("inactive");
  var e = document.getElementById('mode_image');
  if (e!=null)
    e.src = "/images/" + mode + ".png";
};

var select_mode_deactivate = function(mode) {
  $('.mode_switch .' + mode + '_mode').removeClass("active");
  $('.mode_switch .' + mode + '_mode').addClass("inactive");
};

var select_mode = function(mode) {
  switch (mode) {
    case 'walking':
    routing.setMode(routing.WALKING);
    window.setting_mode = WALK;
    select_mode_deactivate("cycling");
    select_mode_activate("walking");
    break;

    case 'cycling':
    routing.setMode(routing.CYCLING);
    window.setting_mode = CYCLE;
    select_mode_deactivate("walking");
    select_mode_activate("cycling");
    break;
  }

  if (routing.has_results) {
    submit_directions_form(true, true);
  }
    
  if(window.setting_type == JOURNEY) {
    JourneyLines.display(window.setting_mode, false);
  }    
};

var disable_resize_callback = false;
var updateHeightWidth = function(/*Optional Boolean*/ force) {
  if (print_mode) {    
    return;
  }
  
  var cache_window      = $(window);
  var bp                = $('#bottom_panel');
  var cache_map         = $("#map");
  var tab_box_content   = $('#tab_box_content');
  var panel             = $('.left_column');
  var cumulative_offset = cache_map.offset();
  var top_offset        = cumulative_offset.top;
  var height            = cache_window.height() - top_offset;
  var delta             = panel.outerHeight() - panel.height();

  var mapclip           = $("#mapclip");

  if (height > 150) {
    var bottom_panel_height = bp.outerHeight(true);
    if (height-bottom_panel_height!=cache_map.height()) {
      cache_map.css('height', height - bottom_panel_height);
      panel.css('height', height - delta);
    }
  }

  // Width
  var width = mapclip.width()-panel.outerWidth();
  if (width > 1024)
    width = 1024;
  if (width < 300)
    width = 300;

  updateBottomWidth(width, force);  //don't know why we have to minus 10. FIXME

  if (map instanceof GMap2)
    map.checkResize();
};

var updateBottomWidth = function(width, force) {
  var bp = $('#bottom_panel');
  if (force || bp.width() != width - 10) {
    bp.width(width-10);
    $('#bottom_panel .content').     width(width - 9);
    $('#bottom_panel .tabs').        width(width);
    $('#elevation_graph_container'). width(width - 10);
    $('#bottom_panel .tab_gap:last').width(width - 533);
  }
};

var paceChanger = function (show_below_this)  {
  if (show_below_this) {
    $('#pace_chooser').css('left', $(show_below_this).offset().left - 10);
  }
  $('#pace_chooser').toggle();
};

var updateJourneys = function(city_name) {
  var region = region_locations[city_name];
  if (region==undefined)
    return;
  JourneyLines.hide();
  $.get("/routing/update_journey", {id:region.id}, function(data){
    // Update the journey list and JS
    var j = $("#journeys")[0];
    j.innerHTML = data;
    journey_times(); // Updates the times shown in journeys

    var js_obj = data.replace(/\n/g, "").match(/<script.*?>(.*)<\/script>/i); // Can't use the multiline flag??
    var js = js_obj[1];
    eval(js);
    
    // Redraw current journeys
    var type;
    if (window.setting_mode==WALK)
      type = 'walking';
    else
      type = 'cycling';
    routing.has_results = false;
    select_mode(type);
    JourneyLines.display(type);
  });
};

var changePace = function(pace) {
  switch(pace) {
    case 'slow':
      $('#directions_current_speed').html($('#directions_slow_speed').html());
      break;
    case 'average':
      $('#directions_current_speed').html($('#directions_average_speed').html());
      break;
    case 'fast':
      $('#directions_current_speed').html($('#directions_fast_speed').html());
      break;
    default:
      ;
  }
  createCookie('pacing', pace, 10);
  if (window.update_calorie_calc) {
    window.update_calorie_calc();
  }
  $('#pace_chooser').hide();
  window.journey_times();
};

function NorthArrowControl (printable_a) {
  this.printable = function () {
    return printable_a;
  };
  this.selectable = function () {
    return false;
  };
  
  var position;
  if(printable_a) {
    position = new GControlPosition(G_ANCHOR_BOTTOM_LEFT, new GSize(0, 0));      
  } else {
    position = new GControlPosition(G_ANCHOR_BOTTOM_LEFT, new GSize(0, 35));
  }
  
  this.getDefaultPosition = function () {
    return position;
  };
  this.initialize = function (map) {
    var northContainer = document.createElement("div");
    northContainer.style.height = "54px";
    northContainer.style.width = "60px";
    if(printable_a) {
      $(northContainer).addClass("gmnoscreen");      
    }
    var northImage = document.createElement("img");
    northImage.alt = "An arrow indicating that North is directly up on the page";
    northImage.src = "/images/north_arrow.png";
    northContainer.appendChild(northImage);
    map.getContainer().appendChild(northContainer);
    return northContainer;
  };
}

//Startup
var startup = function(){
    if (document.getElementById("map")==null) {
      return;
    }

    $(window).resize(function(){
      updateHeightWidth();
      window.feedback_resize();
    });
    updateHeightWidth();
    //Start autocomplete
    start_autocomplete();

    //Google Map.
    if (GBrowserIsCompatible()) {
      map = new GMap2(document.getElementById("map"));
      map.setCenter(new GLatLng(-41.19518982948958, 175.31982421875), 9);
      map.addControl(new GMenuMapTypeControl());
      map.addControl(new GLargeMapControl());
      var scaleControl = new GScaleControl();
      scaleControl.printable = function () { return true; };
      map.addControl(scaleControl);
      map.enableScrollWheelZoom();

      if (print_mode) {
        // add both printable and non-printable versions
        map.addControl(new NorthArrowControl(true));
        map.addControl(new NorthArrowControl(false));
      } else {        
        map.addControl(new ToggleControl);
        map.addControl(new GOverviewMapControl());
      }
        

      // Restrict min and max zoom
      var min_zoom = 8;
      var max_zoom = 19;
      G_PHYSICAL_MAP.getMinimumResolution = function () { return min_zoom; };
      G_NORMAL_MAP.getMinimumResolution = function () { return min_zoom; };
      G_SATELLITE_MAP.getMinimumResolution = function () { return min_zoom; };
      G_HYBRID_MAP.getMinimumResolution = function () { return min_zoom; };
      G_PHYSICAL_MAP.getMaximumResolution = function () { return max_zoom; };
      G_NORMAL_MAP.getMaximumResolution = function () { return max_zoom; };
      G_SATELLITE_MAP.getMaximumResolution = function () { return max_zoom; };
      G_HYBRID_MAP.getMaximumResolution = function () { return max_zoom; };

      if (print_mode) {
        // Print-specific POIs
        window.updatePrintPois();
        GEvent.addListener(map, 'moveend', window.updatePrintPois);
      } else {
        var keyMenuContents =
        "<div id=\"poi_bar\">" +
        "  <div id=\"poi_bar_title\">Click icon here to remove from map</div>" +
        "	<div id='legend'>"	+
        "  <div id=\"pois_keys\"></div>"                +
        "	 <div style='text-align:center;margin-top:5px;'>Route Types</div>"	+
        "	 <div id=\"path_tile_types\"></div>"	+
        "	</div>"	+
        "  <div id=\"pois_keys_message\">"              +
        "  <span>Zoom in on the map to see more points<span>"                 +
        "  </div>"                                      +
        "</div>";
        map.addControl(new MenuControl("Map Legend", {menuContents: keyMenuContents, width:124}));
        var poi_bar = document.getElementById('poi_bar');
        var suppressWheel = function (event) { 
          if (!event) {
            event = window.event;
          }
          if (event.stopPropagation) {
            event.stopPropagation();
          }
          event.returnValue = false;
          return false; 
        };

        poi_bar.onmousewheel = suppressWheel;
        if(poi_bar.addEventListener) {
          poi_bar.addEventListener('DOMMouseScroll', suppressWheel, false);
        }
        updatePoiIconKeys(ALL_POI_TYPES);  // Update keys as needed
				addPathTypeControls(PATH_TYPES);
        weatherControl = new MenuControl("Weather", {menuContents: "<div id=\"weatherContainer\"></div>"});
        weatherControl.getDefaultPosition = function(){
          return new GControlPosition(G_ANCHOR_TOP_RIGHT, new GSize(235+25, 7));
        };
        updateWeather();  //Update weather container
        map.addControl(weatherControl);

        $('#councils').change(function() {
          var city_name = $(this).val();
          if (city_name){
            showWeatherFor(city_name);
            zoomToCity(city_name);
            window.select_tab("journey");
            updateJourneys(city_name);
          }
        });
        GEvent.addListener(map, 'moveend', window.updatePois);

        add_right_click_menu();

      }
    }
    //Blank out the first time it's focused
    restore_default_text($("#dir_from_address"), true);
    restore_default_text($("#dir_to_address"), true);
    $("#dir_from_address").focus(function(){
      remove_default_text(this);
    });
    $("#dir_to_address").focus(function(){
      remove_default_text(this);
    });

    //Switch button
    $("a#dir_switch").click(function(){
      swap_address();
    });

    // Set mode
    if (print_mode!=true) {
      window.setting_type = JOURNEY;
      select_mode("walking");
    }

    gmap_map_control_styling();
    GEvent.addListener(map, "maptypechanged", gmap_map_control_styling);

    // Enforces it in IE
    var mi = document.getElementById('mode_image');
	  if (mi!=null) {
        mi.src = "/images/walking.png";
        mi.style.marginRight = "10px";
	  }

    ie6_crash_hack(); // Without this line IE6 will crash sometimes. Is it ethical to leave this in?!?

    if (typeof(window.load_on_startup)=="function")
      window.load_on_startup();
};
$(document).ready(startup);

var closeSideBar = function() {
  $(".left_column").css("display", "none");
  $("#bottom_panel").css("left", "0px");
  $(map.getContainer()).css("left", "0px").css("marginRight", "0px");
  $("#bottom_panel")[0].align = "center";  
  
  updateHeightWidth();
};
var openSideBar = function() {
  $(".left_column").css("display", "block");
  $("#bottom_panel").css("left", "370px");
  $(map.getContainer()).css("left", "370px").css("marginRight", "370px");
  
  updateHeightWidth();
};

window.toggleMap = function() { // Assumes page is fully loaded
  var ref = window.toggleMap;
  var centre = map.getCenter();
  if (ref.closed==undefined)
    ref.closed = false;
  if (ref.closed==false) {
    ref.closed = true;
    ref.img.src = "/images/arrows_close.png";
    closeSideBar();
  }
  else {
    ref.closed = false;
    ref.img.src = "/images/arrows_open.png";
    openSideBar();
  }
  

  map.setCenter(centre);

  return false;
};
function ToggleControl(type){
        this.disable_type = type;
};
ToggleControl.prototype = new GControl();
ToggleControl.prototype.initialize = function(map) {
  var container = document.createElement("div");
  var a_link = document.createElement("a");
  a_link.href = "#";
  var img = window.toggleMap.img = document.createElement("img");
  img.src = "/images/arrows_open.png";
  img.onclick = window.toggleMap;
  a_link.appendChild(img);
  container.appendChild(a_link);

  map.getContainer().appendChild(container);
  this.container = container;
  return container;
};
ToggleControl.prototype.redraw = function(){};
ToggleControl.prototype.getDefaultPosition = function(){
        return new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(0, 0));
};

$("input[name=show_large_map]").bind("change click", function() {
  var show_large_map = $("input[name=show_large_map]")[0].checked;
  if(show_large_map) {
    $("#printable_map_row").attr('style', 'page-break-after: always;');
    $(".printable_map").show();
  } else {
    $("#printable_map_row").attr('style', 'page-break-after: auto;');
    $(".printable_map").hide();
  }
});

$("input[name=show_elevation]").bind("change click", function() {
  var show_elevation = $("input[name=show_elevation]")[0].checked;
  if(show_elevation) {
    $(".printable_elevation").show();
  } else {
    $(".printable_elevation").hide();
  }
});                         

$("input[name=show_print_pois]").bind("change click", function () {
  show_print_pois = $("input[name=show_print_pois]")[0].checked;
  if(show_print_pois) {
    $(".printable_points_of_interest").show();
    updatePrintPois();
  } else {
    $(".printable_points_of_interest").hide();
    clearPois();
  }
});

$("input[name=show_calorie_counter]").bind("change click", function() {
  var show_calorie_counter = $("input[name=show_calorie_counter]")[0].checked;
  if(show_calorie_counter) {
    $(".printable_calorie_counter").show();
  } else {
    $(".printable_calorie_counter").hide();
  }
});                                   

window.kd_tree_mousemove = function(point) {
        window.getClosest(point, function(point) {
                if (window.draggable_marker_update==false)
                        return;
                if (point==null) {
                        window.routing_circle_overlay.style.display = "none";
                        return;
                }
                else {
                        window.routing_circle_overlay.style.display = "inline";
                        window.routing_circle_overlay.style.cursor = "pointer";
                }
                var p = map.fromLatLngToDivPixel(point);
                var gs = new GPoint(p.x-PIXEL_DIST, p.y-PIXEL_DIST);
                window.draggable_object.moveTo(gs);
        });
};
window.fixes = function() {
        // Fix address div, width and height are not set correctly
        var divs = $(".start_end");
        for (var i=0;i<divs.length;i++) {
                var     h1 = $(".pin")[i].offsetHeight,
                        h2 = $(".address")[i].offsetHeight;
                var h = Math.max(h1, h2)+5;
                divs[i].style.height = h + "px";
        }
}

PIXEL_DIST = 6;//px
window.getDeltaLat = function() {
        var t = window.getDeltaLat;
        if (t.zoom==map.getZoom())
                return t.delta;
        var c_l = map.getCenter();
        var c_p = map.fromLatLngToDivPixel(c_l);
        var d = Math.pow(2, 0.5)*PIXEL_DIST;
        var d_p = new GPoint(c_p.x+d, c_p.y+d);
        var d_l = map.fromDivPixelToLatLng(d_p);
        t.delta = Math.abs(d_l.lat()-c_l.lat());
        t.delta = Math.pow(2, 0.5)*t.delta;
        t.zoom = map.getZoom();
        return t.delta;
};

polyline_render = new Array();
render_list = new Array();
window.startLine = function(startend, gpolyline) {
        polyline_render = new Array();
        render_list = new Array();
        polyline_render.push(gpolyline);
        render_list.push(startend[0]);
        render_list.push(startend[1]);
        if (gpolyline!=null)
                map.addOverlay(gpolyline);
};
window.replaceLine = function(seq, npoint, nline1, nline2) {
        var b_r = render_list.slice(0, seq);
        var e_r = render_list.slice(seq+1);
        render_list = b_r.concat([npoint]).concat(e_r);

        var b_p = polyline_render.slice(0, Math.max(seq-1, 0));
        var e_p = polyline_render.slice(seq+1);
        if (seq==0) {
                map.removeOverlay(polyline_render[0]);
                polyline_render = b_p.concat([nline2]).concat(e_p);
                map.addOverlay(nline2);
        }
        else if (seq==render_list.length-1) {
                map.removeOverlay(polyline_render[seq-1]);
                polyline_render = b_p.concat([nline1]).concat(e_p);
                map.addOverlay(nline1);
        }
        else {
                for (var i=seq-1;i<=seq;i++)
                        map.removeOverlay(polyline_render[i]);
                polyline_render = b_p.concat([nline1]).concat([nline2]).concat(e_p);
                map.addOverlay(nline1);
                map.addOverlay(nline2);
        }
};
window.insertLine = function(seq, npoint, nline1, nline2) {
        var b_r = render_list.slice(0, seq);
        var e_r = render_list.slice(seq);
        render_list = b_r.concat([npoint]).concat(e_r);

        var b_p = polyline_render.slice(0, seq-1);
        var e_p = polyline_render.slice(seq);
        var cur = polyline_render[seq-1];
        if (cur!=null&&window.setting_type==DIRECTIONS)
                map.removeOverlay(cur);
        polyline_render = b_p.concat([nline1]).concat([nline2]).concat(e_p);
        if (window.setting_type==DIRECTIONS)
          map.addOverlay(nline1);
        if (nline2!=null&&window.setting_type==DIRECTIONS)
          map.addOverlay(nline2);
};
window.removeAllLines = function() {
  var make_update = old_routing.clone();
  make_update.waypoints = make_update.waypoints.filter( function(x) {
    return !x[VIA];
  });

  $.get("/routing/route", make_update.getParams(), function(data){
    window.update_all_social_links();
    routing.has_results = true;
    map.clearOverlays();
    eval(data);
  });
};
window.removeLine = function(seq) {
  var make_update = old_routing.clone();
  make_update.waypoints.splice(seq, 1);
  make_update.setMode( window.setting_mode==WALK ? ZRoute.prototype.WALKING : ZRoute.prototype.CYCLING );
  var p = make_update.getParams();
  p["move"] = false;

  $.get("/routing/route", p, function(data){
    window.update_all_social_links();
    routing.has_results = true;
    map.clearOverlays();
    eval(data);
  });
};
var add_routing_circle_overlay = function() {
        if (typeof(map)=="undefined"||!(map instanceof GMap2))
                return setTimeout(add_routing_circle_overlay, 100); // Allow for misordered updates
        if (jQuery.browser.msie&&parseInt(jQuery.browser.version)==6)
          window.routing_circle_overlay.src = "/images/drag_icon.gif";
        else
          window.routing_circle_overlay.src = "/images/drag_icon.png";
        window.routing_circle_overlay.style.display = "none";
        window.routing_circle_overlay.style.position = "absolute";
        window.routing_circle_overlay.style.zIndex = 1000000000;
        map.getPane(G_MAP_MARKER_PANE).appendChild(window.routing_circle_overlay);
        var d = window.draggable_object = new GDraggableObject(window.routing_circle_overlay);
        GEvent.addListener(d, "dragstart", window.draggable_routes_begin);
        GEvent.addListener(d, "drag", window.draggable_routes_update);
        GEvent.addListener(d, "dragend", window.draggable_routes_end);
        GEvent.addListener(map, "moveend", window.map_move);
        $().ajaxError(window.ajaxError);
};

$("#tab_journey").bind("click keypress", function() {
  window.select_tab("journey");
});

$("#tab_directions").bind("click keypress", function() {
  window.select_tab("directions");
});

window.select_tab = function(tab) {
  var journey_tab = $("#tab_journey");
  var directions_tab = $("#tab_directions");
  var journeys = $('#journeys');
  var directions = $('#directions');

  var routing_copy;
  if(tab == "journey") {
    journey_tab.addClass("tab_left_selected");
    directions_tab.removeClass("tab_right_selected");
    journeys.css('display', 'inline');
    directions.css('display', 'none');

    routing.hide_overlays();
    remove_cycle_lanes();
    bottom_panel_visible(false);
    window.setting_type = JOURNEY;
    routing_copy = routing.clone();
    JourneyLines.display(window.setting_mode);

    window.setting_type = JOURNEY;
  } else {
    journey_tab.removeClass("tab_left_selected");
    directions_tab.addClass("tab_right_selected");
    journeys.css('display', 'none');
    directions.css('display', 'inline');

    routing.show_overlays();
    add_cycle_lanes();
    bottom_panel_visible(true);
    window.setting_type = DIRECTIONS;
    routing_copy = routing.clone();
    JourneyLines.hide();

    if (typeof(todo)=="function")
      todo();
    window.setting_type = DIRECTIONS;
  }
  routing = routing_copy;

};

JourneyLines = {
  update_lines: function(mode) {
    var params = {
      mode: mode,
      limit: 9
    };

    $.get("/journey/update", params, function(data){
      var jupdate = (eval(data));
      jupdate.call();
    });
  },

  update_all: function(mode) {
    //update contents of journey tab also
  },

  /* show polylines for all journeys in with mode */
  display: function(mode, should_clear_routing) {
    if (should_clear_routing == undefined) {
      should_clear_routing = true;
    }
       
    this.hide();
    this._refresh();

    window.update_map_common();
    if(should_clear_routing && routing instanceof ZRoute) {
      routing.clear(true);
    }

    this.current_polylines = new Array(Journeys[mode].length);
    for(var i = 0; i < this.current_polylines.length; ++i) {
      var p = Journeys[mode][i].polyline;
      try {
        p.getVertex( parseInt(p.getVertexCount()/2) ); // Test it
        this.current_polylines[i] = p;
      }
      catch (e) {
        this.current_polylines[i] = null;
        continue;
      }
      map.addOverlay(this.current_polylines[i]);
    }

    var journey_click_callback = function(id) {
      return function() {
        JourneyEditor.select(id, true);
      };
    };

    for (var s=this.current_polylines,j=Journeys[mode],i=j.length,l=G_DEFAULT_ICON;i--;) {
      var m = j[i].polyline, p;
      var icon = new GIcon(l);
      icon.image = "/images/transparent_pins/" + (i+1) + ".png";
      try {
        p = m.getVertex( parseInt(m.getVertexCount()/2) );
      }
      catch (e) {
        continue;
      }
      var r = new GMarker(p, {icon:icon});
      map.addOverlay(r);
      GEvent.addListener(r, "click", journey_click_callback(i));
      GEvent.addListener(r, "mouseover", this.highlight.bind(this, 'over', i));
      GEvent.addListener(r, "mouseout",  this.highlight.bind(this, 'out', i));
      s.push(r);
    }
  },

  /* remove all currently displayed journey polylines */
  hide: function() {
    this._clear(this.current_polylines);
    this.current_polylines = [];
  },

  /* remove each of a list of polylines from the map */
  _clear: function(polylines) {
    if(polylines) {
      for(var i = 0; i < polylines.length; ++i)
        try {
          map.removeOverlay(polylines[i]);
        }
        catch (e) {
          // Don't care
        }
    }
  },

  /* create polylines from polyline_params */
  _decode: function(journeys) {
    var len = journeys.length;
    for(var i = 0; i < len; ++i) {
      journeys[i].polyline = new GPolyline.fromEncoded(journeys[i].polyline_params);
    }
  },

  /* decode polylines if necessary */
  _refresh: function() {
    if(Journeys.updated) {
      this._decode(Journeys.walking);
      this._decode(Journeys.cycling);
      Journeys.updated = false;
    }
  },

  /* Highlight the currently selected journey */
  highlight: function(action, index) {
    var current = this.current_polylines[index];

    // Clone it
    var current_clone = new Object();
    var count = 0;
    for (var each in current) {
      current_clone[each] = current[each];
      count += 1;
    }

    // Adjust the colour
    var new_colour;
    if (action=="out")
      new_colour = "#c0c";
    else if (action=="over")
      new_colour = "#0f0";
    current_clone.color = new_colour;

    // Put it on the map and update list
    if (count!=0) { // Unless dummy object
      try {
        map.addOverlay(current_clone);
        this.current_polylines[index] = current_clone;
      }
      catch (e) {
        // If you can't add it, doesn't matter
        this.current_polylines.splice(index, 1);
      }
      try {
        map.removeOverlay(current);
      }
      catch (e) {
        // You can't remove it if it isn't there...
      }
    }
  }
};

JourneyEditor = {
  select: function(id, force) {
    if (force===true)
      window.setting_type = DIRECTIONS;
    if(routing instanceof ZRoute)
      routing.clear(true); // Clear old stuff out
    var mode = window.setting_mode;
    var journey = Journeys[mode][id];
    get_ajax_route(this._getParams(mode, id));
    return false;
  },

  _getParams: function(mode, id) {
    var journey = Journeys[mode][id];
    var params = {};

    params['journey'] = journey.id;

    return params;
  }
};

$("#elevation_tab").click(function() {
  select_bottom_tab("elevation");
});
$("#calorie_tab").click(function() {
  select_bottom_tab("calorie");
});
$("#health_tab").click(function() {
  select_bottom_tab("health");
});
$("#vehicle_tab").click(function() {
  select_bottom_tab("vehicle");
});
$("#carbon_tab").click(function() {
  select_bottom_tab("carbon");
});

var select_bottom_tab = function(tab) {
  var tab_classes = {
    elevation: {
      tab: $("#elevation_tab"),
      content: $("#elevation_graph_container"),
      selected: "tab_left_selected"
    },
    calorie: {
      tab: $("#calorie_tab"),
      selected: "tab_right_selected",
      content: $("#calorie_counter_container")
    },
    health: {
      tab: $("#health_tab"),
      selected: "tab_right_selected",
      content: $("#health_savings_container")
    },
    vehicle: {
      tab: $("#vehicle_tab"),
      selected: "tab_right_selected",
      content: $("#vehicle_savings_container")
    },
    carbon: {
      tab: $("#carbon_tab"),
      selected: "tab_right_selected",
      content: $("#carbon_emissions_container")
    }
  };

  $.each(tab_classes, function(name, info) {
    if (tab == name) {
      info.tab.addClass(info.selected);
      info.content.show();
    } else {
      info.tab.removeClass(info.selected);
      info.content.hide();
    }
  });
  
  if (tab == "elevation") {
    if (window.update_elevation) {
      window.update_elevation();
    }    
  }
  
  updateHeightWidth();
};

var bottom_panel_visible = function(vis) {
  if(vis) {
    $("#bottom_panel_inner").show();
  } else {
    $("#bottom_panel_inner").hide();
  }

  updateHeightWidth(true);
};

/* Collection of destinations */
var destination_pool = {
  /* Get a span from the pool */
  get : function() {
    if (this.pool.length==0)
      this._create();
    var span = this.pool.pop();
    span.style.display = "block";
    return span;
  },

  /* Return a span to the pool */
  send_back : function(elem) {
    var complete = elem.getElementsByTagName("a").length > 0; // If created by this factory, or close enough
    if (complete) {
      elem.style.display = "none";
      this.pool.push( elem );
    }
  },

  /* Style a given span */
  style : function(elem, i, total) {
    var letter = String.fromCharCode(97+i);
    var j = i==1 ? "" : "_" + i;
    var label = i==0 ? "From" : "To";
    
    var label_tag = elem.getElementsByTagName("label")[0];
    label_tag.innerHTML = label;

    var img_tag = elem.getElementsByTagName("img")[0];
    img_tag.src = "images/green_letters/grey_" + letter + ".png";

    var input_tag = elem.getElementsByTagName("input")[0];
    input_tag.tabindex = i+1;
    input_tag.id = i==0 ? "dir_from_address" : "dir_to_address" + j;
    input_tag.name = "a" + (i==0 ? "" : i);

    var a_tag = elem.getElementsByTagName("a")[0];
    a_tag.onclick = function() {
      deleteDestination(i);
      return false;
    };
    a_tag.style.cursor = "pointer";

    elem.position_id = i; // for the awesome bar

    // Hide it is there are too few
    a_tag.style.display = total==2 ? "none" : "inline";

    if (total==2) {
      var list = elem.getElementsByTagName("*");
      elem.disable_drag = true;
    }
    else
      elem.disable_drag = false;
  },

  _create : function() {
    var new_html = 
      "<label>To</label>" +
      "<img width=\"20\" height=\"20\"/>" +
      "<input class=\"ac_input\" autocomplete=\"off\" type=\"text\"/>" +
      "<a href=\"#\" title=\"remove\" class=\"cross_white\"></a>";
    var new_css = "position: relative; display: block";
    var span = document.createElement("span");
    span.innerHTML = new_html;
    span.style.cssText = new_css;

    var input_tag = span.getElementsByTagName("input")[0];
    var idFunction = function() {
      return span.position_id;
    };
    addAwesome(input_tag, idFunction);
    this.pool.push(span);
  },

  pool : new Array()
};

  
var destinationCount = 2;
var addDestination = function() {
  if (destinationCount>=MAX_VIA-1)
    return;
  if (destinationCount>=MAX_VIA-2)
    $("#add_destination").hide();
  destinationCount += 1;
  routing.waypoints[position2Index(destinationCount - 1)] = [null, "", false];
  window.restoreDestination();
};

var updateDragCallback = function(previous, current) { // Switch the fields then redraw
  if (previous==current)
    return;
  // Switch the names
  var get_field = function(no) {
    if (no==0)
      return $("#dir_from_address");
    j = (no==1) ? "" : "_" + no;
    return $("#dir_to_address" + j);
  };
  var old_name = get_field(previous).val();
  if (previous<current)
    for (var i=previous;i<current;i++)
      get_field(i).val( get_field(i+1).val() );
  else // previous>current
    for (var i=previous-1;i>=current;i--)
      get_field(i+1).val( get_field(i).val() );
  get_field(current).val( old_name );

  // Switch the cached geocodes
  var rw = routing.waypoints;
  var old_value = rw[previous];
  if (previous<current)
    for (var i=previous;i<current;i++)
      rw[i] = rw[i+1];
  else // previous>current
    for (var i=previous-1;i>=current;i--)
      rw[i+1] = rw[i];
  rw[current] = old_value;

  window.restoreDestination(); // Redraw
};
var restoreDestination = function(id) {
  var p = $("#togroup")[0];
  if (p==undefined)
    return setTimeout(window.restoreDestination, 100);

  // Remove link on max
  if (destinationCount>=MAX_VIA-2)
    $("#add_destination").hide();

  // Remove grey colour
  $('[name=a]').css("color", "#000");

  var cache = new Array();
  for (var i=1,j;i<=destinationCount;i++) {
    j = (i==1) ? "" : "_" + i;
    cache[i] = $("#dir_to_address" + j).val() || "";
  }
  cache[0] = $("#dir_from_address").val();
  if (id!=undefined)
    cache.splice(id, 1);

  var old_list = p.getElementsByTagName("span");
  for (var k=old_list.length;k--;) {
    var m = old_list[k];
    p.removeChild( m );
    destination_pool.send_back( m );
  }

  for (var i=0,k=0;i<destinationCount;i++,k++) {
    var j = i==1 ? "" : "_" + i;
    var span = destination_pool.get();
    destination_pool.style(span, i, destinationCount);
    p.appendChild(span);

    var elem_id = i==0 ? "dir_from_address" : "dir_to_address" + j;
    var elem = document.getElementById(elem_id);
    while (!routing.waypoints[k] || routing.waypoints[k][VIA]==true) {      
      k += 1;
    }
    elem.value = !(routing.waypoints[k]) ? cache[i] : routing.waypoints[k][ADDRESS];
  }
  
  if (destinationCount==2) {
    $("#dir_switch").show();
    $("#directions_form a.cross_white").hide();
  } else {
    $("#dir_switch").hide();
    if ($("#dir_from_address ~ a.cross_white").length==0)
      $("#dir_from_address").after("<a href=\"#\" onclick=\"deleteDestination(0); return false;\" title=\"remove\" class=\"cross_white\"></a>");
    else
      $("#directions_form a.cross_white").show();

    if (! ('togroup' in dragListIndex) ) {
      var drag_manager = new fv_dragList( 'togroup' );
      drag_manager.setup("vert", "span", window.updateDragCallback);
      dragListIndex = new Array(); // force-refresh
      addDragList( drag_manager );
    }
    else {
      var drag_manager = new fv_dragList( 'togroup' );
      drag_manager.setup("vert", "span", window.updateDragCallback);
    }

    var a_tags = p.getElementsByTagName("a");
    for (var i=a_tags.length;i--;)
      a_tags[i].style.cursor = "pointer";
  }

  // Right click menu
  var items = $(".rightclickitem");
  for (var i=items.length;i--;) {
    var match = items[i].id.match(/address(.)(.?)/), no = match[1], type = match[2];
    items[i].style.display = (no>=destinationCount||type==(destinationCount<=2 ? "b" : "a")) ? "none" : "block";
  }

  // IE6 fix - The close markers have red bottoms
  if (jQuery.browser.msie&&jQuery.browser.version=="6.0") {
    var cw = $(".cross_white");
    for (var i=cw.length;i--;)
      cw[i].style.height = "5px";
  }
};
var dragListIndex = new Array(); // Global array for drag manager

var addAwesome = function(node, idFunction) {
  $(node).each(function(idx, elem) {
    af_initialise(elem, selectSearchItem(idFunction), {
      search_type: 'location',
      pagination: false,
      extraParams: {
        region: function() {
          return WELLINGTON_PXID;
        }
      }
    });
  });
  
  var changeFunc = function(){
    var pos = position2Index(idFunction());
    if (routing.waypoints[pos] && routing.waypoints[pos][ADDRESS] == $(this).val())
      return;
    routing.substituteWayPointN(pos, null, $(this).val(), false);
  };
  $(node).change(changeFunc);
};
 
window.deleteDestination = function(i) {
  routing.waypoints.splice(i, 1);
  destinationCount -= 1;
  $("#add_destination").show();
  window.restoreDestination(i);
};

var SPEED = {"walking":{"slow":3,
                                          "average":5,
                                          "fast":6.5},
                        "cycling":{"slow":10,
                                          "average":20,
                                          "fast":30}};
window.journey_times = function() {
  var fields = $(".journey_time");
  var pace = readCookie('pacing') || 'average';
  for (var i=0;i<fields.length;i++) {
    var div = fields[i];
    if (div.journey_pace==pace)
      continue;
    if (div.journey_pace==undefined) {
      div.distance_metres = parseFloat(div.innerHTML);
      div.journey_type = div.innerHTML.replace(/[0-9\.]+/, "");
    }
    var time = div.distance_metres/(1000*SPEED[div.journey_type][pace])
    div.journey_pace = pace;
    div.innerHTML = craft_time(time);
  }
}
window.craft_time = function(hours) {
  var result = new Array();
  if (hours>=24) {
    var d = Math.floor(hours/24);
    hours -= 24*d;
    result.push(d + " day" + ((d==1) ? "" : "s"));
  }
  if (hours>=1) {
    var h = Math.floor(hours);
    hours -= h;
    result.push(h + " hour" + ((h==1) ? "" : "s"));
  }
  if (hours*60>=1) {
    var m = Math.floor(hours*60);
    result.push(m + " minute" + ((m==1) ? "" : "s"));
  }
  return result.join(" ");
}

window.ie6_crash_hack = function() {
  var unload = [window.onunload, document.body.onunload];
  document.body.onunload = function(){};
  window.onunload = function() {
    try {
      map.clearOverlays();
    }
    catch (e) {
      // Don't care if it fails...
    }
    for (var i=0;i<unload.length;i++)
      if (typeof(unload[i])=="function")
        try {
          unload[i]();
        }
        catch (e) {
        }
    GUnload();
  }
};

window.cycle_lane_overlay = undefined;
window.add_cycle_lanes = function() {
  try { // Check this is still valid
    window.cycle_lane_overlay.show();
  }
  catch (ex) {
    window.cycle_lane_overlay = undefined;
  }
  if (window.cycle_lane_overlay!=undefined)
    return false;
  var urlTemplate = 'http://client1.projectx.co.nz/cgi-bin/mapserv?';
  urlTemplate += 'map=/var/www/html/walk_cycle/paths.map&';
	urlTemplate += 'layers=all&';
  urlTemplate += 'mode=tile&';
  urlTemplate += 'tilemode=gmap&';
  urlTemplate += 'tile={X}+{Y}+{Z}';
  window.cycle_lane_overlay = new GTileLayerOverlay(
    new GTileLayer(null,null,null, {
      tileUrlTemplate:urlTemplate,
      isPng:true,
      opacity: 1.0
    })
  );
  map.addOverlay(window.cycle_lane_overlay);
  return true;
}
window.remove_cycle_lanes = function() {
  if (window.cycle_lane_overlay==undefined)
    return false;
  map.removeOverlay(window.cycle_lane_overlay);
};

window.openFaqPopup = function(tag, name) {
  var newWindow = window.open("/routing/help#faq_" + tag, name, 'height=450, width=600');
  if (window.focus) {
    newWindow.focus();
  }
  return false;
};

// The following lines could be put in the startup method

window.routing_circle_overlay = document.createElement("img");
add_routing_circle_overlay();

// Undisable text boxes
$("#dir_from_address").removeAttr("disabled");
$("#dir_to_address").removeAttr("disabled");

// Calculate Journey times
window.journey_times();

  
// Directions submit
$("#directions_form").submit(function(e) {
  e.preventDefault();
  submit_directions_form(false);
  return false;
});
