/*==================================================*
 $Id: mapviewfuncs.js, v2.0 2009/02/13 01:24:00 Exp $
 Copyright 2009-2010 Spidy Web Design
 Last Modified 3/28/2010
 http://spidy.net/
 This is a set of utility functions to display maps,
   calculate settings, save and use cookies, etc
 *==================================================*/

// default zooms for entering a/f/p
azoom = 6;
fzoom = 10;
pzoom = 15;
var active = null;          // Which marker is active?
var origth = '';

// Describing the shifting state of the map
var isShifted = false;
var shiftV = null;
var shiftB = null;

// == zoom and pan to fit in view
GMap2.prototype.fit = function(bounds){
    this.setCenter(bounds.getCenter(),map.getBoundsZoomLevel(bounds));
}
var gg = GLatLng;

// Function to resize map and sidebar on resize of window
function resizemap(){
    if( typeof( window.innerHeight ) == 'number' ) {
        //Non-IE
        whgt = window.innerHeight;
    } else if( document.documentElement && ( document.documentElement.clientWidth || document.documentElement.clientHeight ) ) {
        //IE 6+ in 'standards compliant mode'
        whgt = document.documentElement.clientHeight;
    } else if( document.body && ( document.body.clientWidth || document.body.clientHeight ) ) {
        //IE 4 compatible
        whgt = document.body.clientHeight;
    }
    var thgt = (whgt - mapoff);
    $('mapcell').style.height = thgt +'px';
    $('side_bar').style.height = thgt +'px';
    var chgt = $('sbhead').style.height;
    var sbhgt = thgt  - chgt.slice(0,-2);
    if ($('sidebar_data')) {$('sidebar_data').style.height = sbhgt+'px';}
    else if ($('sb_pitems').innerHTML==''){ $('sb_layers').style.height = sbhgt+'px';}
    else {
        $('sb_pitems').style.height = 0.33*sbhgt+'px';
        $('sb_layers').style.height = 0.67*sbhgt+'px';
    }
}

// zoom in on a polyline and select middle (if mpoint not given)
function selectPoly(poly, m, mpoint, skipzoom) {
    if ((!skipzoom)&&(poly.state!=2)) map.fit(poly.getBounds());
    if (!mpoint) var mpoint = poly.getVertex(Math.round(poly.getVertexCount()/2));
    if (m) {
        var htmlcontent = m.create_formdata(m.loadedpitem);
        map.openInfoWindowHtml(mpoint, htmlcontent, {noCloseOnClick:true});
    }
}

// select a marker, by first centering and zooming with a timeout
function selectMarker(m, skipzoom) {
    if (m) {
        if (!skipzoom) {
            zoomIn(m.zoom, m.marker, true)
            var t = setTimeout("ed.chooseMarker();", 0)
        } else {ed.chooseMarker();}
    }
}

// Generic function for Zooming to a point.  If shift, put marker at bottom of page
// if point showing in view, do nothing
function zoomTo(zv, point, shift) {
    if (point) {
        if (shift) {
            var span = map.getBounds().toSpan();
            var spanlat = (zv)?span.lat()/Math.pow(2,zv-map.getZoom()):span.lat();
            var lat = point.lat() + 0.4*spanlat;
            var lng = point.lng();
            var npoint = new gg(lat, lng);
        } else {var npoint = point;}
        if (zv) {map.setCenter(npoint, zv);}
        else if (!map.getBounds().containsLatLng(point)) {map.setCenter(npoint);}
    }
}
// Zooming to a marker
function genZoom(zv, marker, shift) {
    if (marker) {
        if (marker instanceof GMarker) {zoomTo(zv, marker.getLatLng(), shift);}
        else if (marker instanceof GPolyline) {selectPoly(marker);}
    } else if (zv) { map.setZoom(zv); }
}
function zoomIn(zv, marker, shift) {
    if (map.getZoom() >= zv) zv = null;
    genZoom(zv, marker, shift)
}
function zoomInTo(zv, point, shift) {
    if (map.getZoom() >= zv) zv = null;
    zoomTo(zv, point, shift)
}
function zoomOut(zv, marker, shift) {
    if (map.getZoom() <= zv) zv = null;
    genZoom(zv, marker, shift)
}

// ------------------------------------------------------------
// Functions related to processing and passing url parameters

// obtain map settings and return a url-format string
function get_map_settings(map) {
    if (map) {
        var cent = map.getCenter();
        var span = map.getBounds().toSpan();
        var zm = map.getZoom();
        extension = '&ll='+cent.toUrlValue()+'&spn='+span.toUrlValue()+'&z='+zm;
    } else { extension = ''; }
    return extension
}

// open kml map with current settings in maps.google.com
function viewingoogle(map, siteurl) {
    var extension = get_map_settings(map);
    window.open("http://maps.google.com/maps?q=http://"+siteurl+"/Photos/map-"+$('settings').prio.value+".kmz"+extension);
}
function viewinbing() {
    var cent = map.getCenter();
    var zm = map.getZoom();
    window.open("http://www.bing.com/maps/default.aspx?v=2&FORM=LMLTCP&cp="+cent.lat().toFixed(5)+"~"+cent.lng().toFixed(5)+"&style=h&lvl="+zm); //+"&tilt=-90&dir=0&alt=-1000&phx=0&phy=0&phscl=1&encType=1");
}
// display a link to this map with current settings
function linktothis(map, siteurl) {
    var root = "http://"+siteurl+"/Photos/mapviewer.html?prio="+$('settings').prio.value;
    var extension = get_map_settings(map);
    alert("Copy the following url to link to this page:\n"+root+extension);
}

// set prio for page
function update_prio(val) {
    $('settings').prio.value = val;
}

// call this function once upon loading page
// read and parse url parameters, setting variables prio, zoom, lat, and lng
function test_settings(cookie) {
    if (cookie) {getCookie()}                   // First get cookie, if any, to set the defaults

    urlquery=location.href.split("?");          // get url params

    if (urlquery[1]) {                          // parse them
        urlterms=urlquery[1].split("&");
        for (jj=0; jj < urlterms.length; jj++) {
            urlitems = urlterms[jj].split('=');
            switch(urlitems[0]) {
              case "prio": prio = urlitems[1];break;
              case "z":    zoom = parseInt(urlitems[1]);break;
              case "ll":
                cent = urlitems[1].split(',');
                lat = parseFloat(cent[0]);
                lng = parseFloat(cent[1]);
                break;
              case "album": album = urlitems[1];break;
              case "ifold": ifold = Number(urlitems[1]);break;
              case "iphot": iphot = Number(urlitems[1]);break;
              case "mapkeys": mapkeys = urlitems[1].split(',');
            }
        }
    }

    update_prio(prio);                          // update prio
}

// random access (zoom and highlight) to markers by url query
function gotoMarkers(mkeys) {

    if ((mkeys) && (mkeys[0] in allmarkers)) {
        mapkeys = mkeys;
        var fm = allmarkers[mkeys[0]]
        var marker = fm.marker;
        if (marker instanceof GMarker) {
            var fmc = marker.getLatLng();
            var zv = 15;

            // Calculate appropriate bounds without zooming
            var margin = 1.1;   // leave some padding around marker set
            var span = map.getBounds().toSpan();
            var slat = margin*span.lat()/Math.pow(2,zv-map.getZoom());
            var slng = margin*span.lng()/Math.pow(2,zv-map.getZoom());
            var clat = fmc.lat(); var clng = fmc.lng();
            var sw = new gg(clat-slat/2.0, clng-slng/2.0);
            var ne = new gg(clat+slat/2.0, clng+slng/2.0);
            var bds = new GLatLngBounds(sw, ne);

            // Fix infowindow anchor
            var iwAnchor = marker.getIcon().infoWindowAnchor;
            var iconAnchor = marker.getIcon().iconAnchor;
            var pixoff = new GSize(iwAnchor.x-iconAnchor.x, iwAnchor.y-iconAnchor.y);
        } else if (marker instanceof GPolyline) {
            var bds = marker.getBounds();
            var fmc = marker.getVertex(Math.round(marker.getVertexCount()/2));
            var pixoff = new GSize(0, 0);
        }

        for (var j=1; j<mkeys.length; j++) {
            if (mkeys[j] in allmarkers) {
                var marker = allmarkers[mkeys[j]].marker;
                if (marker instanceof GMarker) { bds.extend(marker.getLatLng()); }
                // Comment out lines: albums that include long flights will mess this up
                //else if (marker instanceof GPolyline) {lbounds = marker.getBounds();bds.extend(lbounds.getSouthWest());bds.extend(lbounds.getNorthEast());}
            }
        }
        map.fit(bds);
        map.openInfoWindowTabsHtml(fmc, fm.loadContent(), {pixelOffset:pixoff, maxWidth:550});
        var t = setTimeout("highlightSelected();", 0);
    }
}

// highlight selected markers by mapkeys
function highlightSelected() {
    for (var j=0; j<mapkeys.length; j++) {
        if (mapkeys[j] in allmarkers) allmarkers[mapkeys[j]].update_color(true);
    }
}
// ------------------------------------------------------------
// Two Cookie-related functions for preserving settings

// call this function once upon UN-loading page
// reads current params and sets cookie
function setCookie() {
    var mptyp = 0;
    for (var i=0;i<map.getMapTypes().length;i++) {
      if (map.getCurrentMapType() == map.getMapTypes()[i]) {
        mptyp = i;
      }
    }
    var cent = map.getCenter()
    var cookietext = cookiename+"="+cent.toUrlValue().replace(',','|')+"|"+map.getZoom()+"|"+mptyp;
    if (expiredays) {
      var exdate=new Date();
      exdate.setDate(exdate.getDate()+expiredays);
      cookietext += ";expires="+exdate.toGMTString();
    }
    // == write the cookie ==
    document.cookie=cookietext;
    // == Call GUnload() on exit ==
    GUnload();
}

// gets cookie and calculates settings: Call from within test_settings()
function getCookie() {

    // === Look for the cookie ===
    if (document.cookie.length>0) {
        cookieStart = document.cookie.indexOf(cookiename + "=");
        if (cookieStart!=-1) {
            cookieStart += cookiename.length+1;
            cookieEnd=document.cookie.indexOf(";",cookieStart);
            if (cookieEnd==-1) cookieEnd=document.cookie.length;
            cookietext = document.cookie.substring(cookieStart,cookieEnd);
            // == split the cookie text and create the variables ==
            bits = cookietext.split("|");
            lat = parseFloat(bits[0]);
            lng = parseFloat(bits[1]);
            zoom = parseInt(bits[2]);
            maptype = parseInt(bits[3]);
        }
    }

}

// ------------------------------------------------------------

/**
 * Api version display as a custom GControl()
 * @author Esa 2009
 */
function VersionControl(opt_no_style){
  this.noStyle = opt_no_style;
};
VersionControl.prototype = new GControl();
VersionControl.prototype.initialize = function(map) {
  var display = document.createElement("div");
  map.getContainer().appendChild(display);
  display.innerHTML = "v=2."+G_API_VERSION;
  display.className = "api-version-display";
  if(!this.noStyle){
    display.style.fontFamily = "Arial, sans-serif";
    display.style.fontSize = "11px";
  }
  this.htmlElement = display;
  return display;
}
VersionControl.prototype.getDefaultPosition = function() {
  return new GControlPosition(G_ANCHOR_BOTTOM_LEFT, new GSize(3, 88));
}

// Set the cursor and mode button borders depending on editmode
function setcursor() {
  var cursor;
  switch(editmode){
    case 0: cursor = "default";break;
    case 2: cursor = "default";break;
    default: cursor = "crosshair";
  }
  map.getDragObject().setDraggableCursor(cursor);
}
function setborder() {
    $("mode1").style.border=(editmode==1)?"3px ridge blue":"0px";
    $("mode2").style.border=(editmode==2)?"3px ridge blue":"0px";
    $("mode3").style.border=(editmode==3)?"3px ridge blue":"0px";
    $("mode5").style.border=(editmode==5)?"3px ridge blue":"0px";

    $("mode1").style.margin=(editmode==1)?"0px 3px":"3px 6px";
    $("mode2").style.margin=(editmode==2)?"0px 3px":"3px 6px";
    $("mode3").style.margin=(editmode==3)?"0px 3px":"3px 6px";
    $("mode5").style.margin=(editmode==5)?"0px 3px":"3px 6px";
}
function ihover(elem) {
    elem.style.border = "2px outset blue";
    elem.style.margin = "1px 4px";
}
function iactive(elem) {
    elem.style.border = "2px inset blue";
    elem.style.margin = "1px 4px";
}

// set marker color based on state
function setcolor(marker, high) {
    if (marker instanceof GMarker) {
        var ic;
        switch(marker.state) {
          case 2: ic="orange-dot.png"; break;
          case 0: ic="blue-dot.png"; break;
          case 1: ic="green-stars.png"; break;
          case 4: ic="green-stars.png"; break;
          case 3: ic="grey-dot.png"; break;
          case 5: ic="grey-dot.png"; break;
          case 7: ic="grey-dot.png";
        }
        try { marker.setImage(iconbase+ic); } catch(err) { }
        if (!high) marker.getIcon().image = iconbase+ic;  // fixes default for rezoom w/ mgr
    } else if (marker instanceof GPolyline) {
        //if (high) { marker.setStrokeStyle({color: '#FFDD00'}); return; }
        var lc;
        switch(marker.state) {
          case 2: lc='#FF8800'; break;
          case 0: lc='#0000FF'; break;
          case 1: lc='#00FF00'; break;
          case 4: lc='#00FF00'; break;
          case 3: lc='#000000'; break;
          case 5: lc='#000000'; break;
          case 7: lc='#000000';
        }
        marker.setStrokeStyle({color: lc});
    }
}

// return thumbnail URL
function getthumb(th) {
    return '/Photos/'+th[0]+'/'+th[1]+'/thumbs/th_'+th[2].slice(0,-4)+'.jpg';
}

// change displayed thumb and open original pic on click
function chafth(th) { // To be called by album or folder
    origth = [$('ifwthumb').src, $('ifwcap').innerHTML];
    $('ifwthumb').src = getthumb(th);
    $('ifwcap').innerHTML = th[3];
}
function chth(item) {
    origth = [$('ifwthumb').src, $('ifwcap').innerHTML];
    var pname = item.href.split('=').slice(1);
    var path = item.href.split('/').slice(0,-1);
    $('ifwthumb').src = path.join('/')+'/thumbs/th_'+pname;
    $('ifwcap').innerHTML = item.innerHTML;
}
function chmth(item) {  // TO be called by movie
    origth = [$('ifwthumb').src, $('ifwcap').innerHTML];
    var ii = item.href.split('/');
    var pname = ii.slice(-1)[0].slice(0,-4)+'.jpg';
    var path = ii.slice(0,-1);
    $('ifwthumb').src = path.join('/')+'/thumbs/th_'+pname;
    $('ifwcap').innerHTML = item.innerHTML;
}
function pic(item) {
    var items = item.src.split('/');
    var divid = (items.slice(-3)[0]=='Movies')?'/thumbs/':'/';
    window.open(items.slice(0,-2).join('/')+divid+items.slice(-1)[0].slice(3));
}
function bk() {
    $('ifwthumb').src = origth[0];
    $('ifwcap').innerHTML = origth[1];
}
function bk1() { $('thpic').src = origth; } // for editing

// Generic Geocoder
function genericGeocode(addr, func, args) {
    if ((!geocoder) || (addr=='')) { return; }
    geocoder.setViewport(map.getBounds());
    geocoder.getLatLng( addr, function(point) {
        if (!point) {alert('/'+ addr + "/  not found");}
        else {
            if (isShifted && (shiftB.containsLatLng(point))) {
                point = new gg(point.lat()+shiftV.lat(), point.lng()+shiftV.lng());
            } 
            func(point, args)
        }
    });
}

function cmplatlng(latlng, m, prec) {
    if (m.marker instanceof GMarker) {
        mpos = m.marker.getLatLng().toUrlValue(prec);
        if (mpos==latlng) return true;
    }
    return false;
}

// Use geocoding to search map
function search(addr) {genericGeocode(addr, gotoM, null);}

function gotoM(point, dummy) {
    var mk = pinPoint(point, 3);
    if (mk!=null) {
        active = allmarkers[mk];
        active.update_color();
        zoomIn(active.zoom, active.marker, true);
        var t = setTimeout("active.marker.openInfoWindowTabsHtml(active.loadContent(), {maxWidth:550});active.update_color(true);", 0);
    } else {zoomInTo(fzoom, point, false);}
}

// Find nearest marker to point (within precision)
function pinPoint(point, prec) {
    var latlng = point.toUrlValue(prec);
    if (prec==6) { // Quick case
        var mk = latlng.replace(/,/, '_');
        if ((mk in allmarkers)&&(cmplatlng(latlng, allmarkers[mk], prec))) return mk;
        return null;
    }
    nearest = null;
    for (mk in allmarkers) {
        if (cmplatlng(latlng, allmarkers[mk], prec)) {
            nearest = mk;
            break;
        }
    }
    return nearest
}

// My Controls
// We define the function first, then define the methods to be called by GMap2

// Please Wait
function PlsWaitControl() {}
PlsWaitControl.prototype = new GControl();
PlsWaitControl.prototype.initialize = function(map) {
  var container = $('plswait');
  map.getContainer().appendChild(container);
  return container;
}
PlsWaitControl.prototype.getDefaultPosition = function() {
  return new GControlPosition(G_ANCHOR_TOP_RIGHT, new GSize(5,50));
}
PlsWaitControl.prototype.selectable = function() {return false;}
PlsWaitControl.prototype.printable = function() {return false;}

// Spidy Logo
function SpidyLogoControl() {}
SpidyLogoControl.prototype = new GControl();
SpidyLogoControl.prototype.initialize = function(map) {
  var container = $('spidylogo');
  GEvent.addDomListener(container, "click", function() {
    window.open('http://spidy.info/')
  });
  map.getContainer().appendChild(container);
  return container;
}
SpidyLogoControl.prototype.getDefaultPosition = function() {
  return new GControlPosition(G_ANCHOR_BOTTOM_LEFT, new GSize(5,50));
}
SpidyLogoControl.prototype.selectable = function() {return true;}
SpidyLogoControl.prototype.printable = function() {return true;}

// === Fix for Overview Map  courtesy of Marcello and Mike
// Alert if overviewmap control state changed
function om_changed() {
    var ov_container = $("map_overview");   // or ovmap.getContainer()

    //var src = ov_container.firstChild.nextSibling.firstChild.src;
    //if ('http://www.google.com/intl/en_ALL/mapfiles/overcontract.gif') {

    // Now Google uses sprites
    var stl = ov_container.firstChild.nextSibling.firstChild.style;
    if (stl.top == '-443px') {
        GEvent.trigger(map, 'om_collapsed');
    }
    else { //  if (stl.top == '-428px')
        GEvent.trigger(map, 'om_expanded');
    }
}

// Wait until Overview Map loaded from separate module
function checkOverview() {
    // First find the container of the overview map
    // The ID to look for is whatever the ID of your map container with '_overview' attached to it.
    var ov_container = $("map_overview");
    if (ov_container) {
        // Then find the little button with the arrow and attach the event handler
        ov_container.firstChild.nextSibling.onclick = om_changed;
    } else {
        setTimeout("checkOverview()",100);
    }
}

// set copyright line color based on maptype
function setcopycolor() {
    $("spidycopyright").style.color = map.getCurrentMapType().getTextColor();
    $("spidycopylink").style.color = map.getCurrentMapType().getLinkColor();
}

// Spidy Copyright
function SpidyCopyControl() {}
SpidyCopyControl.prototype = new GControl();
SpidyCopyControl.prototype.initialize = function(map) {
    var container = $('spidycopyright');
    if (container) {
        spcpmsg = container.innerHTML;
    } else {
        var container = document.createElement('div');
        container.innerHTML = spcpmsg;
        container.id = 'spidycopyright';
    }
    map.getContainer().appendChild(container);
    setcopycolor();
    GEvent.addListener(map, "maptypechanged", setcopycolor);
    return container;
}
SpidyCopyControl.prototype.getDefaultPosition = function() {
    return new GControlPosition(G_ANCHOR_BOTTOM_RIGHT, new GSize(124,17));
}
SpidyCopyControl.prototype.selectable = function() {return true;}
SpidyCopyControl.prototype.printable = function() {return true;}

// Spidy Copyright - shifted
function SpidyCopyControl2() {}
SpidyCopyControl2.prototype = new SpidyCopyControl();
SpidyCopyControl2.prototype.getDefaultPosition = function() {
    return new GControlPosition(G_ANCHOR_BOTTOM_RIGHT, new GSize(18,17));
}

// Runtime function to shift Spidy copyright right and left
function sh_copy_r() {
    map.removeControl(spcp);
    spcp = new SpidyCopyControl2();
    map.addControl(spcp);
}

function sh_copy_l() {
    map.removeControl(spcp);
    spcp = new SpidyCopyControl();
    map.addControl(spcp);
}

/*
*** Utilities for shifting the map to align satellite and map/hybrid/terrain layers
*/
// Calculate shift in pixels correspond to shift by ll from point lc in LatLng
// for current map zoom  returns Array [x,y]
function shiftLLtoPixel(ll, lc) {
    var merc = map.getCurrentMapType().getProjection();
    if (!lc) var lc = map.getCenter();
    var zz = map.getZoom();
    var pt1 = merc.fromLatLngToPixel(lc, zz);
    var l2 = new gg(lc.lat()+ll.lat(), lc.lng()+ll.lng());
    var pt2 = merc.fromLatLngToPixel(l2, zz);
    var x = pt2.x - pt1.x;
    var y = pt2.y - pt1.y;
    return [x, y];
}

// Shifts current layer (hybrid or map only)
// by latlng ll, around center point lc (optional)
function shiftLayer(ll, lc) {
    var container = document.getElementById("map");
    var cLayer = container.firstChild.firstChild.firstChild.nextSibling.firstChild;
    var mt = map.getCurrentMapType();

    // only operate on normal, terrain, and hybrid maps
    if (mt == G_HYBRID_MAP) { cLayer = cLayer.nextSibling; }
    else if ((mt != G_NORMAL_MAP) && (mt != G_PHYSICAL_MAP)) { return; } 

    var res = shiftLLtoPixel(ll, lc);
    if (cLayer) {
        cLayer.id = 'cLayer';
        cLayer.style.left = parseInt(res[0]) + 'px';
        cLayer.style.top = parseInt(res[1]) + 'px';
    } else { window.status = cLayer; }
}

// Shift Map by amount shift if any part of bounds bds overlaps with viewport
function shiftMap(plist) {
    var mbds = map.getBounds();
    var mc = map.getCenter();   // ? bds.getCenter()
    var cz = map.getZoom();

    for (j=0; j < plist.length; j++) {
        var p = plist[j];
        var bds = p['b'];
        var shift = p['s'];

        // if (bds.containsBounds(mbds)) {
        if (mbds.intersects(bds) && (map.getBoundsZoomLevel(bds)<cz)) {
            shiftLayer(shift, mc);
            isShifted = true;
            shiftV = shift;
            shiftB = bds;
            //window.status = 'Shifted!'
            return;     // Break for loop, no need to go through other cities
        }
    }
    if (isShifted) { // This should be outside of the for loop
        shiftV = new gg(0, 0);
        shiftLayer(shiftV, mc);
        isShifted = false;
        //window.status = 'Not Shifted!'
    }
}

// Read JSON file containing map shift amounts and set up and call Listeners
function setUpShift(doc) {
    var plist = eval('(' + doc + ')');

    // Apply initially, on change maptype, and on change zoom (trickiest)
    shiftMap(plist);
    GEvent.addListener(map, 'maptypechanged', function(){shiftMap(plist)});
    GEvent.addListener(map, 'zoomend', function(o, n){shiftMap(plist)});
}



