/* $Id: script.js 6055 2009-12-22 15:43:43Z wheirman $ */

var photosPerPage = 30;

function KeyCheck(e) {
  e = window.event ? event : e;
  if (e.altKey || e.ctrlKey) return;
  if (!e.shiftKey) return; /* require shift key */
  switch(e.keyCode) {
    case 36:
      // Home
      if (document.getElementById("albumlink")) location.assign(document.getElementById("albumlink").href);
      return false;
    case 37:
      // Arrow Left
      prev();
      return false;
    case 39:
      // Arrow Right
      next();
      return false;
  }
}

function prev() {
  if (current > 0) goto_(current - 1, -1, true);
}

function next() {
  var last = style == "album" ? Math.ceil(info.photos.length / photosPerPage) : info.photos.length;
  if (current < last-1) goto_(current + 1, +1, true);
}

function loadImage(imgtag, src) {
  /* load image with URL <src> into img-tag <imgtag>, taking care of pre-loading stuff
     (IE can't handle just doing imgtag.src = src !!) */
  var img = new Image();
  imgtag.src = src;
  img.onload = function() {
    imgtag.src = src;
  }
  img.src = src;
}

function zoomToggle() { setImage(true); }

var zoomActive = false;
function setImage(toggleZoom) {
  var dd = document.getElementById("divdivimage");
  if (dd) {
    if (toggleZoom) {
      zoomActive = !zoomActive;
      document.getElementById("zoomlink").title = "Zoom " + (zoomActive ? "out" : "in");
      document.getElementById("zoomimg").src = "/images/zoom_" + (zoomActive ? "active" : "normal") + ".gif";
    }

    var p = info.photos[current];
    var canZoom = p.ar > 1.5 * info.LARGEX / info.LARGEY;
    if (document.getElementById("zoomlink")) document.getElementById("zoomlink").style.display = canZoom ? "inline" : "none";

    /* Create a new image element. Don't reuse the existing one, because that will keep showing
       the existing photo while downloading the new one, possibly with new (and wrong) aspect ratio
       (we can't just delete the width/height from the image element and have it auto-scale, this won't
       work reliably, and makes it way too big for panorama photos) */
    var img = document.createElement("img");
    loadImage(img, "photos/" + p.name + ".jpg");
    img.alt = p.comments ? p.comments : p.name;

    if (info.full) {
      var a = document.createElement("a");
      a.href = "full/" + p.name + ".jpg";
      a.appendChild(img);
      img = a;
    }

    if (canZoom && zoomActive) {
      var s = sizeImg(p.ar, 10 * info.LARGEX, info.LARGEY);
      img.width = s[0]; img.height = s[1];
      dd.style.overflow = "auto";
      var ddLeft = (img.width - dd.clientWidth) / 2;
    } else if (style == 'slideshow') {
      var s = sizeImg(p.ar, dd.clientWidth, dd.clientHeight);
      img.width = s[0]; img.height = s[1];
      dd.style.overflow = "visible";
      var ddLeft = 0;
    } else {
      var s = sizeImg(p.ar, info.LARGEX, info.LARGEY);
      img.width = s[0]; img.height = s[1];
      dd.style.overflow = "visible";
      var ddLeft = 0;
    }
    if (canZoom) {
      img.onclick = zoomToggle;
      img.style.cursor = "pointer";
    }

    dd.replaceChild(img, dd.firstChild);
    dd.scrollLeft = ddLeft;
    resizeAll();
  }
}

function sizeImg(ratio, width, height) {
  if (ratio > width / height)
    return [ Math.round(width), Math.round(width / ratio) ];
  else
    return [ Math.round(height * ratio), Math.round(height) ];
}

function setThumb(i, idx) {
  var t = document.getElementById("thumb" + i);
  if (idx >= 0 && idx < info.photos.length) {
    loadImage(t, "thumbs/" + info.photos[idx].name + ".jpg");
    var s = sizeImg(info.photos[idx].ar, info.THUMBX, info.THUMBY);
    t.width = s[0];
    t.height = s[1];
    t.onclick = function() { goto_(idx, i > 2 ? +1 : -1, true); }
    t.style.display = 'inline';
  } else {
    t.src = "/images/dot_clear.gif";
    t.onclick = null;
    t.style.display = 'none';
  }
}

function XmlHttp() {
  if (window.XMLHttpRequest)
    return new XMLHttpRequest();
  else if (window.ActiveXObject)
    return new ActiveXObject("Microsoft.XMLHTTP");
  else
    return null;
}

function loadDiv(divName, url) {
  document.getElementById(divName).innerHTML = "<span class='loading'>loading...</span>";
  var req = XmlHttp();
  if (req != null) {
    req.onreadystatechange = function() {
      if (req.readyState == 4)
        document.getElementById(divName).innerHTML = req.responseText;
    };
    req.open("GET", url, true);
    req.send(null);
  } else
    document.getElementById(divName).innerHTML = "error";
  resizeAll();
}

/* Resize one item */
function resizeItem(item) {
  if (!item)
    return;

  /* Find browser window height */
  if (window.innerHeight)
    h = window.innerHeight;
  else if (document.documentElement && document.documentElement.clientHeight)
    h = document.documentElement.clientHeight;
  else if( document.body && document.body.clientHeight)
    h = document.body.clientHeight;
  else
    h = 800;

  /* Find item top */
  t = 0;
  o = item;
  while(o) {
    t += o.offsetTop;
    if (!o) break; /* This shouldn't be necessary, but IE barfs less now... Duhh!! */
    o = o.offsetParent;
  }

  /* Item height = window height - top - bottom margin */
  item.style.height = (h - t - 30) + 'px';
}

function resizeAll() {
  if (document.getElementById("exif") && document.getElementById("exif").offsetParent) {
    document.getElementById("exif").style.height = "150px";
    var h = document.getElementById("exif").offsetParent.clientHeight - document.getElementById("exif").offsetTop - 10;
    document.getElementById("exif").style.height = h + "px";
  }
  if (style == 'map') {
    resizeItem(document.getElementById("map"));
    map.checkResize();
  }
}

function goto_(idx, direction, updateURL) {
  if (current == idx) return;

  var last = style == "album" ? Math.ceil(info.photos.length / photosPerPage) : info.photos.length;

  document.getElementById("previmg").src = "/images/left_"  + (idx == 0 ?        "ghosted" : "normal") + ".gif";
  document.getElementById("nextimg").src = "/images/right_" + (idx == last - 1 ? "ghosted" : "normal") + ".gif";

  if (idx >= 0 && idx < last) {
    current = idx;
    /* update URL */
    if (updateURL) {
      /* don't do this when the URL is already correct (for instance, in response to
         the browser's Back button being pressed */
      var m = location.href.match(/([^#?]*)[#?]/);
      if (m)  var base = m[1];
      else    var base = location.href;
      if (!base.match(/photos/)) base = 'http://photos.heirman.net/' + info.id + '/';
      if (style == 'album') {
        location.assign(base + '?' + idx);
        return;
      } else
        location.assign(base + '#' + info.photos[idx].name);
    }

    if (style == "album") {
      /* info bar */
      var numpages = Math.ceil(info.photos.length / photosPerPage);
      var html = '';
      html += "<div><div><b>Photos " + (idx*photosPerPage+1) + "&nbsp;-&nbsp;" + Math.min((idx+1)*photosPerPage, info.photos.length) + "&nbsp;/&nbsp;" + info.photos.length + "</b></div>";
      if (numpages > 1) {
        html += "<div class='navdiv'>&nbsp;&nbsp;&nbsp;"
              + (idx > 0 ? " <a href='?0'>|«</a> <a href='?" + (idx-1) + "'>«</a>" : " <span>|«</span> <span>«</span>")
              + " page " + (idx+1) + "&nbsp;/&nbsp;" + numpages
              + (idx < numpages-1 ? " <a href='?" + (idx+1) + "'>»</a> <a href='?"+(numpages-1)+"'>»|</a>" : " <span>»</span> <span>»|</span>")
              + "</div><div class='navdiv'>&nbsp;&nbsp;&nbsp; "
        /*   some really unreadable code follows, to print links to other pages:
          [first] '...' [current-5] [current-4] .. [current+5] '...' [last]'
          special cases: - first (last) is in (current-5, current+5): don't print first (last) or '...'
                         - first (last) is current-6 (current+6)    : don't print '...'
                         - first (last) is current-7 (current+7)    : print current-6 (current+6) instead of '...'
                         - if 10 pages or less: always print all of them
          this way, we always have first, last & current-5 .. current+5, but never '...' as denoting none or just one page
        */
        if (numpages < 11) {
          for(var i = 0; i < numpages; ++i)
            html += ' <a ' + (i == idx ? 'class="navsel" ' : '') + 'href="?' + i + '">' + (i+1) + '</a>';
        } else {
          if (idx > 5) html += '<a href="?0">1</a>';
          if (idx > 6) html += idx == 7 ? ' <a href="?1">2</a>' : ' ...';
          for(var i = Math.max(0, idx - 5); i < Math.min(numpages, idx + 6); ++i)
            html += ' <a ' + (i == idx ? 'class="navsel" ' : '') + 'href="?' + i + '">' + (i+1) + '</a>';
          if (idx < numpages - 7) html += idx == numpages - 8 ? ' <a href="?' + (numpages-2) + '">' + (numpages-1) + '</a>' : ' ...';
          if (idx < numpages - 6) html += ' <a href="?' + (numpages-1) + '">' + numpages + '</a>';
        }
        html += "</div>";
      }
      html += "</div>";
      document.getElementById("albuminfo_top").innerHTML = html;
      /* zoom */
      if (document.getElementById("zoomlink")) {
        var m = location.href.match(/([^&]*)&z/);
        if (m) {
          zoomIndexActive = true;
          document.getElementById("zoomlink").href = m[1];
        } else {
          zoomIndexActive = false;
          document.getElementById("zoomlink").href = location.href + '&z';
        }
        document.getElementById("zoomimg").src = "/images/zoom_" + (zoomIndexActive ? "active" : "normal") + ".gif";
      } else
        zoomIndexActive = false;
      /* thumbnails */
      html = '';
      for(var i = idx*photosPerPage; i < (idx+1)*photosPerPage && i < info.photos.length; ++i) {
        /* determine thumbnail width / height based on stored aspect ratio */
        var s = sizeImg(info.photos[i].ar, 3*info.THUMBX, info.THUMBY);
        var w = s[0], h = s[1];
        var t = sizeImg(info.photos[i].ar, info.SMALLX, info.SMALLY);
        /* write out thumbnail HTML code */
        html += "<div" + (zoomIndexActive ? "style='height: auto'": "") + ">"
                /* poor man's "vertical-align: bottom" */
              + (h < info.THUMBY ? "<img src='/images/dot_clear.gif' width='1' height='" + (info.THUMBY-h) + "' /></br>" : "")
              + "<a href='photo.html#"+info.photos[i].name+"' title='"+info.photos[i].name+".jpg'>"
              + "  <img src='" + (zoomIndexActive || w > info.THUMBX ? "small" : "thumbs")
              + "/"+info.photos[i].name+".jpg' border='0' "
              + (zoomIndexActive ? "" : "width='"+w+"' height='"+h+"' ")
              + "     onMouseOver=\"overlib('<img src=\\'small/"+info.photos[i].name+".jpg\\' width=\\'"+t[0]+"\\' height=\\'"+t[1]+"\\' />', "
              + "                           SNAPX, 20, SNAPY, 20, HAUTO, VAUTO, WIDTH, "+t[0]+", HEIGHT, "+t[1]+", "
              + "                           BGCOLOR, '#c0c0c0', FGCOLOR, '#f0f0f0');\" onMouseOut=\"nd();\""
              + "  /></a></div>\n";
      }
      document.getElementById("images").innerHTML = html;

    } else if (style == "photo") {
      /* show image */
      var p = info.photos[idx];
      setImage(false);
      var html = '';
      if (p.copyright) html += "<div id='copyright'>" + p.copyright + "</div>";
      if (p.comments)  html += "<div id='comments'>" + p.comments + "</div>";
      document.getElementById("caption").innerHTML = html;
      /* update thumbnails */
      for(var i = 0; i < 5; ++i)
        setThumb(i, idx + i - 2);
      /* update info bar on the right */
      html = '<div><b>Photo '+(idx+1)+' of '+info.photos.length+'</b></div><br/>';
      html += '<div><table class="infotable">';
      for(var i = 0; i < p.info.length; ++i)
        html += "<tr><td class='info_key'>" + p.info[i][0] + "</td><td class='info_value'>" + p.info[i][1] + "</td></tr>";
      html += "</table></div>";
      document.getElementById('info_top').innerHTML = html;
      if (map) {
        var mapdiv = document.getElementById('info_map');
        if (p.marker) {
          mapdiv.style.display = 'block';
          map.checkResize();
          map.setCenter(p.marker.getPoint());
          document.getElementById("maplink").href = "map.html#" + idx
        } else
          mapdiv.style.display = 'none';
      }
      html = '';
      html += '<div><i>EXIF Information:</i></div><div id="exif"></div>';
      document.getElementById('info_bottom').innerHTML = html;
      loadDiv("exif", "exif/" + p.name + ".html");
      /* set link to correct page in album */
      document.getElementById("albumlink").href = "index.html?" + parseInt(idx/info.perpage);
      if (document.getElementById("slidelink")) document.getElementById("slidelink").href = "slide.html#" + idx;
      /* start downloading next picture */
      var _idx = idx + direction;
      if (_idx >= 0 && _idx < info.photos.length)
        document.getElementById("image_prefetch").src = "photos/" + info.photos[_idx].name + ".jpg";
    } else if (style == "map") {
      var p = info.photos[idx];
      if (p.marker) {
        map.setCenter(p.marker.getPoint());
        //p.marker.openInfoWindowHtml(p.marker.html);
      }
    } else if (style == "slideshow") {
      setImage(false);
      /* set link to correct page in album */
      document.getElementById("albumlink").href = "index.html?" + parseInt(idx/photosPerPage);
      document.getElementById("photolink").href = "photo.html#" + idx;
      /* start downloading next picture */
      var _idx = idx + direction;
      if (_idx >= 0 && _idx < info.photos.length)
        document.getElementById("image_prefetch").src = "photos/" + info.photos[_idx].name + ".jpg";
    }
  } else
    location.assign("index.html?0");
}

var playing = false;
function play() {
  playing = !playing;
  if (playing)
    setTimeout("playNext()", 5*1000);
}
function playNext() {
  if (!playing) return;
  next();
  setTimeout("playNext()", 5*1000);
}

function checkURL() {
  var m = location.href.match(/[#\?]([^&]*)/);
  if (m) {
    pName = m[1];
    for(idx = 0; idx < info.photos.length; ++idx)
      if (info.photos[idx].name == pName || pName == idx)
        break;
    if (idx == info.photos.length) idx = parseInt(pName);
    if (idx != current)
      goto_(idx, +1, false);
  } else
    goto_(0, +1, true);
  setTimeout("checkURL()", 200);
}

function init(_style) {
  style = _style;
  if (style == 'photo' || style == 'map')
    setupMap();
  if (style == 'map') {
    document.getElementById("map").style.display = 'block';
    resizeAll();
    for(var i = 0; i < info.photos.length; ++i)
      if (info.photos[i].marker) {
        goto_(i);
        break;
      }
  }
  if (style == 'slideshow')
    window.onresize = function() { setImage(false); };
  document.onkeyup = KeyCheck;
  checkURL();
}

var style = null;
var current = -1;

var map = null, icon = null, mgr = null;

function setupMap() {
  if (!document.getElementById("map")) return;

  // Creating Icons
  //
  // Creates a new type of icon, using the
  // <a href="http://labs.google.com/ridefinder/">Google Ride Finder</a> "mini"
  // markers as an example. We have to specify the foreground image, the shadow
  // image, and the points at which we anchor the icon to the map and anchor the
  // info window to the icon.

  // Create our "tiny" marker icon
  icon = new GIcon();
  icon.image = "/images/icon38.png";
  icon.shadow = "/images/icon38s.png";
  icon.iconSize = new GSize(32, 32);
  icon.shadowSize = new GSize(59, 32);
  icon.iconAnchor = new GPoint(16, 16);
  icon.infoWindowAnchor = new GPoint(16, 16);

  // Center the map on Palo Alto
  map = new GMap2(document.getElementById("map"));
  map.addMapType(G_PHYSICAL_MAP);
  map.addControl(new GMapTypeControl());
  if (style == "map") {
    map.addControl(new GLargeMapControl());
    map.addControl(new GOverviewMapControl());
    map.addControl(new GScaleControl());
  } else
    map.addControl(new GSmallMapControl());
  map.enableDoubleClickZoom();
  map.enableScrollWheelZoom();
  map.setCenter(new GLatLng(0, 0), 14);

  mgr = new GMarkerManager(map);

  var markers = [];
  for(var i = 0; i < info.photos.length; ++i)
    if (info.photos[i].lat && info.photos[i].lon) {
      var pt = new GLatLng(info.photos[i].lat, info.photos[i].lon);
      var marker = createMarker(pt, i);
      info.photos[i].marker = marker;
      markers.push(marker);
    }
  mgr.addMarkers(markers, 12);
  mgr.refresh();

  if (0 && info.gpxpath && style == 'map')
    for(var i = 0; i < polylines.length; ++i) {
      var line = new GPolyline.fromEncoded({
        color: "#0000FF",
        weight: 5,
        points: polylines[i].points,
        levels: polylines[i].levels,
        zoomFactor: 32,
        numLevels: 4
      });
      map.addOverlay(line);
    }
}

// Creates one of our tiny markers at the given point
function createMarker(point, idx) {
  var marker = new GMarker(point, icon);
  GEvent.addListener(marker, "click", function() {
    if (style == "map")
      marker.openInfoWindowHtml(marker.html);
    else
      goto_(idx, +1, true);
  });
  if (style == "map") {
    var s = sizeImg(info.photos[idx].ar, info.SMALLX, info.SMALLY);
    var html = '<div>'
             + '<a href="photo.html#'+idx+'"><img src="small/'+info.photos[idx].name+'.jpg" width="'+s[0]+'" height="'+s[1]+'" border="0" /></a>'
             + '</div>';
    marker.html = html;
  }
  return marker;
}

var hidingRight = false;
function hideRight() {
  hidingRight = !hidingRight;
  if (hidingRight) {
    document.getElementById("info").style.display = "none";
    document.getElementById("hideright").src = "/images/show-arrow.png";
  } else {
    document.getElementById("info").style.display = "table-cell";
    document.getElementById("hideright").src = "/images/hide-arrow.png";
    resizeAll();
  }
}
