var mapImage = null;
var searchResultsPager = null;
var srp_vert = null;
//var mapTool = null;
var layerTree = null;

var ol_mapObj;

//DcoMap.blankImage = 'images/blank.png';
DcoMap.leftOffset = 300;
//DcoMap.topOffset = 127;
DcoMap.ohioMapExtent = '-9442137 4636542,-8963299 5157613.5';
DcoMap.usaMapExtent = '-13985234 2719924,-7352828 6440332.5';


// impl in highlighting.js
function Highlighting() {};
Highlighting.elemId = 'highlighting_elem';
Highlighting.getHLElem = function() { }; // stub

function initializeMap()
{
  var se = $('#address, #owner, #parcel_id');
  if (se.val() == "")
  {
    se.focus();
  }
  /*
  var aoo = document.getElementById('address_or_owner');
  if (aoo)
  {
    set_addr_or_owner(aoo);
  }
  */
  $('#tabs_ul').css('margin-left', DcoMap.leftOffset + 'px');

  if (!DcoMap.defaultMapExtent)
  {
    DcoMap.defaultMapExtent = DcoMap.usaMapExtent;
  }
  layerTree = LayerTree.defaultLayerTree;

  var is_map_tab = tab_active_is_map();
  if (is_map_tab)
  {
    initMapImage();
    initLeftPanel();
  }

  var th_jq = $('#tabs_header');
  var top_off = th_jq.offset().top + th_jq.outerHeight();
  /*
  var jq_sr = $('#search_results');
  jq_sr.css('top', top_off + 'px');
  jq_sr.css('left', '0px');
  jq_sr.css('width', viewportWidth() + 'px');
  jq_sr.css('height', viewportHeight() - top_off + 'px');
  */

  initSearchConstraints();
  if (is_map_tab)
  {
    populateLayers();
    initializeMapTools();
  }
  else
  {
    var is_advanced = false;
    var search_tabs = $('.search_tabs_tab');
    for (var i=0; i<search_tabs.length; ++i)
    {
      var st = $(search_tabs[i]);
      if ((st.text() !== 'Basic Search') && (st.css('background-color') === 'rgb(230, 243, 255)'))
      {
	is_advanced = true;
	// switch to advanced search
	var e = ({ target: search_tabs[i] });
        search_tab_switch(e);
      }
    }
    if (!is_advanced)
    {
      $('#searchForm .search_row_advanced :input[type="text"]').attr('value',''); // clear advanced search
    }
    search_tabs.click(search_tab_switch);
  }


}

$(document).ready(initializeMap);
//$(window).load(recalcExternalLinks);
$(window).resize(resizeMapElem);

/*
function hash_history(new_h_param)
{
  var nh_arr = new_h_param.split('&');
  var nh_obj = ({});
  for (var i=0; i<nh_arr.length; ++i)
  {
    var nh_param = nh_arr[i];
    if (nh_param.length > 0)
    {
      var nh_eqpos = nh_param.indexOf('=');
  
      var nh_p_key = nh_param;
      var nh_p_val = null;
      if (nh_eqpos !== -1)
      {
        nh_p_key = nh_param.substr(0, nh_eqpos);
        nh_p_val = nh_param.substr(nh_eqpos + 1);
      }
      nh_obj[nh_p_key] = nh_p_val;
    }
  }
  
  if (typeof(nh_obj['tab']) === "undefined" || nh_obj['tab'] === 'search')
  {
    if (!(nh_obj['region']))
    {
      //search_clear();
    }
    else
    {
      if (typeof(nh_obj['sr_page']) !== "undefined")
      {
        searchResultsPager.pageTo(nh_obj['sr_page']);
      }
      else
      {
        var inp = $('#searchForm :input');
        var inp_obj = ({});
        for (var i=0; i<inp.length; ++i)
        {
          var e = $(inp[i]);
          var e_name = e.attr('name');
          if (typeof(nh_obj[e_name]) !== "undefined")
          {
            e.val(nh_obj[e_name]);
          }
        }
        searchResultsPager.searchByMainForm();
      }
    }
    if (tab_active_is_map())
    {
      tab_switch('tab_search');
    }
  }
  else if (nh_obj['tab'] === 'map' && tab_active_is_search())
  {
    tab_switch('tab_map');
  }
}
*/

function resizeMapElem()
{
  var jq_ol_mapElem = $('#map');
  if (jq_ol_mapElem.length > 0)
  {
    var ol_mapElem = jq_ol_mapElem[0];

    var map_area_w = viewportWidth() - DcoMap.leftOffset;
    var ads = $('.ads_mappage');
    if (ads.length > 0)
    {
      map_area_w -= ads.outerWidth();
    }
    ol_mapElem.style.width = Math.max(map_area_w, 0) + 'px';

    var th_jq = $('#tabs_header');
    var top_off = th_jq.offset().top + th_jq.outerHeight();
    var map_area_h = viewportHeight() - top_off;
    ol_mapElem.style.height = map_area_h + 'px';
    ol_mapElem.style.position = 'absolute';
    ol_mapElem.style.top = top_off + 'px';
    ol_mapElem.style.left = DcoMap.leftOffset + 'px';
    if (ol_mapObj)
    {
      ol_mapObj.updateSize();
    }

    $('#leftPanel').css('height', (viewportHeight() - top_off) + 'px');
  }
}

function ll_spn_to_bounds(ll, spn)
{
  var ll_spn = ll.split(',');
  var ll_pt = new OpenLayers.Geometry.Point(ll_spn[1], ll_spn[0]);
  OpenLayers.Layer.SphericalMercator.projectForward(ll_pt);
  
  var spn_spl = spn.split(',');
  var spn_pt = new OpenLayers.Geometry.Point(ll_spn[1] - (spn_spl[0] / 2.0), ll_spn[0] - (spn_spl[1] / 2.0));
  OpenLayers.Layer.SphericalMercator.projectForward(spn_pt);
  
  var xdiff = (ll_pt.x - spn_pt.x) / 2.0;
  var ydiff = (ll_pt.y - spn_pt.y) / 2.0;
  
  var mb = new OpenLayers.Bounds(ll_pt.x - xdiff, ll_pt.y - ydiff, ll_pt.x + xdiff, ll_pt.y + ydiff);
  return mb;
}

function map_bounds_to_ll_spn()
{
  var mr = MapTool.getMapExtRect();
  var lonlat = OpenLayers.Layer.SphericalMercator.inverseMercator(mr.getCenterX(), mr.getCenterY());
  var lon = lonlat.lon;
  var lat = lonlat.lat;

  var ll =  lat.toFixed(6) + ',' + lon.toFixed(6);
  var minll = OpenLayers.Layer.SphericalMercator.inverseMercator(mr.minx, mr.miny);
  var spn = ((lon - minll.lon) * 2.0).toFixed(6) + ',' + ((lat - minll.lat) * 2.0).toFixed(6);
  return [ll, spn];
}

// apply changes from GET to layer tree
function mod_layer_tree_by_getparam()
{
  var s = document.location.search;
  if (s[0] === '?')
  {
    s = s.substr(1);
  }
  var p = s.split('&');
  for (var i=0; i<p.length; ++i)
  {
    var pval = unescape(p[i]);
    var pm;
    if (pm = pval.match(/^layer_\[(.*?)\]\[(.*?)\]=(\d+)$/))
    {
      var lname = pm[2].replace(/\+/g, ' ');
      LayerTree.root[pm[1]].getLayerByName(lname).status = parseInt(pm[3]);
    }
  }
}

function set_basemap_by_getparam()
{
  var s = document.location.search;
  if (s[0] === '?')
  {
    s = s.substr(1);
  }
  var p = s.split('&');
  for (var i=0; i<p.length; ++i)
  {
    var pval = unescape(p[i]);
    var pm;
    if (pm = pval.match(/^basemap=(.*)$/)) 
    {
      setBasemap(pm[1]);
    }
  }
}

function initMapImage()
{
  mod_layer_tree_by_getparam();

  var ol_mapElem = document.createElement('div');
  ol_mapElem.id = 'map';
  //ol_mapElem.style.display = 'none';

  MapTool.mapImagePosX = parseInt($('#leftPanel').offset().left);
  var th_jq = $('#tabs_header');
  var top_off = th_jq.offset().top + th_jq.outerHeight();
  MapTool.mapImagePosY = top_off;
  document.body.appendChild(ol_mapElem);

  resizeMapElem();

  // note: don't use maxResolution = "auto".  It defeats caching by relying on size of map <div>
  ol_mapObj = new OpenLayers.Map('map', { maxExtent: new OpenLayers.Bounds(-20000000,-20000000,20000000,20000000), maxResolution: 10000, minResolution: 0.15, numZoomLevels: 16, units: "m", projection: new OpenLayers.Projection("EPSG:900913"), tileSize: new OpenLayers.Size(384, 384) } );

  ol_mapObj.removeControl(ol_mapObj.getControlsByClass('OpenLayers.Control.PanZoom')[0]);

  var tile_url = "http://reportallusa.com/dyn/tile.py";

  delete OpenLayers.Layer.MapServer.prototype.DEFAULT_PARAMS.map_imagetype;

  var hl_tbl_jq = $('.highlight_table');
  if (hl_tbl_jq.length > 0)
  {
    var highlight_table = $(hl_tbl_jq[0]).text();
    // TODO: extract from Parcel_Highlight2.map
    LayerTree.root['Parcel_Highlight2'] = new LayerTree();
    LayerTree.root['Parcel_Highlight2'].mapfile = 'siteroot/highlight/Parcel_Highlight2.map';
    LayerTree.root['Parcel_Highlight2'].status = 1;
    var highlight_table_mbr = JSON.parse($('.highlight_table_mbr').text());
    var srLayer = new Layer('Search Results', null, 1, -1, -1, 2, 6, new Layer.Style(null,'rgb(0,255,0)',null,0,null), null, null, ['tableoid','cmax','xmax','cmin','xmin','ctid','county_id','parcel_id','addr_number','addr_street_prefix','addr_street_name','addr_street_suffix','addr_street_type','owner','trans_date','sale_price','bldg_sqft','ngh_code','land_use_code','acreage','muni_id','school_dist_id','mkt_val_tot','mkt_val_land','mkt_val_bldg','zip_code','load_table_gid','is_parid_uniq','orig_addr','xattr','story_height','census_tract','census_blkgrp','census_block'], null, highlight_table_mbr, null);
    srLayer.cgi_vars = [ 'highlight_table=' + highlight_table ];
    LayerTree.root['Parcel_Highlight2'].push(srLayer);
  }

  var basebranches = LayerTree.getBaseBranches();
  var non_basebranches = LayerTree.getNonBaseBranches();

  for (var i=0; i<basebranches.length; ++i)
  {
    var branch = basebranches[i];
    var bm = new OpenLayers.Layer.MapServer( branch.getMapName(), tile_url, { map: branch.mapfile }, {isBaseLayer: true, sphericalMercator: true, transitionEffect: 'resize'} );
    ol_mapObj.addLayer(bm);
    if (!branch.metadata || !branch.metadata.defer_default_baselayer)
    {
      ol_mapObj.setBaseLayer(bm);
    }
  }

  set_basemap_by_getparam();

  for (var j=0; j<non_basebranches.length; ++j)
  {
    var branch = non_basebranches[j];
    var llLength = branch.getLength();
    var vis_layer_names = [];
    var minmaxscale = Number.POSITIVE_INFINITY;
    var maxminscale = Number.NEGATIVE_INFINITY;
    for (var i=0; i<llLength; ++i)
    {
      var layer = branch.getLayerById(i);
  
      var eff_name = (layer.group != null) ? layer.group : layer.name;
      var l_vis = layer.isStatusVis();
      if (l_vis)
      {
        vis_layer_names.push(eff_name);
      }

      if (layer.minscale == -1) maxminscale = NaN;
      maxminscale = Math.max(maxminscale, layer.minscale);
      if (layer.maxscale == -1) minmaxscale = NaN;
      minmaxscale = Math.min(minmaxscale, layer.maxscale);
  
      if (ol_mapObj.getLayersByName(eff_name).length == 0 && (!branch.metadata.single_tile || layer.isBasemap()))
      {
        var olp = new Object();
        olp.map = branch.mapfile;
        //olp.map_imagetype = branch.getImagetype();
    
        var olo = { isBaseLayer: false, sphericalMercator: true, transitionEffect: 'resize', visibility: l_vis };
        if (layer.maxscale != -1) olo.minScale = layer.maxscale;
        if (layer.minscale != -1) olo.maxScale = layer.minscale;
	if (layer.isTypeAnnotation())
	{
          olo.singleTile = true;
	}
	if (layer.extent != null)
	{
	  var e = layer.extent;
          olo.maxExtent = new OpenLayers.Bounds(e[0], e[1], e[2], e[3]);
	}
	if (layer.isBasemap())
	{
          olo.isBaseLayer = true;
	}
    
	var layer_url = tile_url + '?layer=' + eff_name;
	if (typeof(layer.cgi_vars) !== 'undefined')
	{
          if (layer.cgi_vars.length > 0)
	  {
            layer_url += '&' + layer.cgi_vars.join('&');
	  }
	}
        var ol = new OpenLayers.Layer.MapServer(eff_name, layer_url, olp, olo );
    
        ol_mapObj.addLayer(ol);
      }
    }

    if (branch.metadata.single_tile)
    {
      var layers_str = '';
      if (vis_layer_names.length > 0)
      {
        layers_str = 'layer=' + vis_layer_names.join('&layer=');
      }
      // TODO: sphericalMercator = true?
      var olo = { isBaseLayer: false, singleTile: true, transitionEffect: 'resize', visibility: (vis_layer_names.length > 0) };
      if (minmaxscale != Number.POSITIVE_INFINITY && !isNaN(minmaxscale))
      {
        olo.minScale = minmaxscale;
      }
      if (maxminscale != Number.NEGATIVE_INFINITY && !isNaN(maxminscale))
      {
        olo.maxScale = maxminscale;
      }
      var mn = branch.getMapName();

      var ol = new OpenLayers.Layer.MapServer(mn, tile_url + '?no_tilecache=1&' + layers_str, { map: branch.mapfile }, olo );

      ol_mapObj.addLayer(ol);
    }
  }

  /*
  var hl_tbl_jq = $('.highlight_table');
  if (hl_tbl_jq.length > 0)
  {
    var highlight_table = $(hl_tbl_jq[0]).text();
    var hlp = new Object();
    hlp.map = 'siteroot/highlight/Parcel_Highlight2.map';
    var hlo = { isBaseLayer: false, sphericalMercator: true, transitionEffect: 'resize', visibility: true };
    var hl = new OpenLayers.Layer.MapServer('Search Results', tile_url + '?layer=Parcels&highlight_table=' + highlight_table, hlp, hlo);
    ol_mapObj.addLayer(hl);
  }
  */
  
  var d = new Rect2D(DcoMap.defaultMapExtent.split(/[ ,]/));
  var mb = new OpenLayers.Bounds(d.minx,d.miny,d.maxx,d.maxy);

  // aggregate extent of search result geometries
  var sel_row = $('.srContainer table')
  var new_b = null;
  for (var i=0; i<sel_row.length; ++i)
  {
    var wkt = $(sel_row[i]).find('.geom_as_wkt').text();
    var geom = OpenLayers.Geometry.fromWKT(wkt);
    if (new_b === null)
    {
      new_b = geom.getBounds();
    }
    else
    {
      new_b.extend(geom.getBounds());
    }
  }
  if (new_b !== null)
  {
    mb = new_b;
  }

  {
    var qs = document.location.search;
    if (qs[0] == '?')
    {
      qs = qs.substr(1);
    }
    var qs_spl = qs.split('&');
    var params = new Object();
    for (var i=0; i<qs_spl.length; ++i)
    {
      var qv = qs_spl[i].split('=');
      if (qv.length == 2)
      {
	  params[qv[0]] = qv[1];
      }
    }

    var ll = params['ll'];
    if (typeof(ll) !== 'undefined')
    {
      ll = unescape(ll);
    }
    var spn = params['spn'];
    if (typeof(spn) !== 'undefined')
    {
      spn = unescape(spn);
    }
    if (ll && spn)
    {
      mb = ll_spn_to_bounds(ll, spn);
    }
  }

  if (Highlighting.hl_layer.features.length > 0)
  {
    ol_mapObj.addLayer(Highlighting.hl_layer);
  }

  ol_mapObj.zoomToExtent(mb);
   
  //ol_mapObj.addControl(new OpenLayers.Control.LayerSwitcher());
  ol_mapObj.addControl(new OpenLayers.Control.ScaleLine());
  ol_mapObj.addControl(new OpenLayers.Control.PanZoomBar());
  ol_mapObj.addControl(new OpenLayers.Control.ZoomBox());
  var ml = new OpenLayers.Control.Measure(OpenLayers.Handler.Path, {displaySystem: 'english', geodesic: true} );
  ml.events.register("measure", null, 
function(me) { 
  var c = me.geometry.getCentroid();

  var m_fl = parseFloat(me.measure);
  var p_txt = "Total line distance:<br/>";
  if (me.units === "m")
  {
    p_txt += (m_fl * 3.2808399).toFixed(3) + " ft<br/>";
  }
  else if (me.units === "km")
  {
    p_txt += (m_fl * 0.621371192).toFixed(3) + " mi";
  }
  p_txt += m_fl.toFixed(3) + " " + me.units + "<br/>";

  var p = new OpenLayers.Popup.AnchoredBubble("mline_popup", new OpenLayers.LonLat(c.x, c.y), new OpenLayers.Size(200, 150), p_txt, { 'size': new OpenLayers.Size(0, 0), 'offset': new OpenLayers.Pixel(0, 0) }, true);
  ol_mapObj.addPopup(p);
});
  //m.events.register("measurepartial", null, function(obj) { alert("measurepartial " + obj + ", " + obj2); });

  ol_mapObj.addControl(ml);

  var mp = new OpenLayers.Control.Measure(OpenLayers.Handler.Polygon, {displaySystem: 'english', geodesic: true} );
  mp.events.register("measure", null,
function(mp)
{
  var c = mp.geometry.getCentroid();

  var m_fl = parseFloat(mp.measure);
  var p_txt = "Total area:<br/>";
  if (mp.units === "m")
  {
    p_txt += (m_fl * 10.7639104).toFixed(3) + " sq ft<br/>";
  }
  else if (mp.units === "km")
  {
    p_txt += (m_fl * 0.386102159).toFixed(3) + " sq mi<br/>";
  }
  p_txt += parseFloat(mp.measure).toFixed(3) + " sq " + mp.units + "<br/>";

  var p = new OpenLayers.Popup.AnchoredBubble("marea_popup", new OpenLayers.LonLat(c.x, c.y), new OpenLayers.Size(200, 150), p_txt, { 'size': new OpenLayers.Size(0, 0), 'offset': new OpenLayers.Pixel(0,0) }, true);
  ol_mapObj.addPopup(p);
});
  ol_mapObj.addControl(mp);

  /*
  var idc = new OpenLayers.Control({
    type: OpenLayers.Control.TYPE_BUTTON,
    eventListeners: toolListeners,
    displayClass = "green"
  }
  .Identify();
  var tpanel = new OpenLayers.Control.Panel({div: document.getElementById("zoom_panel")});
  tpanel.addControls([idc]);
  */

  ol_mapObj.addControl(new Dco.Identify());

  ol_mapObj.events.register("move", null, recalcExternalLinks);
  //ol_mapObj.events.register("move", null, bookmarkMapArea);

}

function set_addr_or_owner(ct)
{
  var ct = $('#address_or_owner').get(0);
  var addr_owner = ct.options[ct.selectedIndex].value;
  var elem = $('#address, #owner, #parcel_id');
  elem.attr('id',addr_owner);
  elem.attr('name',addr_owner);
  elem.attr('value','');
  $('#' + addr_owner).focus();
  $('.search_hint_address, .search_hint_owner').css('display','none');
  $('.search_hint_' + addr_owner).css('display','');
}

function tab_get_active()
{
  var tc = $('.tab_current');
  var ta = null;
  if (tc.length > 0)
  {
    ta = tc.attr('id').match('^tab_(.*)$')[1];
  }
  return ta;
}

function tab_active_is_map()
{
  return (tab_get_active() == 'map');
}

function tab_active_is_search()
{
  return (tab_get_active() == 'search');
}

/*
function tab_switch(tab_name)
{
  if (tab_name == 'tab_search')
  {
    //search_clear();
  }
  $('#tabs_ul li').removeClass('tab_current');
  $('#'+tab_name).addClass('tab_current');
  var is_map = (tab_name == 'tab_map');

//  var ha = document.location.hash.substr(1).split('&');
//  var tm_ex = false;
//  for (var i=0; i<ha.length; ++i)
//  {
//    if (ha[i] === 'tab=map')
//    {
//      tm_ex = true;
//      break;
//    }
//  }
//  if (is_map)
//  {
//    // add tab=map param to hash
//    if (!tm_ex)
//    {
//      if (document.location.hash.length > 0)
//      {
//        document.location.hash += '&';
//      }
//      document.location.hash += 'tab=map';
//    }
//  }
//  else
//  {
//    // remove tab=map param from hash
//    if (tm_ex)
//    {
//      var nh = '';
//      for (var i=0; i<ha.length; ++i)
//      {
//        if (ha[i] !== 'tab=map')
//	{
//	  if (nh.length === 0)
//	  {
//            nh.length += '#';
//	  }
//	  if (nh.length > 1 && ha[i] !== '')
//	  {
//            nh += '&'; 
//	  }
//	  nh += ha[i];
//	}
//      }
//      if (nh.length > 0)
//      {
//        document.location.hash = nh;
//      } else {
//        document.location.href = document.location.href.substr(0, document.location.href.indexOf('#') - 1);
//      }
//    }
//  }
  if (is_map && $('#map').length == 0)
  {
    initMapImage();
    populateLayers();
  }
  //$('#map, #leftPanel, #mapToolsTable').css('display', is_map ? '' : 'none');
  $('#search_results').css('display', is_map ? 'none' : '');
  $('.other_map_link').css('display', is_map ? 'inline' : 'none');
}
*/

function initLeftPanel()
{
  var lp = document.getElementById('leftPanel');
  if (lp)
  {
    var th_jq = $('#tabs_header');
    var top_off = th_jq.offset().top + th_jq.outerHeight();
    lp.style.height = (viewportHeight() - top_off) + 'px';
  
    if ($.browser.msie)
    {
      for (var i=0; i<lp.childNodes.length; ++i)
      {
	if (typeof(lp.childNodes[i].style) !== 'undefined')
	{
          lp.childNodes[i].style.width = (DcoMap.leftOffset - 17) + 'px';
	}
      }
    }
  }
}

function initSearchConstraints()
{
  var lp = document.getElementById('leftPanel');
  if (lp)
  {
    var lpi = lp.getElementsByTagName('input');
    for (var i=0; i<lpi.length; ++i)
    {
      var inp = lpi[i];
      addEventListenersToElem(inp);
      inp.addEventListener('keyup',search_keyup,false);
    }
  }
}

function get_external_links(mr)
{
  if (mr instanceof OpenLayers.Bounds)
  {
    mr = new Rect2D(mr.left, mr.bottom, mr.right, mr.top);
  }
  else if (mr instanceof Array)
  {
    mr = new Rect2D(mr[0], mr[1], mr[2], mr[3]);
  }
  else if (mr == null) 
  {
    mr = MapTool.getMapExtRect();
  }
  var el = null;
  if (mr != null)
  {
    el = ({});
    var lonlat = OpenLayers.Layer.SphericalMercator.inverseMercator(mr.getCenterX(), mr.getCenterY());
    var lon = lonlat.lon;
    var lat = lonlat.lat;

    var m_elem = $('#map');
    var map_height = null;
    if (m_elem.length > 0)
    {
      map_height = m_elem.height();
    }
    else
    {
      var th_jq = $('#tabs_header');
      var top_off = th_jq.offset().top + th_jq.outerHeight();
      map_height = viewportHeight() - top_off;
    }
    var ground_res = mr.getHeight() / parseFloat(map_height);
    var twoToLevel = (Math.cos(lat * Math.PI / 180.0) * 2.0 * Math.PI * 6378137) / (256 * ground_res);
    var level = Math.round(Math.log(twoToLevel) / Math.LN2);

    el['google_maps'] = 'http://maps.google.com/?ll=' + lat + ',' + lon + '&z=' + Math.min(level - 1, 19);
    el['bing_maps'] = 'http://www.bing.com/maps/default.aspx?cp=' + lat + '~' + lon + '&lvl=' + Math.min(level, 19);
    el['yahoo_maps'] = 'http://maps.yahoo.com/broadband/#mvt=h&lat=' + lat + '&lon=' + lon + '&zoom=' + Math.min(level, 18);
    el['mapquest'] = 'http://atlas.mapquest.com/maps/map.adp?dtype=h&formtype=latlong&latlongtype=decimal&latitude=' + lat + '&longitude=' + lon + '&zoom=' + Math.min(level,12);

    var ll_lonlat = OpenLayers.Layer.SphericalMercator.inverseMercator(mr.minx, mr.miny);
    var ur_lonlat = OpenLayers.Layer.SphericalMercator.inverseMercator(mr.maxx, mr.maxy);
    el['zillow'] = 'http://www.zillow.com/homes/map/#/homes/for_sale/map/' + ur_lonlat.lat + ',' + ur_lonlat.lon + ',' + ll_lonlat.lat + ',' + ll_lonlat.lon + '_rect/' + Math.min(level, 18) + '_zm';
  }
  return el;
}

function recalcExternalLinks(e,mr)
{
  var el = get_external_links(mr);
  for (var link in el)
  {
    document.getElementById(link).href = el[link];
  }
}

function enDisableLayers(e)
{
  var branches = LayerTree.getNonBaseBranches();
  for (var i=0; i<branches.length; ++i)
  {
    var branch = branches[i];
    for (var j=0; j<branch.getLength(); ++j)
    {
      var layer = branch.getLayerById(j);
      var layerNameUnd = layer.name.replace(/ /g,'_');
      var inpElemId = 'l:' + branch.getMapName() + ':' + layerNameUnd;
      var chkbox = document.getElementById(inpElemId);
      if (!layer.isVisibleAtScale())
      {
        chkbox.disabled = 'disabled';
	//$(chkbox).css('background-color', '#dcdcdc').css('border', '1px solid #3532ff').css('color', 'white');

      }
      else
      {
        chkbox.removeAttribute('disabled');
	//$(chkbox).css('background-color', '').css('border', '').css('color');
      }
    }
  }
}

function expandBranch(b)
{
  var bchl = $("#layerTreeTable tr[id^=lRow:" + b + ":]");
  var expand = false;
  if (bchl.length > 0)
  {
    expand = (bchl.css('display') == 'none');
    bchl.css('display', expand ? ($.browser.msie ? 'block' : 'table-row') : 'none');
  }
  var r = $("#rRow\\:" + b);
  r.find('img').attr('src', 'images/tree_node_' + (expand ? 'expanded' : 'collapsed') + '.gif');
}

function setBasemap(bm_name)
{
  var bl = ol_mapObj.getLayersByName(bm_name)[0];
  ol_mapObj.setBaseLayer(bl);
}

function activateControl(con)
{
  var all_ctl = [ 'Dco.Identify', 'OpenLayers.Control.ZoomBox', 'OpenLayers.Control.Measure' ];
  for (var i=0; i<all_ctl.length; ++i)
  {
    var ctl = all_ctl[i];
    var cbc = ol_mapObj.getControlsByClass(ctl);
    for (var j=0; j<cbc.length; ++j)
    {
      var cc = cbc[j];
      if (cc != con)
      {
        cc.deactivate();
      }
    }
  }
  if (con)
  {
    con.activate();
  }
}

function layer_info(e)
{
  var tr = e.currentTarget;
  while (tr && tr.nodeName.toLowerCase() != 'tr')
  {
    tr = tr.parentNode;
  }
  if (tr)
  {
    var ls = $(tr).attr('id').split(':');
    var mapName = ls[1];
    var layerName = ls[2].replace(/_/g, ' ');
    window.open('/layer_info?mapName=' + mapName + '&layerName=' + layerName);
  }
}


function populateLayers()
{
  var layerForm = document.getElementById('layerForm');
  var llTbody = document.createElement('tbody');

  var ie = (navigator.userAgent.indexOf('MSIE') != -1);

  var branches = LayerTree.getBaseBranches();
  branches = branches.concat(LayerTree.getNonBaseBranches());

  for(var j=0; j<branches.length; ++j)
  {
    var branch = branches[j];

    var img_str = "<img src='images/tree_node_" + (!branch.isStatusOn() ? 'collapsed' : 'expanded') + ".gif' width='9' height='9' style='border-width: 0px; vertical-align: middle; margin-right: 3px;'/>";
    

    var brr = document.createElement('tr');
    brr.id = 'rRow:' + branch.getMapName();
    var brd = document.createElement('td');
    if (branch.isBasemap())
    {
      var radio_str = "<input type='radio' name='base_layer' id='b:" + branch.getMapName() + "' onclick='setBasemap(\"" + branch.getMapName() + "\")'";
      /*
      if (!branch.isBasemap())
      {
        radio_str += " style='visibility: hidden' disabled='disabled'";
      } else 
      */
      //if (j == branches.length - 1 || (j < branches.length - 1 && !branches[j + 1].isBasemap()))
      if (branch.getMapName() === ol_mapObj.baseLayer.name)
      {
        radio_str += " checked='checked'";
      }
      radio_str += "/>";
      brd.innerHTML = radio_str;
    }
    brr.appendChild(brd);
    
    var brd2 = document.createElement('td');
    brd2.style.width = '100%';
    brd2.innerHTML = "<a href='#' onclick='expandBranch(\"" + branch.getMapName() + "\"); return false'>" + img_str + "</a><label for='b:" + branch.getMapName() + "'>" + branch.getMapName().replace(/_/g,' ') + "</label>";
    brr.appendChild(brd2);

    llTbody.appendChild(brr);

    for (var i=0; i<branch.getLength(); ++i)
    {
      var layer = branch.getLayerById(i);
      var layerNameUnd = layer.name.replace(/ /g,'_');
      var inpElemId = 'l:' + branch.getMapName() + ':' + layerNameUnd;
  
      var inpElem;
      if (!layer.isBasemap())
      {
        inpElem = $('<input type="checkbox" />').attr('id', inpElemId).css('float','left').attr('checked',layer.isStatusVis());
        if ($.browser.msie)
        {
          inpElem.attr('defaultChecked',layer.isStatusVis());
	  //inpElem.click(toggleLayerVis);
        }
      }
      else
      {
        inpElem = $('<input type="radio" name="base_layer" onclick="setBasemap(\'' + layer.name + '\')" />').attr('id', inpElemId);
      }

      if (branch.isBasemap())
      {
        inpElem.css('visibility','hidden').attr('disabled',true);
      }
  
      var inpLabelElem = document.createElement('label');
      $(inpLabelElem).attr('for', inpElemId);
      inpLabelElem.appendChild(inpElem[0]);

      var icon_elem = layer.buildIconElement();
      if (icon_elem != null)
      {
	inpLabelElem.appendChild(icon_elem);
      }

      inpLabelElem.appendChild(document.createTextNode(layer.name));

      var llElem = document.createElement('td');
      if (!layer.isBasemap())
      {
        llElem.style.paddingLeft = '10px';
	if (!$.browser.msie)
	{
          //$(llElem).attr('onclick', 'toggleLayerVis(event)');
	  //$(inpLabelElem).click(toggleLayerVis);
	}
	$(inpLabelElem).click(toggleLayerVis);
      }
      $(llElem).mouseenter(function(e) { $(this).find('.layer_info').css('display','inline') });
      $(llElem).mouseleave(function(e) { $(this).find('.layer_info').css('display','none') });
  
      if (!layer.isConnectionTypeDb())
      {
        llElem.setAttribute((!ie) ? 'colspan' : 'colSpan','2'); // capital 'S' for IE
      }
      llElem.appendChild(inpLabelElem);

      var info = $('<img class="layer_info" src="http://reportallusa.com/images/info.png" width="16" height="16" />').css('display','none').click(layer_info);
      //info.mouseenter(function(e) { $(this).css('border-color', 'gray') });
      //info.mouseleave(function(e) { $(this).css('border-color', 'transparent') });
      llElem.appendChild(info[0]);
  
  
      var llRow = document.createElement('tr');
      llRow.id = 'lRow:' + branch.getMapName() + ':' + layerNameUnd;

      if (!layer.isBasemap())
      {
        var radio_nil = document.createElement('td');
        llRow.appendChild(radio_nil);
      }
      else
      {
        $(llElem).attr('colspan',2).attr('colSpan',2);
      }

      llRow.appendChild(llElem);

      /*
      if (layer.isConnectionTypeDb())
      {
        var ul_str = "<ul><li><img src='images/map_buttons/Label_Off.png' width='15' height='15' title='Label by attribute'/><ul>";
        var label_fields = layer.getLabelFields();
        var def_label_field = layer.getDefaultLabelField();
        if (label_fields != null)
        {
          for (var j=0; j<label_fields.length; ++j)
          {
            var cur_lf = label_fields[j];
    	var is_def = (cur_lf == layer.getDefaultLabelField());
    	ul_str += "<li";
    	if (is_def) ul_str += " class='label_field_sel'";
    	ul_str += ">" + cur_lf;
    	if (is_def) ul_str += "*";
    	ul_str += "</li>";
          }
        }
        ul_str += "</ul></li></ul>";
  
        var ul = $(ul_str);
        $(ul[0]).clickMenu({onClick: change_label});
        var ul_cell = $("<td style='width: 15px'/>")[0];
        ul_cell.appendChild(ul[0]);
  
        llRow.appendChild(ul_cell);
      }
      */
  
      if (!branch.isStatusOn())
      {
        llRow.style.display = 'none';
      }
  
      llTbody.appendChild(llRow);
    }
  }

  var fd = document.createElement('td');
  fd.setAttribute((!ie) ? 'colspan' : 'colSpan', '2');
  fd.appendChild(document.createTextNode(''));

  var fr = document.createElement('tr');
  fr.appendChild(fd);

  llTbody.appendChild(fr);
  

  var llTable = document.createElement('table');
  //$(llTable).css('padding-bottom', '5px');
  //$(llTable).addClass('leftPanelFoot');
  //$(llTable).addClass('layerLine');
  llTable.className = 'leftPanelFoot layerLine';
  llTable.style.paddingBottom = '5px';
  llTable.id = 'layerTreeTable';
  //llTable.setAttribute((!ie) ? 'class' : 'className', 'layerLine');
  llTable.appendChild(llTbody);
  //llTable.style.border = '5px solid green';
  //llTable.style.backgroundColor = 'yellow';
  layerForm.appendChild(llTable);

  enDisableLayers();
  ol_mapObj.events.register("zoomend", null, enDisableLayers);

  // could be set by site-specific js
  if (!Dco.Identify.selectedMapName)
  {
    var mapName = 'Overlays';
    var mn_e = $('.mapName');
    if (mn_e.length > 0)
    {
      mapName = mn_e.text();
    }
    //document.location.search.match(/(?:\?|&)mapName=([^&]*)/)
    Dco.Identify.selectedMapName = mapName;
  }

  // could be set by site-specific js
  if (!Dco.Identify.selectedLayer)
  {
    var layerName = 'Parcels';
    var ln_e = $('.layerName');
    if (ln_e.length > 0)
    {
      layerName = ln_e.text();
    }
    Dco.Identify.selectedLayer = LayerTree.root[Dco.Identify.selectedMapName].getLayerByName(layerName);
  }

  // highlight
  var sel_row = $('.srContainer table')
  for (var i=0; i<sel_row.length; ++i)
  {
    var wkt = $(sel_row[i]).find('.geom_as_wkt').text();
    Highlighting.addGeometry(wkt, Dco.Identify.selectedMapName, Dco.Identify.selectedLayer.name);
  }
  
}

function change_label(e)
{
  var t = e.currentTarget ? e.currentTarget : e.srcElement;
  var t_jq = $(t);
  var s = t_jq.siblings().removeClass('label_field_sel');
  t_jq.addClass('label_field_sel');
  var tr = t;
  while (tr && tr.nodeName.toLowerCase() != 'tr') tr = tr.parentNode;
  var layer_name = tr.id.match(/^lRow_(.*)$/)[1].replace(/_/g,' ');
  var field_name = t_jq.text().replace('*','');
  setMapImageParam('map.layer[' + layer_name + '].labelitem',"labelitem '" + field_name + "'");

}

function toggleLayerVis(e)
{
  //var tr = e.target ? e.target : e.srcElement;
  var tr = e.currentTarget;
  while (tr && tr.nodeName.toLowerCase() != 'tr')
  {
    tr = tr.parentNode;
  }
  tr = $(tr);

  var input = tr.find(':input[type="checkbox"]');

  // if checkbox is disabled, manually flip its state
  if (input.attr('disabled'))
  {
    input.attr('checked', input.attr('checked') ? '' : 'checked');
  }

  var ls = input.attr('id').split(':');
  var layerMap = ls[1];
  var layerName = ls[2].replace(/_/g, ' ');
  var branch = LayerTree.root[layerMap]
  if (branch.metadata.single_tile)
  {
    var layer = ol_mapObj.getLayersByName(branch.getMapName())[0]; //branch.getLayerByName(branch.getMapName());
    var lu_spl = layer.url.split('?');
    var p = [];
    var num_vis_layers = 0;

    if (lu_spl.length > 1)
    {
      var lp = lu_spl[1].split(/&/);
      for (var i=0; i<lp.length; ++i)
      {
	var pn = lp[i];

	var pn_eqpos = pn.indexOf('=');
	if (pn_eqpos == -1 || pn_eqpos == pn.length - 1 || pn.substring(0, pn_eqpos) != 'layer')
	{
          p.push(pn);
	  continue;
	}

	var p_lname = pn.substring(pn_eqpos + 1);
	if (p_lname != layerName) 
	{
	  p.push('layer=' + p_lname);
	  ++num_vis_layers;
	}
      }
    }

    if (input.attr('checked'))
    {
      p.push('layer=' + layerName);
      ++num_vis_layers;
    }

    var l_url = lu_spl[0];
    var l_nowvis = (num_vis_layers > 0);
    if (l_nowvis)
    {
      l_url += '?' + p.join('&');
    }

    layer.setVisibility(l_nowvis);
    layer.setUrl(l_url);
    if (l_nowvis)
    {
      layer.redraw();
    }
  } else {
    var layer = ol_mapObj.getLayersByName(layerName)[0];
    var vis = (!(!(input.attr('checked'))));
    layer.setVisibility(vis);
    var ra_layer = branch.getLayerByName(layerName);
    ra_layer.setStatusVis(vis);
  }

  // invalidate Identify tool menu
  $('#cur_toolbar_menu').remove();

  /*
  var lForm = document.getElementById('layerForm');
  //var inputElems = lForm.getElementsByTagNameNS('http://www.w3.org/1999/xhtml', 'input');
  var inputElems = lForm.getElementsByTagName('input');
  for (var i=0; i<inputElems.length; ++i)
  {
    var inpElem = inputElems[i];
    if (inpElem.type == 'checkbox')
    {
      var ls = inpElem.id.split(':');
      var layerMap = ls[1];
      var layerName = ls[2]; //.replace(/_/g,' ');
      var layer = LayerTree.root[layerMap].getLayerByName(layerName);
      layer.setStatusVis(inpElem.checked);
      ol_mapObj.getLayersByName(layerName)[0].setVisibility(inpElem.checked);
    }
  }
  */
}

/// takes an element in a result row, returns geom bounds
function geom_bounds_by_row_elem(ct)
{
  //var row_id = row_num_by_row_elem(ct);
  //var cur_pager = tab_active_is_map() ? srp_vert : searchResultsPager;
  //var wkt = cur_pager.rows2[row_id][cur_pager.col_idx['geom_as_wkt']];
  var row_rec = row_rec_by_row_elem(ct);
  //var wkt = $('#row_' + row_id + ' .geom_as_wkt').text();
  var wkt = $(row_rec).find('.geom_as_wkt').text();
  var g = OpenLayers.Geometry.fromWKT(wkt);
  var b = g.getBounds();
  return [b.left, b.bottom, b.right, b.top];
  /*
  var svgElem = document.getElementById('geom_' + row_id);
  var minx, maxx, miny, maxy;
  minx = miny = Number.POSITIVE_INFINITY;
  maxx = maxy = Number.NEGATIVE_INFINITY;

  var nn = svgElem.nodeName.toLowerCase();
  if (nn == 'rect')
  {
    minx = parseFloat(svgElem.getAttributeNS(null,'x'));
    maxx = minx + parseFloat(svgElem.getAttributeNS(null,'width'));
    miny = parseFloat(svgElem.getAttributeNS(null,'y'));
    maxy = miny + parseFloat(svgElem.getAttributeNS(null,'height'));
  } else if (nn == 'path' || nn == 'span') {
    var svgStr;
    if (nn == 'path')
    {
      svgStr = svgElem.getAttributeNS ? svgElem.getAttributeNS(null,'d') : svgElem.d;
    } else if (nn == 'span') {
      svgStr = svgElem.innerHTML;
    }
    var mbrArr = svgStr.split(/ *[M,ZL ] * /i); // FIX IF UNCOMMENTED!!
    if (mbrArr.length >= 5) // take into account leading 'M '
    {
      var num_coords = 0;
      for (var i=0; i<mbrArr.length; ++i) 
      {
        var pathElem = mbrArr[i];
        if (pathElem == '' || pathElem == 'M')
        {
          continue;
        }
        
        if (++num_coords % 2 == 1)
        {
          var x = parseFloat(pathElem);
          minx = Math.min(minx, x);
          maxx = Math.max(maxx, x);
        } else {
          var y = parseFloat(pathElem) * -1.0;
          miny = Math.min(miny, y);
          maxy = Math.max(maxy, y);
        }
      }
    }
  } else if (nn == 'shape') {
    //var path = svgElem.getAttribute('path');
    var oh = svgElem.outerHTML;
    var path = oh.match(/path\s*=\s*\"\s*(.*?)\s*\"/)[1];
    //alert(svgElem.getAttribute('path'));
    if (path.substring(0, 1) == 'm') path = path.substring(1);
    if (path.substring(path.length - 3) == ' xe') path = path.substring(0, path.length - 3);
    path = path.replace(/\s+l\s* /, ','); // FIX IF UNCOMMENTED!
    path_arr = path.split(/[ ,]/);
    //var vsu = Highlighting.vmlScaleUp;
    for (var i=0; i<path_arr.length - 2; i += 2)
    {
      var x = parseFloat(path_arr[i]); // / vsu;
      minx = Math.min(minx, x);
      maxx = Math.max(maxx, x);

      var y = parseFloat(path_arr[i+1]) * -1.0; // / vsu;
      miny = Math.min(miny, y);
      maxy = Math.max(maxy, y);
    }
  }

  var br = null;
  if (minx != Number.POSITIVE_INFINITY && miny != Number.POSITIVE_INFINITY && maxx != Number.NEGATIVE_INFINITY && maxy != Number.NEGATIVE_INFINITY)
  {
    br = [minx, miny, maxx, maxy];
  }
  return br;
  */
}

/// accepts either an event or a DOM element
function zoomTo(evt_or_node)
{
  var ct = evt_or_node;
  if (ct.currentTarget || ct.srcElement)
  {
    ct = ct.currentTarget ? ct.currentTarget : ct.srcElement;
  }

  var br = geom_bounds_by_row_elem(ct);

  if (br != null)
  {
    var minx = br[0];
    var miny = br[1];
    var maxx = br[2];
    var maxy = br[3];

    var expFrac = 0.1;
    var xExp = (maxx - minx) * expFrac;
    var yExp = (maxy - miny) * expFrac;
    var b = new OpenLayers.Bounds(minx - xExp, miny - yExp, maxx + xExp, maxy + yExp);
    /*
    if (alt_map_choose.cur_map === 'reportall_usa_map')
    {
      if ($('#map').length == 0)
      {
        initMapImage();
        populateLayers();
      }
      activateControl();
  
      //alert('zooming to ' + b);
      ol_mapObj.zoomToExtent(b);
  
      if (!document.location.hash.match(/tab=map/))
      {
        //tab_switch('tab_map');
	//document.location.hash = 'tab=map';
	$.historyLoad('tab=map');
      }
    }
    else
    */
    {
      var e_links = get_external_links(b);
      //recalcExternalLinks(null, b);
      var cm = alt_map_choose.cur_map;
      //var cm_href = $('#' + cm.replace(/ /g,'_').toLowerCase()).attr('href');
      var cm_href = e_links[cm.replace(/ /g,'_').toLowerCase()];

      var kml_url = null;
      if (cm === 'google_maps' || cm === 'bing_maps' || cm === 'google_earth')
      {
        //var rn = row_num_by_row_elem(ct);
        //var ctid = $('#row_' + rn + ' .ctid').text();
	var rr = row_rec_by_row_elem(ct);
	var ctid = $(rr).find('.ctid').text();
	if (ctid)
	{
	  // grab at least a rectangle of a certain size around the parcel, to mesh with mapping apps' minimum zoom thresholds
	  var g_xExp = Math.max(xExp, 100);
	  var g_yExp = Math.max(yExp, 100);
	  var g = new OpenLayers.Bounds(minx - g_xExp, miny - g_yExp, maxx + g_xExp, maxy + g_yExp);

	  var mapName = $('.mapName').text();
	  var layerName = $('.layerName').text();
	  var db_host = $('.db_host').text();

	  // TODO: use (county_id, parcel_id) where parcel num is unique
	  kml_url = 'http://reportallusa.com/kml_single_rec/mapName_' + mapName + '/layerName_' + layerName + '/rect_' + g.toArray().join(',') + '/ctid_' + ctid.substr(1,ctid.length - 2);
	  if (db_host)
	  {
	    kml_url += '/dbhost_' + db_host;
	  }
	  if (cm === 'google_maps')
	  {
            cm_href += '&q=' + kml_url;
	  }
	  else if (cm === 'bing_maps')
	  {
            cm_href += '&mapurl=' + kml_url + '/blankicon_1';
	  }
	}
      }

      if (cm !== 'google_earth')
      {
        window.open(cm_href);
      }
      else
      {
        window.open(kml_url);
      }
    }
  }
}

function search_form_submit()
{
  var sf = $('#searchForm');
  if (!sf.find('input[name="region"]:visible').val())
  {
    alert("You must enter a county or state before performing a search.");
    return false;
  }

  var nonr_flds = sf.find(':input[name!="region"][type="text"][name!="address_or_owner"], select[name!="address_or_owner"]');
  var nonr_nonempty = [];
  for (var i=0; i<nonr_flds.length; ++i)
  {
    var field = $(nonr_flds[i]);
    if ($.trim(field.val() + '') !== '')
    {
      nonr_nonempty.push(field.attr('name'));
      nonr_nonempty.push(field.val());
    }
  }

  if (nonr_nonempty.length == 0)
  {
    alert("Enter some search values to perform a search.");
    return false;
  }


  // disable blank inputs
  var f_inp = sf.find(':input,:submit');
  for (var i=0; i<f_inp.length; ++i)
  {
    var cur_inp = $(f_inp[i]);
    if (cur_inp.val() === '' || cur_inp.attr('name') === 'address_or_owner' || cur_inp.attr('type') === 'submit')
    {
      cur_inp.attr('disabled',true);
    }
  }
  return true;
}

function parDet(e)
{
  var td = e.currentTarget ? e.currentTarget : e.srcElement;
  //var detElem = target.parentNode.parentNode.getElementsByTagName('tr')[1];
  while (td && td.nodeName.toLowerCase() != 'td')
  {
    td = td.parentNode;
  }

  var detElem = td.parentNode.nextSibling;
  while (detElem && detElem.nodeName.toLowerCase() != 'tr')
  {
    detElem = detElem.nextSibling;
  }
  var collapse = (detElem.style.display == Highlighting.displayVis);
  td.innerHTML = collapse ? '→' : '↓';
  var newDispVal = collapse ? 'none' : Highlighting.displayVis;
  detElem.style.display = newDispVal;
}

function loadCamaLink()
{
}

function getMapImageParam(paramName, mapImageSrc)
{
  var paramVals = new Array();
  var reStr = '[?&]' + paramName + '=([^?&]*)';
  if (mapImageSrc == null)
  {
    mapImageSrc = mapImage.src;
  }
  var mp = mapImageSrc.match(new RegExp(reStr, 'g'));
  var eapm = new RegExp('^' + reStr + '$');
  for (var i=0; i<mp.length; ++i)
  {
    var param = mp[i];
    var paramMatch = param.match(eapm);
    if (paramMatch)
    {
      paramVals.push(unescape(paramMatch[1]));
      // return decodeURIComponent(paramMatch[1]); // this would be better
    }
  }
  if (paramVals.length == 1)
  {
    return paramVals[0]; 
  }
  if (paramVals.length > 1)
  {
    return paramVals;
  }
}

function rewriteParam(url, paramName, paramValue)
{
  var preQs = '';
  var postQs = url;
  var qmPos = url.indexOf('?');
  if (qmPos != -1)
  {
    preQs = url.substr(0, qmPos);
    postQs = url.substr(qmPos + 1);
  }
  var srcParams = postQs.split('&');
  for (var i=srcParams.length-1; i>=0; --i)
  {
    var param = srcParams[i];
    if (param.match('^' + paramName + '='))
    {
      srcParams.splice(i,1);
      //srcParams[i] = paramName + '=' + escape(paramValue);
      //break;
    }
  }
  var pvArr;
  if (paramValue instanceof Array)
  {
    pvArr = paramValue;
  } else {
    pvArr = [ paramValue ];
  }
  for (var j=0; j<pvArr.length; ++j)
  {
    srcParams.push(paramName + '=' + escape(pvArr[j]));
  }

  var resUrl = '';
  if (preQs != '')
  {
    resUrl += preQs + '?';
  }
  resUrl += srcParams.join('&');
  return resUrl;
}

function setMapImageParam(paramName, paramValue, mapImageSrc)
{
  var mapImage = document.getElementById('mapImage');
  if (!mapImageSrc)
  {
    mapImageSrc = mapImage.src;
  }

  var rewUrl = rewriteParam(mapImageSrc, paramName, paramValue);

  if (paramName == 'mapext')
  {
    var new_sc_denom = new Rect2D(paramValue.split(/[ ,]/)).getScaleDenom(mapImage.width);
    rewUrl = rewriteParam(rewUrl, 'map.imagetype', layerTree.getImagetype(new_sc_denom));
  }

  mapImage.src = rewUrl;
}

function viewportWidth() {
  if(window.innerWidth) return window.innerWidth;
  if(window.document.documentElement.clientWidth) return document.documentElement.clientWidth;
  return window.document.body.clientWidth;
}

function viewportHeight() {
  if(window.innerHeight) return window.innerHeight;
  if(window.document.documentElement.clientHeight) return document.documentElement.clientHeight;
  return window.document.body.clientHeight;
}


function findElemPos(obj) {
  var curleft = curtop = 0;
  if (obj.offsetParent) {
    curleft = obj.offsetLeft
    curtop = obj.offsetTop
    while (obj = obj.offsetParent) {
      curleft += obj.offsetLeft
      curtop += obj.offsetTop
    }
  }
  return [curleft,curtop];
}

// Map Tools

MapToolbarEvent = new Object();

MapToolbarEvent.deferMenuClosure = false;

MapToolbarEvent.mouseover = function(e)
{
  MapToolbarEvent.deferMenuClosure = true;
}

MapToolbarEvent.mouseout = function(e)
{
  MapToolbarEvent.deferMenuClosure = false;
  MapToolbarEvent.close_menu(e);
}

MapToolbarEvent.close_menu = function(e)
{
  var ctm = document.getElementById('cur_toolbar_menu');
  var p = (e.relatedTarget) ? e.relatedTarget : e.toElement;
  while (p && p != ctm && p.nodeName.toLowerCase() != 'body')
  {
    p =  p.parentNode;
  }
  if (p != ctm)
  {
    if (!MapToolbarEvent.deferMenuClosure)
    {
      //var tm = document.getElementById('cur_toolbar_menu');
      //if (tm) document.body.removeChild(tm);
      $('#cur_toolbar_menu').css('display','none');
    }
  }
}

MapToolbarEvent.activate = function(e)
{
  var td = (e.target) ? e.target : e.srcElement;
  $('#cur_toolbar_menu tr').css('background-color','').css('font-weight','normal');
  td.parentNode.style.backgroundColor = 'rgb(250, 250, 230)';
  td.parentNode.style.fontWeight = 'bold';


  var ls = td.id.split(':');
  var mapfile = ls[1];
  var ln = ls[2];
  
  Dco.Identify.selectedLayer = LayerTree.root[mapfile].getLayerByName(ln);
  Dco.Identify.selectedMapName = mapfile;

  activateControl(ol_mapObj.getControlsByClass('Dco.Identify')[0]);
  MapToolEvent.select_only_button('Identify');

  MapToolbarEvent.deferMenuClosure = false;
  MapToolbarEvent.close_menu(e);
}


function MapToolEvent()
{
}

MapToolEvent.elem_to_toolname = function(elem)
{
  var img = elem;
  if (img.nodeName.toLowerCase() != 'img')
  {
    img = $(elem).find('img').get(0);
  }
  var src = img.src;
  var toolSrcArr = src.split('/');
  var toolSrc = toolSrcArr[toolSrcArr.length - 1];
  var toolName = toolSrc.match(/^[^_]*/)[0];
  return toolName;
}

MapToolEvent.mouseover = function(e)
{
  var target = (e.target) ? e.target : e.srcElement;

  MapToolbarEvent.close_menu(e);

  var td = target;
  while (td && td.nodeName.toLowerCase() != 'td')
  {
    td = td.parentNode;
  }
  $(td).addClass('mapToolHover');

  //target.src = target.src.replace(/_off.png$/, '_over.png');
  var toolName = MapToolEvent.elem_to_toolname(target);
  if (toolName == 'Identify')
  {
    Dco.Identify.get_dropdown_table(td);
  }
}

MapToolEvent.mouseout = function(e)
{
  var target = (e.target) ? e.target : e.srcElement;
  //target.src = target.src.replace(/_over.png$/, '_off.png');

  var td = target;
  while (td && td.nodeName.toLowerCase() != 'td')
  {
    td = td.parentNode;
  }
  $(td).removeClass('mapToolHover');

  var jq_t = $(target);
  var btn_xy = jq_t.offset(); //element_offset(target);
  var btn_x = btn_xy.left; //parseInt(btn_xy[0]);
  var btn_y = btn_xy.top; //parseInt(btn_xy[1]);

  if (e.pageX < btn_x || e.pageX > btn_x + parseInt(jq_t.width()) || e.pageY < btn_y + parseInt(jq_t.height()))
  {
    MapToolbarEvent.close_menu(e);
  }
}

MapToolEvent.select_only_button = function(button_name)
{
  $('#mapToolsTable td.mapToolSel').removeClass('mapToolSel');
  var jq_btn = $('#mapToolsTable img[src$="/images/map_buttons/' + button_name + '_off.png"]');
  if (jq_btn.length > 0)
  {
    var td = jq_btn[0];
  }
  while (td && td.nodeName.toLowerCase() != 'td')
  {
    td = td.parentNode;
  }
  if (td)
  {
    $(td).addClass('mapToolSel');
  }
}

MapToolEvent.activate = function(e)
{
  var target = (e.target) ? e.target : e.srcElement;
  //target.src = target.src.replace(/_over.png$/, '_on.png');
  /*
  if (mapTool)
  {
    mapTool.cancel.call(mapTool, e);
    var mtTbe = mapTool.getToolButtonElem();
    //mtTbe.src = mtTbe.src.replace(/_on.png/, '_off.png');
    mapTool = null;
  }
  */

  var toolName = MapToolEvent.elem_to_toolname(target);

  if (toolName != 'ZoomOhio' && toolName != 'ZoomUSA' && toolName != 'Print')
  {
    MapToolEvent.select_only_button(toolName);
  }

  if (toolName == 'ZoomIn')
  {
    var zc = ol_mapObj.getControlsByClass('OpenLayers.Control.ZoomBox')[0];
    zc.out = false;
    activateControl(zc);
  } else if (toolName == 'ZoomOut') {
    var zc = ol_mapObj.getControlsByClass('OpenLayers.Control.ZoomBox')[0];
    zc.out = true;
    activateControl(zc);
  } else if (toolName == 'ZoomOhio') {
    zoom_to_map_extent(DcoMap.ohioMapExtent);
  } else if (toolName == 'ZoomUSA') {
    zoom_to_map_extent(DcoMap.usaMapExtent);
  } else if (toolName == 'Pan') {
    activateControl();
  } else if (toolName == 'Identify') {
    var ic = ol_mapObj.getControlsByClass('Dco.Identify')[0];
    activateControl(ic);
    MapToolEvent.select_only_button('Identify');
    //MapToolbarEvent.close_menu(e); // close Identify menu
  } else if (toolName == 'IdentifyCircle') {
  } else if (toolName == 'MeasureLine') {
    var mlc = ol_mapObj.getControlsByClass('OpenLayers.Control.Measure')[0];
    activateControl(mlc);
  } else if (toolName == 'MeasurePolygon') {
    var mpc = ol_mapObj.getControlsByClass('OpenLayers.Control.Measure')[1];
    activateControl(mpc);
  } else if (toolName == 'Print') {
    var url = '/dyn/map_pdf/map_pdf.py?map=' + ol_mapObj.baseLayer.params.map;;
    url += '&mapext=' + ol_mapObj.getExtent().toArray().join('+');

    overlays = [];
    var non_basebranches = LayerTree.getNonBaseBranches();
    for (var i=0; i<non_basebranches.length; ++i)
    {
      var branch = non_basebranches[i];
      var llLength = branch.getLength();
      for (var j=0; j<llLength; ++j)
      {
        var layer = branch.getLayerById(j);
	if (layer.isStatusVis() && layer.isVisibleAtScale())
	{
          var eff_name = (layer.group != null) ? layer.group : layer.name;
          overlays.push([branch.mapfile, eff_name]);
	}
      }
    }

    for (var i=0; i<overlays.length; ++i)
    {
      url += '&ovr_map_' + (i + 1) + '=' + overlays[i][0];
      url += '&ovr_layer_' + (i + 1) + '=' + overlays[i][1];
    }

    var mn_e = $('.mapName');
    if (mn_e.length == 1)
    {
      url += '&mapName=' + mn_e.text();
    }

    var ln_e = $('.layerName');
    if (ln_e.length == 1)
    {
      url += '&layerName=' + ln_e.text();
    }

    //var ctid_elem = $('#row_1 .ctid');
    var ctid_elem = $('.srContainer table .ctid');
    if (ctid_elem.length == 1)
    {
      url += '&ctid=' + ctid_elem.text();
    }
    var db_host = $('.db_host').text();
    url += '&db_host=' + db_host;

    window.open(url);
  }
}

function zoom_to_map_extent(map_extent)
{
  if (!map_extent) map_extent = DcoMap.defaultMapExtent;
  var dmeRect = new Rect2D(map_extent.split(/[ ,]/));
  var b = new OpenLayers.Bounds(dmeRect.minx, dmeRect.miny, dmeRect.maxx, dmeRect.maxy);
  ol_mapObj.zoomToExtent(b);
  /*
  var it = layerTree.getImagetype(dmeRect.getScaleDenom(mapImage.width));
  var itSrc = rewriteParam(mapImage.src,'map.imagetype', it);
  setMapImageParam('mapext', dmeRect.toMapExtString(), itSrc);
  */
  zoomTo.addedPolygons = new Object();
}

function initializeMapTools()
{
  var mtt = document.getElementById('mapToolsTable');
  var mTools = mtt.getElementsByTagName("td"); //"img");
  for(var i=0; i<mTools.length; ++i)
  {
    var mTool = mTools[i];
    addEventListenersToElem(mTool);
    mTool.addEventListener('click', MapToolEvent.activate, false);
    mTool.addEventListener('mouseover', MapToolEvent.mouseover, false);
    mTool.addEventListener('mouseout', MapToolEvent.mouseout, false);
  }
  var ads = $('.ads_mappage');
  if (ads.length > 0)
  {
    $(mtt).css('margin-right', ads.outerWidth() + 'px');
  }

  // select map tool from GET
  {
    var s = document.location.search;
    if (s[0] === '?')
    {
      s = s.substr(1);
    }
    var p = s.split('&');
    for (var i=0; i<p.length; ++i)
    {
      var pval = unescape(p[i]);
      var pm;
      if (pm = pval.match(/^default_tool=(.+)$/))
      {
        var jq_t = $('#mapToolsTable img[src$="/images/map_buttons/' + pm[1] + '_off.png"]');
	if (jq_t.length > 0)
	{
          MapToolEvent.activate(({'target': jq_t[0]}));
	}
      }
    }
  }
}

// Creates an absolute-positioned <div> suitable for drawing a zoom box
function createDiv(id, borderStyle) {
    if (id == null) id = 'zoomBox';
    if (borderStyle == null) borderStyle = '1px solid red';
    var elem = document.createElement("div");
    elem.id = id;
    elem.style.position = 'absolute';
    elem.style.lineHeight = '1px'; // let IE make it small vertically
    elem.style.border = borderStyle;
    //elem.style.backgroundColor = 'rgba(255,255,255,0.2)';
    elem.style.zIndex = 4;
    elem.style.top = elem.style.left = '0px';
    addEventListenersToElem(elem);
    document.body.appendChild(elem);
    return elem;
}


function MapTool()
{
  this.listenElems = MapTool.getListenElems();
}

/*
MapTool.begin = function(e)
{
  return mapTool.begin.call(mapTool, e);
}

MapTool.end = function(e)
{
  return mapTool.end.call(mapTool, e);
}

MapTool.drawRect = function(e)
{
  return mapTool.drawRect.call(mapTool, e);
}

MapTool.drawCircle = function(e)
{
  return mapTool.drawCircle.call(mapTool, e);
}

MapTool.setSelectedLayer = function(e)
{
  return mapTool.setSelectedLayer.call(mapTool, e);
}

MapTool.getMapXY = function(e)
{
  return [e.pageX - MapTool.mapImagePosX, e.pageY - MapTool.mapImagePosY];
}

if ($.browser.msie)
{
  MapTool.getMapXY = function(e)
  {
    return [e.clientX - MapTool.mapImagePosX, e.clientY - MapTool.mapImagePosY];
  }
}
*/

MapTool.getMapExtRect = function(mi_src)
{
  var ea = ol_mapObj.getExtent().toArray();
  var propMER = new Rect2D(ea[0],ea[1],ea[2],ea[3]);
  return propMER;
}

/*
MapTool.getListenElems = function()
{
  var le = [ ];
  var hlElem = Highlighting.getHLElem();
  if (hlElem)
  {
    le.push(hlElem);
  } else {
    le.push(mapImage);
  }
  return le;
}
*/

/*
function decorateMapTool(toolClass)
{
  if (!toolClass.name)
  {
    toolClass.name = toolClass.toString().match(/function ([^\(]*)/)[1];
  }
  toolClass.prototype.toolName = toolClass.name.replace(/Tool$/, '');
  toolClass.prototype.getToolButtonElem = function()
  {
    var mtt = document.getElementById('mapToolsTable');
    var mTools = mtt.getElementsByTagName("img");
    for(var i=0; i<mTools.length; ++i)
    {
      var mTool = mTools[i];
      if (mTool.src.match(this.toolName + '_(on|off|over).png'))
      {
        return mTool;
      }
    }
  }

  toolClass.prototype.addEventListener = function(eventName, func, blocking)
  {
    addArrEventListener(this.listenElems, eventName, func, blocking);
  }

  toolClass.prototype.removeEventListener = function(eventName, func, blocking)
  {
    removeArrEventListener(this.listenElems, eventName, func, blocking);
  }

  toolClass.prototype.curse = function(cursorStyle)
  {
    var leLen = this.listenElems.length;
    for (var i=0; i<leLen; ++i)
    {
      this.listenElems[i].style.cursor = cursorStyle;
    }
  }
}
*/

/*
function DrawRectTool()
{
  MapTool.prototype.constructor.call(this);
  this.mapExtRect = null;
  this.origX = -1;
  this.origY = -1;
  this.zoomBox = null;
  this.zbRect = null;
  this.propBox = null;
  this.zoomThresholdPx = 4;
}

DrawRectTool.prototype.init = function(e)
{
  this.addEventListener('mousedown', MapTool.begin, false);
  this.curse(this.mapCursor);
}

DrawRectTool.prototype.begin = function(e)
{
  this.removeEventListener('mousedown', MapTool.begin, false);

  this.zoomBox = createDiv('zoomBox');
  this.propBox = createDiv('propBox', 'gray 1px dashed');
  this.zoomBox.style.cursor = this.propBox.style.cursor = this.mapCursor;

  var xy = MapTool.getMapXY(e);
  this.origX = parseFloat(xy[0]); // - 1); // subtract border
  this.origY = parseFloat(xy[1]); // - 1); // subtract border
  this.zbRect = new Rect2D(this.origX, this.origY, this.origX, this.origY);
 
  this.mapExtRect = MapTool.getMapExtRect();

  this.listenElems.push(this.zoomBox, this.propBox);
  this.addEventListener('mousemove', MapTool.drawRect, false);
  this.addEventListener('mouseup', MapTool.end, false);

  if (e.preventDefault) 
  {
    e.preventDefault();
  }
  return false;
}

DrawRectTool.prototype.drawRect = function(e)
{
  var xy = MapTool.getMapXY(e);
  this.zbRect.setXCoords(this.origX, parseFloat(xy[0]));
  this.zbRect.setYCoords(this.origY, parseFloat(xy[1]));
  this.zbRect.positionElemAt(this.zoomBox, MapTool.mapImagePosX, MapTool.mapImagePosY);
  this.drawCustomRect(e);
  window.status = this.zbRect.toString(); // + '     ' + projCoords.toString();
}

/// default is to draw rect proportional to map image
DrawRectTool.prototype.drawCustomRect = function(e)
{
  var mapImageWidth = parseFloat(mapImage.width);
  var mapImageHeight = parseFloat(mapImage.height);
  var propRect = this.zbRect.getProportionalTo(mapImageWidth, mapImageHeight);
  propRect.positionElemAt(this.propBox, MapTool.mapImagePosX, MapTool.mapImagePosY);
  //var projCoords = this.mapExtRect.getProjectionOf(propRect, mapImageWidth, mapImageHeight);
}


DrawRectTool.prototype.cancel = function(e)
{
  this.removeEventListener('mousedown', MapTool.begin, false);
  this.removeEventListener('mousemove', MapTool.drawRect, false);
  this.removeEventListener('mouseup', MapTool.end, false);
  if (this.zoomBox)
  {
    document.body.removeChild(this.zoomBox);
    this.zoomBox = null;
  }
  if (this.propBox)
  {
    document.body.removeChild(this.propBox);
    this.propBox = null;
  }
  this.curse('auto');
}

DrawRectTool.prototype.end = function(e)
{
  this.cancel(e);
  var zbrW = this.zbRect.getWidth();
  var zbrH = this.zbRect.getHeight();
  if (zbrW < this.zoomThresholdPx && zbrH < this.zoomThresholdPx)
  {
    var mapImageWidth = parseFloat(mapImage.width);
    var mapImageHeight = parseFloat(mapImage.height);
    var zoomProp = 1.0 / 6.0;
    var widthP = mapImageWidth * zoomProp;
    var heightP = mapImageHeight * zoomProp;
    var zbrC = this.zbRect.getCenter();
    this.zbRect.setXCoords(zbrC[0] - widthP, zbrC[0] + widthP);
    this.zbRect.setYCoords(zbrC[1] - heightP, zbrC[1] + heightP);
  }
}
*/


/*
function IdentifyCircleTool()
{
  MapTool.prototype.constructor.call(this);
  this.mapCursor = 'help';
  this.circleElem = null;
  this.lineElem = null;
  this.mapExtRect = null;
  this.origX = null;
  this.origY = null;
}
decorateMapTool(IdentifyCircleTool);

IdentifyCircleTool.ic_id = 'identify_circle';
IdentifyCircleTool.ic_line_id = 'identify_circle_line';

IdentifyCircleTool.prototype.getCoordSysXY = function(e)
{
  var xy = MapTool.getMapXY(e);
  var me = this.mapExtRect;
  var cs_x = me.minx + (parseFloat(xy[0]) / parseFloat(mapImage.width)) * me.getWidth();
  var miHeight = parseFloat(mapImage.height);
  var cs_y = (me.miny + ((miHeight - parseFloat(xy[1])) / miHeight) * me.getHeight());
  //alert(cs_x + ',' + cs_y);
  return [cs_x,cs_y];
}

IdentifyCircleTool.prototype.init = function()
{
  this.addEventListener('mousedown', MapTool.begin, false);
  this.curse(this.mapCursor);
}

IdentifyCircleTool.prototype.begin = function(e)
{
  this.removeEventListener('mousedown', MapTool.begin, false);

  var hl = Highlighting.getHLElem();
  var c = document.getElementById(IdentifyCircleTool.ic_id);
  if (c) hl.removeChild(c);
  var l = document.getElementById(IdentifyCircleTool.ic_line_id);
  if (l) hl.removeChild(l);

  this.mapExtRect = MapTool.getMapExtRect();
  var cs_xy = this.getCoordSysXY(e);
  this.origX = cs_xy[0];
  this.origY = cs_xy[1];

  var svg_ns = 'http://www.w3.org/2000/svg';
  c = document.createElementNS(svg_ns,'circle');
  c.id = IdentifyCircleTool.ic_id;
  c.setAttribute('xmlns',svg_ns);

  c.setAttributeNS(null,'cx',this.origX);
  c.setAttributeNS(null,'cy',-1.0 * this.origY);
  c.setAttributeNS(null,'r',0);
  c.setAttributeNS(null,'fill','none');
  c.setAttributeNS(null,'stroke','blue');
  c.setAttributeNS(null,'stroke-width',Highlighting.scrnPxToCSUnit(2));
  hl.appendChild(c);
  this.circleElem = c;

  l = document.createElementNS(svg_ns,'line');
  l.id = IdentifyCircleTool.ic_line_id;
  l.setAttribute('xmlns',svg_ns);
  l.setAttributeNS(null,'x1',this.origX);
  l.setAttributeNS(null,'y1',-1.0 * this.origY);
  l.setAttributeNS(null,'x2',this.origX);
  l.setAttributeNS(null,'y2',-1.0 * this.origY);
  l.setAttributeNS(null,'stroke','green');
  l.setAttributeNS(null,'stroke-width',Highlighting.scrnPxToCSUnit(2));
  hl.appendChild(l);
  this.lineElem = l;

  Highlighting.updateViewBox();

  this.addEventListener('mousemove', MapTool.drawCircle, false);
  this.addEventListener('mouseup', MapTool.end, false);
}

IdentifyCircleTool.prototype.drawCircle = function(e)
{
  var cs_xy = this.getCoordSysXY(e);
  var r = Math.sqrt(Math.pow(this.origX - cs_xy[0],2) + Math.pow(this.origY - cs_xy[1],2));
  this.circleElem.setAttributeNS(null,'r',r);
  this.lineElem.setAttributeNS(null,'x2',cs_xy[0]);
  this.lineElem.setAttributeNS(null,'y2',-1.0 * cs_xy[1]);
}

IdentifyCircleTool.prototype.cancel = function()
{
  this.removeEventListener('mouseup', MapTool.end, false);
  this.removeEventListener('mousedown', MapTool.begin, false);
  this.removeEventListener('mousemove', MapTool.drawCircle, false);
  var hl = Highlighting.getHLElem();
  var c = document.getElementById(IdentifyCircleTool.ic_id);
  if (c) hl.removeChild(c);
  this.circleElem = null;
  this.lineElem = null;
  this.mapExtRect = null;
  this.origX = null;
  this.origY = null;
}

IdentifyCircleTool.prototype.end = function()
{
  this.removeEventListener('mousedown', MapTool.begin, false);
  this.removeEventListener('mousemove', MapTool.drawCircle, false);

}
*/



function search_keyup(e)
{
  var ct_name = null;
  if (e)
  {
    var ct = e.currentTarget ? e.currentTarget : e.srcElement;
    ct_name = ct ? ct.name : null;
  }

  var s_form = document.getElementById('searchForm');
  var s_inp = s_form.getElementsByTagName('input');
  var inp_text_nonpar = new Array();
  var ps_elem = s_form.elements['parcel'];
  for (var i=0; i<s_inp.length; ++i)
  {
    var inp = s_inp[i];
    if (inp.type == 'text')
    {
      if (inp.name != 'parcel' && inp.name != 'region')
      {
        inp_text_nonpar.push(inp);
      }
    }
  }
  
  if (ct_name == 'parcel')
  {
    var ps_empty = (ct.value == '');
    for (var i=0; i<inp_text_nonpar.length; ++i)
    {
      var ie = inp_text_nonpar[i];
      if (ps_empty)
      {
        ie.disabled = '';
      } else {
        ie.disabled = 'disabled';
        ie.value = '';
      }
    }
  } else {
    var non_par_val = '';
    for (var i=0; i<inp_text_nonpar.length; ++i)
    {
      var ie = inp_text_nonpar[i];
      non_par_val += ie.value;
    }

    var ps = $(s_form).find(':input[name="parcel"]');
    if (non_par_val == '')
    {
      ps.attr('disabled','');
    } else {
      ps.attr('disabled','disabled').attr('value','');
    }
  }
}

function search_clear(e)
{
  $('.par_sr').css('display','none'); 
  $('#address,#owner,#parcel_id').focus();
  $('#searchForm input[type="text"]').attr('value','');
  $('#searchForm :input[name="mapName"]').attr('value','Overlays');
  $('#searchForm :input[name="layerName"]').attr('value','Parcels');

  var soe = $('#search_options_expander');
  if (soe.length > 0)
  {
    var soe_expanded = (soe.text().indexOf('Advanced') == -1);
    if (soe_expanded)
    {
      show_search_options(soe.get(0));
    }
  }
  if (document.location.href.indexOf('#') !== -1)
  {
    document.location.href = document.location.href.substr(0, document.location.href.indexOf('#') - 1);
  }
}

function element_offset(elem)
{
  var offsetTrail = elem;
  var offsetLeft = 0, offsetTop = 0;
  while (offsetTrail) {
    offsetLeft += offsetTrail.offsetLeft;
    offsetTop += offsetTrail.offsetTop;
    offsetTrail = offsetTrail.offsetParent;
  }
  return [offsetLeft, offsetTop];
}

function RegionSearch() { }

RegionSearch.ac_elem = null;
RegionSearch.min_length = 3; // min length to search
RegionSearch.fetching = new Object();
RegionSearch.search_cache = new Object(); // all returned prefix results
RegionSearch.recent_cache = new Array(); // results specifically searched on

/*
RegionSearch.rs_elem = function()
{
  return document.getElementById('searchForm').elements['region'];
}
*/

RegionSearch.sub_value = function(rs_elem)
{
  //var rs_elem = RegionSearch.rs_elem();
  var elem_val = rs_elem.value;
  var ev_arr = elem_val.split(/\s*;\s*/);
  var sv = '';
  if (ev_arr.length)
  {
    sv = ev_arr[ev_arr.length - 1];
  }
  return sv;
}

RegionSearch.autocomplete = function(e)
{
  if ((e.keyCode < 37 || e.keyCode > 40) && e.keyCode != 13)
  {
    RegionSearch.clearTable();
  
    var target = e.currentTarget ? e.currentTarget : e.srcElement;
    var val = RegionSearch.sub_value(target);
    if (val.length >= RegionSearch.min_length)
    {
      if (RegionSearch.search_cache[val.substr(0,RegionSearch.min_length).toLowerCase()])
      {
        if (e.keyCode != 27)
        {
          RegionSearch.buildTable(target, val);
        }
      } else {
	RegionSearch.searchFor(val, target);
      }
    } else if (RegionSearch.recent_cache.length > 0) {
      if (e.keyCode != 27)
      {
        RegionSearch.buildTable(target, val);
      }
    }
  }
}

RegionSearch.handleCmdKey= function(e)
{
  var ac_elem = RegionSearch.ac_elem;
  var target = e.currentTarget ? e.currentTarget : e.srcElement;
  var sr_elem = null;
  var tbody_elem = null;
  if (ac_elem)
  {
    tbody_elem = ac_elem.childNodes[0];
    sr_elem = tbody_elem.childNodes[0];
    while (sr_elem && sr_elem.getAttribute('class') != 'ac_hl')
    {
      sr_elem = sr_elem.nextSibling;
    }
  }

  if (e.keyCode == 13)
  {
    if (sr_elem)
    {
      RegionSearch.addRegionByRow(sr_elem, target);
      return false;
    } else {
      RegionSearch.clearTable();
    }
  }
  else if (e.keyCode >= 37 && e.keyCode <= 40)
  {
    if (ac_elem)
    {
      if (sr_elem)
      {
        sr_elem.setAttribute('class', '');
        sr_elem.setAttribute('className', '');
      }

      if (e.keyCode == 40)
      {
        if (!sr_elem)
	{
          sr_elem = tbody_elem.childNodes[0];
	} else if (sr_elem.nextSibling) {
	  sr_elem = sr_elem.nextSibling;
	}
      } else if (e.keyCode == 38) {
        if (!sr_elem)
	{
          sr_elem = tbody_elem.childNodes[tbody_elem.childNodes.length - 1];
	} else if (sr_elem.previousSibling) {
          sr_elem = sr_elem.previousSibling;
	}
      }

      sr_elem.setAttribute('class', 'ac_hl');
      sr_elem.setAttribute('className', 'ac_hl');
    }
  }
  return true;
}

RegionSearch.inputElem = null;

RegionSearch.searchFor = function(val, target)
{
  var sv = val.substr(0,RegionSearch.min_length).toLowerCase();
  if (!RegionSearch.fetching[sv])
  {
    RegionSearch.fetching[sv] = true;
    RegionSearch.inputElem = target;
    $.getJSON('/json/cs_autocomplete?region_val=' + sv, RegionSearch.response);
  }
}

RegionSearch.response = function(data, textStatus)
{
  if (textStatus == "success")
  {
    var sv = data.region_val;
    RegionSearch.search_cache[sv] = data.results;
    if (RegionSearch.sub_value(RegionSearch.inputElem).substr(0,RegionSearch.min_length).toLowerCase() == sv)
    {
      RegionSearch.buildTable(RegionSearch.inputElem, sv);
    }
    delete RegionSearch.fetching[sv];
  }
  else
  {
    alert("RegionSearch error: unexpected textStatus response: " + textStatus);
  }
}

RegionSearch.clearTable = function()
{
  var ac = RegionSearch.ac_elem;
  if (ac)
  {
    RegionSearch.ac_elem = null;
    document.body.removeChild(ac);
    //while(ac.childNodes.length) ac.removeChild(ac.childNodes[ac.childNodes.length - 1]);
  }
}

RegionSearch.logSearchedRegions = function(regions_str)
{
  var regions = regions_str.split(/\s*;\s*/);
  for (var j=0; j<regions.length; ++j)
  {
    // TODO: validate against search_cache
    var cur_r = regions[j];

    var found_in_recent = false;
    for (var m=0; m<RegionSearch.recent_cache.length; ++m)
    {
      var rc_e = RegionSearch.recent_cache[m];
      if (cur_r.toLowerCase() == rc_e.region_name.toLowerCase())
      {
        ++rc_e.num_searched;
	break;
      }
    }
    if (found_in_recent)
    {
      break;
    }

    // not found in recent_cache; look in search_cache
    var found_in_search = false;
    var cur_sc_key = cur_r.substr(0, RegionSearch.min_length).toLowerCase();
    var sc_entry = RegionSearch.search_cache[cur_sc_key];
    if (sc_entry)
    {
      for (var m=0; m<sc_entry.length; ++m)
      {
        var sc_rec = sc_entry[m];
        if (sc_rec.region_name.toLowerCase() == cur_r.toLowerCase())
        {
	  // remove from search_cache
          var cur_sc_rec_arr = sc_entry.splice(m, 1);
	  var cur_sc_rec = cur_sc_rec_arr[0];
	  ++cur_sc_rec.num_searched;

	  // insert into recent_cache (in lexicographic order)
	  var sc_rec_ins = false;
          for (var n=0; n<RegionSearch.recent_cache.length; ++n)
	  {
	    var rc_rec = RegionSearch.recent_cache[n];
            if (rc_rec.region_name.toLowerCase() > cur_sc_rec.region_name.toLowerCase()) 
	    {
              RegionSearch.recent_cache.splice(n, 0, cur_sc_rec); // insert before
	      sc_rec_ins = true;
	      break;
	    }
	  }
	  if (!sc_rec_ins)
	  {
            RegionSearch.recent_cache.push(cur_sc_rec);
	  }

	  found_in_search = true;
  	  break;
        }
      }
    }
    if (found_in_search)
    {
      break;
    }

    // TODO: determine what to do if the search name is not found at all

  }
}

RegionSearch.buildTable = function(rs_elem, val)
{
  if (!RegionSearch.ac_elem)
  {
    //var rs_elem = RegionSearch.rs_elem();
    var rs_off = element_offset(rs_elem);

    var a = document.createElement('table');
    a.setAttribute('class', 'autocomplete');
    a.setAttribute('className', 'autocomplete');

    a.style.left = rs_off[0] + 'px';

    a.style.top = (rs_off[1] + rs_elem.offsetHeight) + 'px';

    a.appendChild(document.createElement('tbody'));
    document.body.appendChild(a);

    //alert(a.outerHTML);

    RegionSearch.ac_elem = a;
  }

  var res = RegionSearch.recent_cache;
  var region_val = RegionSearch.sub_value(rs_elem);
  if (region_val.length >= RegionSearch.min_length)
  {
    var rv_prefix = region_val.substr(0,RegionSearch.min_length).toLowerCase();
    res = res.concat(RegionSearch.search_cache[rv_prefix]);
  }
  var tbody_elem = RegionSearch.ac_elem.childNodes[0];
  var rvl = region_val.length;
  var unsearched = false;
  var num_rendered = 0;
  for (var i=0; i<res.length; ++i)
  {
    var res_row = res[i];
    var rn = res_row['region_name'];
  // check: &#2713; or &#2714
  // x:     &#2716; or &#2717 or &#2718
    if (rn.substr(0,region_val.length).toLowerCase() == region_val.toLowerCase())
    {
      var tr = document.createElement('tr');
      var td = document.createElement('td');
      var np = parseInt(parseInt(res_row['num_parcels']));
      if (np == 0)
      {
        td.style.color = 'gray';
      }
      var b = document.createElement('span');
      b.style.color = (np > 0) ? 'blue' : 'gray';
      b.style.fontWeight = 'bold';
      b.appendChild(document.createTextNode(rn.substr(0, rvl)));
      td.appendChild(b);
      td.appendChild(document.createTextNode(rn.substr(rvl)));
      var td2 = document.createElement('td');
      td2.style.paddingLeft = '15px';
      td2.style.color = (np > 0) ? 'green' : 'gray';
      td2.appendChild(document.createTextNode(res_row['region_type']));
      var td3 = document.createElement('td');
      td3.style.paddingLeft = '4px';
      var check_or_x = (np > 0) ? '<span style="color: darkgreen; font-weight: bold" title="Have data (' + np + ' parcels)">√</span>' : '<span style="color: gray" title="No data">×</span>';
      td3.innerHTML = check_or_x;

      var cur_unsearched = (res_row.num_searched == 0);
      if (!unsearched && cur_unsearched)
      {
	if (num_rendered > 0)
	{
          td.style.borderTop = td2.style.borderTop = '2px solid green';
	}
        unsearched = true;
      }

      tr.appendChild(td);
      tr.appendChild(td2);
      tr.appendChild(td3);
      tbody_elem.appendChild(tr);
      //addEventListenersToElem(tr);
      //tr.addEventListener('mousedown', RegionSearch.rowEvent, false);
      $(tr).mousedown(RegionSearch.rowEvent);
      var lp_elem = document.getElementById('leftPanel');
      //addEventListenersToElem(lp_elem);
      //lp_elem.addEventListener('scroll', RegionSearch.scroll, false);
      $(tr).scroll(RegionSearch.scroll);

      ++num_rendered;
    }
  }
}

RegionSearch.addRegionByRow = function(row_elem)
{
  //var rs_elem = RegionSearch.rs_elem();
  var rs_elem = RegionSearch.inputElem;
  var l_sem_pos = rs_elem.value.lastIndexOf(';');
  if (l_sem_pos != -1)
  {
    rs_elem.value = rs_elem.value.substr(0, l_sem_pos) + '; ';
  } else {
    rs_elem.value = '';
  }
  var r_txt_elem = (row_elem.nodeName.toLowerCase() == 'tr') ? row_elem.childNodes[0] : row_elem;
  rs_elem.value += r_txt_elem.textContent ? r_txt_elem.textContent : r_txt_elem.innerText;
  rs_elem.value += '; ';

  document.body.removeChild(RegionSearch.ac_elem);
  RegionSearch.ac_elem = null;

  rs_elem.focus();
}

RegionSearch.rowEvent = function(e)
{
  var t = e.currentTarget ? e.currentTarget : e.srcElement;
  if (e.type == 'mousedown')
  {
    RegionSearch.addRegionByRow(t, RegionSearch.inputElem);
  }
}

RegionSearch.scroll = function(e)
{
  RegionSearch.clearTable();  
  document.getElementById('leftPanel').removeEventListener('scroll', RegionSearch.scroll, false);
}

// event

function addEventListenersToElem(elem)
{
  if ((!elem.addEventListener) && (!elem.removeEventListener))
  {
    if (elem.attachEvent && elem.detachEvent)
    {
      elem.addEventListener = function(eventName, func, blocking)
      {
        this.attachEvent('on' + eventName, func);
      }
      elem.removeEventListener = function(eventName, func, blocking)
      {
        this.detachEvent('on' + eventName, func);
      }
    }
  }
}

function addRemoveArrEventListener(elemArr, action, eventName, func, blocking)
{
  for (var i=0; i<elemArr.length; ++i)
  {
    var elem = elemArr[i];
    if (action == 'add')
    {
      elem.addEventListener(eventName, func, blocking);
    } else if (action == 'remove') {
      elem.removeEventListener(eventName, func, blocking);
    }
  }
}

function addArrEventListener(elemArr, eventName, func, blocking)
{
  addRemoveArrEventListener(elemArr, 'add', eventName, func, blocking);
}

function removeArrEventListener(elemArr, eventName, func, blocking)
{
  addRemoveArrEventListener(elemArr, 'remove', eventName, func, blocking);
}

function export_qs()
{
  var qs = null;
  if (document.location.search.length > 0)
  {
    if (document.location.search[0] === '?')
    {
      qs = document.location.search.substr(1);
    }
    else
    {
      qs = document.location.search;
    }
  }
  var new_qs_a = [];
  var qs_p = qs.split('&');
  for (var i=0; i<qs_p.length; ++i)
  {
    var qp = qs_p[i].split('=');
    if (qp.length > 1)
    {
      if (qp[0] === 'sr_page')
      {
        continue;
      }
    }
    new_qs_a.push(qs_p[i]);
  }
  var new_qs = new_qs_a.join('&');
  return new_qs;
}

function ra_export(type)
{
  if (type == 'xls')
  {
    /*
    var xls_str = '/exp/xls.php?' + export_qs();
    if ($.browser.msie)
    {
      location.href = xls_str;
    } else {
      window.open(xls_str);
    }
    */
    location.href = '/price.php?' + export_qs();
  } else if (type == 'shp') {
    /*
    var shp_str = '/exp/shapefile.php?' + export_qs();
    if ($.browser.msie)
    {
      location.href = shp_str;
    } else {
      window.open(shp_str);
    }
    */
    location.href = '/price.php?' + export_qs();
  } else if (type == 'price') {
    //window.open('/price.php?' + export_qs(), 'price_popup', 'width=600,height=500,location=1,status=1,scrollbars=1');
    location.href = '/price.php?' + export_qs();
  } else if (type == 'kml') {
    /*
    var kml_loc = '/exp/kml.php?' + export_qs();
    if ($.browser.msie)
    {
      location.href = kml_loc;
    } else {
      window.open(kml_loc);
    }
    */
    location.href = '/price.php?' + export_qs();
  } else {
    alert('Export of this type is under development.  Email reportallusa@gmail.com to check on status.');
  }
}

function search_comparables(rn)
{
  var p = tab_active_is_map() ? srp_vert : searchResultsPager;
  var row = p.rows2[rn];

  var row_obj = ({});
  for (var i=0; i<row.length; ++i)
  {
    row_obj[p.col_names[i]] = row[i];
  }

  search_comparables_populate(row_obj);

  var soe = $('#search_options_expander');
  var soe_collapsed = (soe.text().indexOf('More') != -1);
  if (soe_collapsed)
  {
    show_search_options(soe.get(0));
  }

  searchResultsPager.searchByMainForm(); 
}

function search_comparables_populate(row_obj)
{
  var county_id = row_obj['county_id'];
  var ngh_code = row_obj['ngh_code'];

  var n_url = '/json/num_par_in_ngh?county_id=' + county_id + '&ngh_code=' + ngh_code;
  function ngh_error(xhr, textStatus, errorThrown)
  {
    alert("Error querying for number of parcels in neighborhood. textStatus: " + textStatus + ", errorThrown: " + errorThrown);
  }
  function ngh_success(data, textStatus)
  {
    if (textStatus != "success")
    {
      alert("Error: unexpected textStatus: " + textStatus + " when querying number of parcels in neighborhood");
    }
    else
    {
      search_comparables_populate.num_parcels_in_ngh[data.county_id + '_' + data.ngh_code] = data.num_parcels;
    }
  }

  var school_dist_id = row_obj['school_dist_id'];

  var cid_ngh_key = county_id + '_' + ngh_code;
  var num_par_in_ngh = null;
  if (school_dist_id != null && typeof(search_comparables_populate.num_parcels_in_ngh[cid_ngh_key]) == "undefined")
  {
    $.ajax({ 'url': n_url, 'async': false, 'dataType': 'json', 'error': ngh_error, 'success': ngh_success });
    num_par_in_ngh = search_comparables_populate.num_parcels_in_ngh[cid_ngh_key];
  }

  /*
  if (num_par_in_ngh < 10)
  {
    alert("Notice: ngh_code " + ngh_code + " in county " + county_id + " only has " + num_par_in_ngh + " parcels.  TODO: use school_dist_id instead");
  }
  */

  var mkt_val_tot = row_obj['mkt_val_tot'];
  var bldg_sqft = row_obj['bldg_sqft'];
  var land_use_code = row_obj['land_use_code'];
  var geom = row_obj['geom_as_wkt'];
  var county = row_obj['county_name'];
  var state_abbr = row_obj['state_abbr'];
  
  search_clear();

  function set_sval(name, value)
  {
    $('#searchForm :input[name="' + name + '"]').attr('value', value); 
  }

  set_sval('region', county + ', ' + state_abbr);

  set_sval('mkt_val_tot_min', mkt_val_tot * 0.7);
  set_sval('mkt_val_tot_max', mkt_val_tot * 1.3);
  if (num_par_in_ngh == null || (num_par_in_ngh >= 10 && school_dist_id != null))
  {
    set_sval('ngh_code', ngh_code);
  }
  else
  {
    set_sval('school_dist_id', school_dist_id);
  }
  var d = new Date();
  set_sval('trans_date_min', d.getMonth() + '-' + d.getDate() + '-' + (d.getFullYear() - 2));

  set_sval('range_radius', 3);
  var g = OpenLayers.Geometry.fromWKT(geom);
  var g_c = g.getCentroid();
  var lonlat = OpenLayers.Layer.SphericalMercator.inverseMercator(g_c.x, g_c.y);
  set_sval('range_lon', lonlat.lon);
  set_sval('range_lat', lonlat.lat);

  set_sval('bldg_sqft_min', bldg_sqft * 0.5);
  set_sval('bldg_sqft_max', bldg_sqft * 1.5);

  set_sval('land_use_code', land_use_code);
}

search_comparables_populate.num_parcels_in_ngh = new Object();

function excel_beforepaste(e)
{
  if (typeof(e.returnValue) !== "undefined")
  {
    e.returnValue = false;
  }
}

function excel_paste(e)
{
  var target = e.target ? e.target : e.srcElement;
  var clipData = e.clipboardData ? e.clipboardData : window.clipboardData;
  if (target && typeof(clipData) !== "undefined" && typeof(clipData.getData) !== "undefined")
  {
    var clipData = clipData.getData('Text');
    if (clipData.indexOf('\n') != -1)
    {
      target.value = clipData.replace(/\r\n/g,'; ').replace(/;\s+$/,'');
      return false;
    }
  }
}

function search_tab_switch(e)
{
  var st = $('.search_tabs_tab');
  for (var i=0; i<st.length; ++i)
  {
    var t = st[i];
    if (t !== e.target) 
    {
      $(t).css('background-color', 'rgb(240, 240, 240)').css('border-bottom', '1px solid gray');
    }
    $(e.target).css('background-color', '#E6F3FF').css('border-bottom', '1px solid #E6F3FF');
    
  }

  var target_text = $(e.target).text();
  var is_advanced = (target_text === 'Advanced');
  var is_basic = (target_text === 'Basic Search');
  var tr_disp_vis = $.browser.msie ? 'block' : 'table-row';
  
  var r = $('#searchPanel tr.search_row_advanced, #searchPanel tr.search_row_basic');
  for (var i=0; i<r.length; ++i)
  {
    var row = r[i];
    if ($(row).hasClass('search_row_advanced') && is_advanced)
    {
      $(row).css('display', tr_disp_vis);
    }
    else if ($(row).hasClass('search_row_basic') && is_basic)
    {
      $(row).css('display', tr_disp_vis);
    }
    else
    {
      $(row).css('display', 'none');
      $(row).find('input[type="text"]').val('');
    }
  }

  if (is_advanced)
  {
    // add story_height_min and story_height_max textbox overlays
    var minmax_arr = ['min', 'max'];
    for (var i=0; i<minmax_arr.length; ++i)
    {
      var minmax = minmax_arr[i];
      var sel = $('#searchForm select.story_height_' + minmax);
      var seloff = sel.offset();
      var over = $('<input type="text" name="story_height_' + minmax + '" style="background-color: transparent; font-size: 8pt; width: 5em; position: absolute; z-index: 2; border: 1px solid gray; padding: 0px;" />').css('left', seloff.left).css('height', sel.height());

      $('#searchForm').append(over);

      over.css('top', parseInt(seloff.top) + ((sel.outerHeight() - over.outerHeight()) / 2));

      sel.change(function(e) {
	var shClass = null;
	var sel = $(this);
	if (sel.hasClass('story_height_min'))
	{
          shClass = 'story_height_min';
	}
	else if (sel.hasClass('story_height_max'))
	{
          shClass = 'story_height_max';
	}
        $('#searchForm input[name="' + shClass + '"]').val(sel.val());

	// to cause onchange if blank selected
        sel.find('option[value=""]').text(' ');
        sel.val(' ');
      });

      if (sel.val() !== '')
      {
        over.val(sel.val());

	// to cause onchange if blank selected
        sel.find('option[value=""]').text(' ');
        sel.val(' ');
      }
    }

    // load land_use_code dropdown
    var sel = $('#searchForm select[name="land_use_code"]');
    if (sel.children().length < 3)
    {
      var qs_luc = [];
      var qs = document.location.search;
      if (qs)
      {
	if (qs[0] === '?')
	{
          qs = qs.substr(1);
	}
        var qs_spl = qs.split('&');
	for (var i=0; i<qs_spl.length; ++i)
	{
	  var luc_m;
          if (luc_m = qs_spl[i].match(/^land_use_code=(\d+)$/))
	  {
            qs_luc.push(luc_m[1]);
	  }
	}
      }

      // cannot use absolute URL because of same-site AJAX policy
      $.getJSON('/json/luc.php', function(data, textStatus) {
        sel.empty();
	var blank_opt_html = '<option';
	if (qs_luc === null)
	{
          blank_opt_html += ' selected="selected"';
	}
	blank_opt_html += '/>';
	sel.append($(blank_opt_html));
        for (var i=0; i<data.length; ++i)
        {
	  var data_item = data[i];
	  var luc = data_item[0];
	  var description = data_item[1];
	  var luc_padded = luc;
	  var pad_digits = 4 - luc_padded.length;
	  for (var j=0; j<pad_digits; ++j)
	  {
            luc_padded += '&#x2007';
	  }
          var newopt = $('<option value="' + luc + '">' + luc_padded + ' - ' + description + '</option>');
	  if ($.inArray(luc, qs_luc) !== -1)
	  {
            newopt.attr('selected', 'selected');
	  }
          sel.append(newopt);
        }
      });
    }
  }
  else
  {
    $('#searchForm input[name="story_height_min"], #searchForm input[name="story_height_max"]').remove();
  }

}

/*
function show_search_options(target)
{
  var jq_t = $(target);
  var expand = (jq_t.text().indexOf('Advanced') != -1);
  var bs_elem = $('#address,#owner,#parcel_id,#address_or_owner');
  $('#address,#owner,#parcel_id').attr('value','');
  if (expand)
  {
    jq_t.html('&laquo; Basic Search');
    bs_elem.css('display', 'none');
  }
  else
  {
    jq_t.html('Advanced Search &raquo;');
    bs_elem.css('display', '');
  }

  var or = $('#searchPanel tr').filter(".search_row_advanced");
  var tr_disp_vis = $.browser.msie ? 'block' : 'table-row';
  for (var i=0; i<or.length; ++i)
  {
    var opt_row = or[i];
    if (expand)
    {
      opt_row.style.display = tr_disp_vis;
    } else {
      opt_row.style.display = 'none';
      var inps = opt_row.getElementsByTagName('input');
      for (var j=0; j<inps.length; ++j)
      {
        var inp = inps[j];
	if (inp.type == 'text')
	{
          inp.value = '';
	}
      }
    }
  }
  if (!expand)
  {
    search_keyup();
  }
}
*/

