/* - - - - - - - - - - - - - - - - - - - - - - -
 JavaScript:  BildAnzeige      (Version; 2.02)
 - - - - - - - - - - - - - - - - - - - - - - - */
//class ------------------------------------------------------------------------
function BildAnzeige()
{
  // private properties
  var self = this;
  var mIsSlideshowOn = false;
  var mSlideshowTimeout = 5000; /* ms */
  var mSlideshowTimer;
  var mIsScaleUpEnabled = false;
  var mIsZoomEnabled = false;
  var mIsZoomOn = false;
  var mBildZoom;
  var mAlbumPath;
  var mAlbumBilder = new Array();
  var mOriginalDocumentTitle = document.title;
  var mControlImagesPath = 'Bilder/controlimages/';
  //var mIsIE = navigator.appName.indexOf('Microsoft') >= 0;
  //var mIsIE = navigator.userAgent.indexOf('MSIE') >= 0;

  // stupid IE7 doesn't understand  const
  var idPage = 'view-page';
  var idShadow = 'view-shadow';
  var idLoad = 'view-loading';
  var idShowPicture = 'view-picture';
  var idPicture = 'area-picture';
  var idControl = 'area-control';
  var idBild = 'the-picture';
  var idControlMove = 'area-control-move';
  var idControlTools = 'area-control-tools';
  var idControlQuit = 'area-control-quit';
  var idButtonInfo = 'button-info';
  var idButtonZoom = 'button-zoom';
  var idButtonPrevious = 'button-previous';
  var idButtonSlide = 'button-slide';
  var idButtonNext = 'button-next';
  var idButtonQuit = 'button-quit';

  // private
  var setId = function(id)
  {
      return 'id="' + id + '"';
  }

  // private
  var setControlImageFile = function(name)
  {
      return mControlImagesPath + name + '.gif';
  }

  // private
  var switchVisibility = function(on, elements)
  {
      var visibility = on ? 'visible' : 'hidden';
      for (var i = 0; i < elements.length; i++)
      {
          document.getElementById(elements[i]).style.visibility = visibility;
      }
  }

  // private
  var showElements = function(e) { switchVisibility(true , arguments); }
  var hideElements = function(e) { switchVisibility(false, arguments); }

  // private
  var setSlideshowTimer = function()
  {
      if (mSlideshowTimer)
      {
          window.clearTimeout(mSlideshowTimer);
          mSlideshowTimer = undefined;
      }
      else if (mIsSlideshowOn)
          mSlideshowTimer = window.setTimeout(self.next, mSlideshowTimeout);
  }

  // private
  var switchZoom = function()
  {
      if (mIsZoomEnabled && mIsZoomOn)
      {
          buttonZoom.SetImgSrc(setControlImageFile('zoomrminus'));
          if (!mBildZoom)
             mBildZoom = new BildZoom(document.getElementById(idBild));
      }
      else
      {
          if (mBildZoom)
          {
              mBildZoom.Dispose();
              mBildZoom = undefined;
          }
          if (mIsZoomEnabled)
          {
              buttonZoom.SetImgSrc(setControlImageFile('zoomrplus'));
              buttonZoom.Show();
          }
          else
          {
              buttonZoom.Hide();
              mIsZoomOn = false;
          }
      }
  }

  // private: prepare the display of the picture:
  var showBild = function(bildName)
  {
      var ownName = new PathInfo(bildName).Name;
      document.title = mOriginalDocumentTitle + ' - ' + ownName;  // filename in window title
      mIsZoomEnabled = false;                 // disable zoom
      switchZoom();
      showElements(idLoad, idPage);           // show area displaying load message
      hideElements(idShowPicture);            // hide area displaying the picture to hide mods
      with (document.getElementById(idBild))
      {
          title = ownName;
          alt = bildName;
          // replace source with new picture to show; provokes the on load event
          src = mAlbumPath + bildName;
      }
  }

  // private: image on load handler:
  var loadBild = function()
  {
      hideElements(idLoad);    // hide the load message area
      self.resize();           // scale the picture to the available display area
      setSlideshowTimer();     // possibly start the slideshow timer
      return false;
  }

  // private: move to next (forward) or previous(backward) picture in list:
  var move = function(forward)
  {
      setSlideshowTimer();

      var aktuellesBild = new PathInfo(document.getElementById(idBild).src).FileName;
      for (var i = 0; i < mAlbumBilder.length; i++)
      {
          if (mAlbumBilder[i] == aktuellesBild)
          {
              var k = forward ? (i == mAlbumBilder.length - 1 ? 0 : i + 1) : (i == 0 ? mAlbumBilder.length : i) - 1;
              break;
          }
      }

      showBild(mAlbumBilder[k]);
  }

  // private: start or stop the automatic change to the next picture in the list:
  var slide = function()
  {
      var s = mIsSlideshowOn ? 'Stop' : 'Start';
      buttonSlide.SetHint(s + ' Slideshow');
      buttonSlide.SetImgSrc(setControlImageFile(s.toLowerCase() + 'slide'));
      buttonSlide.SetOnClick(mIsSlideshowOn ? self.slideStop : self.slideStart);
      setSlideshowTimer();
  }

  // ------------------------------------------------------------
  // this is the main entry point to show a picture in full size:
  // ............................................................
  // public
  this.showPicture = function(url)
  {
      var bild = new PathInfo(url);

      if (mAlbumPath != bild.Path)
      {
          mAlbumPath = bild.Path;    // we have a different album, remember new path
          mAlbumBilder.splice(0, mAlbumBilder.length);      // forget current list
          // bild up a list of the pictures in this album
          for (var i = 0; i < document.images.length; i++)
          {
              var src = document.images[i].src;
              if (src.indexOf(mAlbumPath) >= 0)
              {
                  var a = src.split('?')[1].split('&');
                  for (var k = 0; k < a.length; k++)
                  {
                      var p = a[k].split('=');
                      if (p[0] == 'bild')
                      {
                          mAlbumBilder.push(new PathInfo(p[1]).FileName);
                          break;
                      }
                  }
              }
          }
      }

      // if there is only one picture in our list hide the control for moving between pictures:
      document.getElementById(idControlMove).style.visibility = mAlbumBilder.length <= 1 ? 'hidden' : 'inherit';
      showBild(bild.FileName);
  }

  // public
  this.EnableScaleUp = function(enable)
  {
      mIsScaleUpEnabled = enable == 'on';
  }

  // public
  this.IsVisible = function()
  {
      return document.getElementById(idPage).style.visibility === 'visible';
  }

  // public
  this.resize = function()
  {
    //alert('rr '+document.getElementById(idPage).clientWidth+' '+document.getElementById(idPage).clientHeight)
    //alert('al '+document.getElementById(idLoad).clientWidth+' '+document.getElementById(idLoad).clientHeight)
    //alert('ba '+document.getElementById(idShowPicture).clientWidth+' '+document.getElementById(idShowPicture).clientHeight)
    //alert('mc '+document.getElementById(idControl).clientWidth+' '+document.getElementById(idControl).clientHeight);
    //alert('si '+document.getElementById(idButtonSlide).clientWidth+' '+document.getElementById(idButtonSlide).clientHeight);
    //alert('bb '+document.getElementById(idBild).clientWidth+' '+document.getElementById(idBild).clientHeight)

    // hide the area holding the display of the picture and the controls
    // in order to render the follwing scaling manipulations invisible:
    hideElements(idShowPicture);

    // determine the size of the available display area
    with (document.getElementById(idShowPicture))
    {
        var useWidth = clientWidth;    // total area minus space for controls
        var useHeight = clientHeight - Math.max(
            document.getElementById(idControl).clientHeight,
            document.getElementById(idButtonSlide).clientHeight);    // needed for IE
    }

    // set the space for the picture leaving space for the controls:
    document.getElementById(idPicture).style.height = useHeight.toPx();

    // fit the picture to the available space for display:
    with (document.getElementById(idBild))
    {
      // force reloading of these attrubutes to get the original size:
      removeAttribute('width');
      removeAttribute('height');
      // if size of picture exceeds available display space allow to toggle zoom mode:
      mIsZoomEnabled = (width > useWidth || height > useHeight);
      switchZoom();
      if (mBildZoom)
      {
          // zoom mode: i. e. show picture in full size with capability to move it around in the diaplay area
          mBildZoom.SetSize(useWidth, useHeight);
          // initially zoom on center of picture:
          mBildZoom.SetOrigin((width - useWidth) * 0.5, (height - useHeight) * 0.5);
          style.marginTop = 0;
      }
      else
      {
          // non zoom mode: scale image to use fully available area (scale up or down):
          if (mIsScaleUpEnabled || mIsZoomEnabled)
          {
            var scale = width / height;
            var w = Math.round(useHeight * scale);
            var h = useHeight;
            if (w > useWidth)
            {
                w = useWidth;
                h = Math.round(useWidth / scale);
            }
            width = w;
            height = h;
          }
          style.marginTop = Math.round((useHeight - height) * 0.49).toPx();
      }
      //alert(id+' '+clientWidth+' '+clientHeight+'  '+width+' '+height+'  '+useWidth+' '+useHeight+'  '+style.marginTop+'  '+style.clip)
      //alert("original: w*h " + width + " * " + height + "  s " + scale + "\ndisplay: w*h " + w + " * " + h + " used out of " + useWidth + " * " + useHeight + "\nwindow: w*h " + windowWidth + " * " + windowHeight);
    }

    // now show the area holding the picture and the controls (at bottom)
    showElements(idShowPicture);
  }

  // public
  this.quit = function()
  {
      self.slideStop();
      mIsZoomEnabled = false;    // make sure zoom is off
      switchZoom();
      document.title = mOriginalDocumentTitle;
      hideElements(idShowPicture, idPage);
      return false;
  }

  // public
  this.next     = function() { move(true);  return false; };
  this.previous = function() { move(false); return false; };

  // public
  this.slideStart = function() { mIsSlideshowOn = true;  slide(); return false; };
  this.slideStop  = function() { mIsSlideshowOn = false; slide(); return false; };

  // public
  this.zoom = function()
  {
      mIsZoomOn = !mIsZoomOn;  // toggle request
      switchZoom();
      self.resize();
      return false;
  }

  // public
  this.info = function()
  {
      alert('Info may be added in some future.');
      return false;
  }

  // define the layout of our additions to the document:
  document.writeln('<style type="text/css">');
  document.writeln('div#' + idPage);
  document.writeln('{');
  document.writeln(' position: fixed;');
  document.writeln(' left: 0; top: 0; width: 100%; height: 100%;');
  document.writeln(' z-index: 991;');
  document.writeln(' visibility: hidden;');
  document.writeln('}');
  document.writeln('div#' + idShadow);
  document.writeln('{');
  document.writeln(' position: absolute;');
  document.writeln(' left: 0; top: 0; width: 100%; height: 100%;');
  document.writeln(' visibility: inherit;');
  document.writeln(' background-color: #000000;');
  document.writeln(' filter: alpha(opacity=70);');    // IE
  document.writeln(' -moz-opacity: 0.7;');            // alte Firefox versionen [0.00 ... 1.00]
  document.writeln(' opacity: 0.70;');
  document.writeln('}');
  document.writeln('div#' + idLoad);
  document.writeln('{');
  document.writeln(' position: absolute;');
  document.writeln(' left: 0; top: 45%; height: 10%; width: 100%;');
  document.writeln(' visibility: hidden;');
  document.writeln('');
  document.writeln('}');
  document.writeln('div#' + idLoad + ' p');
  document.writeln('{');
  document.writeln(' font: normal 16px Tahoma,sans-serif; color: #ffffff; text-align: center;');
  document.writeln(' margin: auto; padding: 0;');
  document.writeln('}');
  document.writeln('div#' + idShowPicture);
  document.writeln('{');
  document.writeln(' position: absolute;');
  document.writeln(' left: 3%; top: 3%; width: 94%; height: 97%;');
  document.writeln(' visibility: hidden;');
  document.writeln('}');
  document.writeln('div#' + idPicture);
  document.writeln('{');
  document.writeln(' position: relative;');
  document.writeln(' visibility: inherit;');
  document.writeln(' text-align: center;');
  document.writeln('}');
  document.writeln('div#' + idControl);
  document.writeln('{');
  document.writeln(' position: relative;');
  document.writeln(' visibility: inherit;');
  document.writeln(' text-align: center;');
  document.writeln('}');
  document.writeln('div#' + idControl + ' img');
  document.writeln('{');
  document.writeln(' vertical-align: middle; margin: 0; cursor: pointer;');
  document.writeln('}');
  document.writeln('div#' + idControlTools);
  document.writeln('{');
  document.writeln(' visibility: inherit;');
  document.writeln(' float: left; text-align: left; width: 20%;');
  document.writeln('}');
  document.writeln('div#' + idControlQuit);
  document.writeln('{');
  document.writeln(' visibility: inherit;');
  document.writeln(' float: right; text-align: right; width: 20%;');
  document.writeln('}');
  document.writeln('div#' + idControlMove);
  document.writeln('{');
  document.writeln(' visibility: inherit;');
  document.writeln(' margin: auto; width: 59.8%;');
  document.writeln('}');
  document.writeln('</style>');

  // add our structure to the document:
  document.writeln('<div ' + setId(idPage) + '>');            // | covers entire window of current page

  document.writeln('<div ' + setId(idShadow) + '></div>');    //  | shadow as background for picture

  document.writeln('<div ' + setId(idLoad) + '>');            //  | message while loading the picture
  document.writeln('<p><img src="' + setControlImageFile('loading') + '" alt="loading the picture" />');
  document.writeln('<br />Press ESC to cancel loading.</p>');
  document.writeln('</div>');                                 //  | end area loading message

  document.writeln('<div ' + setId(idShowPicture) + '>');     //  | area for displaying picture and controls
  document.writeln('<div ' + setId(idPicture) + '>');         //   | subarea for picture
  document.writeln('<img ' + setId(idBild) + ' />');          //      the picture itself
  document.writeln('</div>');                                 //   | end subarea for picture
  document.getElementById(idBild).onload = loadBild;
  document.writeln('<div ' + setId(idControl) + '>');         //   | subarea for controls
  document.writeln('<div ' + setId(idControlTools) + '>');    //    | subsubarea at left (tools)
  var buttonZoom = new Button(idButtonZoom, '', 'Toggle Zoom | z', this.zoom);
  // hide until reasonable functionality will have been assigned to info
  // var buttonInfo = new Button(idButtonInfo, setControlImageFile('info'), 'Info | i', this.info);
  document.writeln('</div>');                                 //    | end subsubarea at öeft
  document.writeln('<div ' + setId(idControlQuit) + '>');     //    | subsubarea at right (quit)
  var buttonQuit = new Button(idButtonQuit, setControlImageFile('quit'), 'Quit | Esc', this.quit);
  document.writeln('</div>');                                 //    | end subsubarea at right
  document.writeln('<div ' + setId(idControlMove) + '>');     //    | subsubarea at center (move between pictures)
  var buttonPrevious = new Button(idButtonPrevious, setControlImageFile('left'), 'Previous Picture | Left Arrow Key', this.previous);
  var buttonSlide = new Button(idButtonSlide, setControlImageFile('startslide'), 'Start Slideshow', this.slideStart);
  var buttonNext = new Button(idButtonNext, setControlImageFile('right'), 'Next Picture | Right Arrow Key', this.next);
  document.writeln('</div>');                                 //    | end subsubarea at center
  document.writeln('</div>');                                 //   | end subarea for controls
  document.writeln('</div>');                                 //  | end area for display of picture and controls

  document.writeln('</div>');                                 // | end area page
}


// the instance of the object of type BildAnzeige
var ba = new BildAnzeige();

window.onresize = function()
{
  if (ba.IsVisible())  ba.resize();
  return true;
}

window.document.onkeydown = function(event)
{ 
  if (!event)  event = window.event;

  var keycode = event.which || event.keyCode;
  var isVisible = ba.IsVisible();

  if (keycode == 37 && isVisible) ba.previous();
  if (keycode == 39 && isVisible) ba.next();
  if (keycode == 27) ba.quit();
  if (keycode == 90 && isVisible) ba.zoom();
  if (keycode == 73 && isVisible) ba.info();
}


//class extension --------------------------------------------------------------
Number.prototype.toPx = function()
{
  return this.toFixed(0) + 'px';
}

//class ------------------------------------------------------------------------
function PathInfo(url)
{
  var i = url.lastIndexOf('/') + 1, k = url.lastIndexOf('.');
  this.Path = url.substring(0, i);
  this.FileName = url.substring(i, url.length);
  this.Name = url.substring(i, k);
  this.Extension = url.substring(k + 1, url.length);
}

//class ------------------------------------------------------------------------
function Tracer(x, y)    // keep track of relative displacement deltas
{
  var mX = x, mY = y;
  this.DX = function(x) { var d = mX - x; mX = x; return d; };
  this.DY = function(y) { var d = mY - y; mY = y; return d; };
}

//class ------------------------------------------------------------------------
//      initially the zoom window is positioned at the left top of the element (origin = (0, 0))
function BildZoom(element)
{
  var self = this;
  var mElement = element;
  var mSaveStylePosition = mElement.style.position;
  var mSaveStyleCursor = mElement.style.cursor;
  var mWidth = 40, mHeight = 30, mLeft = 0, mTop = 0;
  var mMouseTrace;

  // private
  var updatePosition = function()
  {
      var marginLeftRight = mElement.clientWidth  - mWidth;
      var marginTopBottom = mElement.clientHeight - mHeight;
      mLeft = Math.min(Math.max(0, mLeft), marginLeftRight);
      mTop  = Math.min(Math.max(0, mTop),  marginTopBottom);
      mElement.style.left = ((Math.min(marginLeftRight, 0) * 0.5) - mLeft).toPx();
      mElement.style.top  = ((Math.min(marginTopBottom, 0) * 0.5) - mTop).toPx();
      mElement.style.clip =
        'rect(' + mTop.toPx() +' '+ (mLeft + mWidth).toPx() +' '+ (mTop + mHeight).toPx() +' '+ mLeft.toPx() + ')';
  }

  // private
  var moveBegin = function(e)
  {
      if (!e)  e = window.event;
      mMouseTrace = new Tracer(e.clientX, e.clientY);
      with (mElement)
      {
          onmousemove = move;
          onmouseup = (onmouseout = moveFinish);
      }
      //e.stopPropagation();
      return false;
  }

  // private
  var move = function(e)
  {
      if (!e)  e = window.event;
      mLeft += mMouseTrace.DX(e.clientX);
      mTop  += mMouseTrace.DY(e.clientY);
      updatePosition();
      //e.stopPropagation();
      return false;
  }

  // private
  var moveFinish = function(e)
  {
      move(e);
      with (mElement)
      {
          onmouseup = (onmouseout = (onmousemove = null));
      }
      delete(mMouseTrace);
      return false;
  }

  // public      set the size (width & height) of the zoom window
  this.SetSize = function(w, h)
  {
      mWidth = w;
      mHeight = h;
      updatePosition();
  }

  // public      set the initial position (left & top) of thr zoom window within the area of the element
  this.SetOrigin = function(l, t)
  {
      mLeft = l;
      mTop = t;
      updatePosition();
  }

  // public      cleanup for destroying ourself
  this.Dispose = function()
  {
    with (mElement)
    {
      style.position = mSaveStylePosition;
      style.cursor = mSaveStyleCursor;
      onmousedown = null;
    }
  }

  with (mElement)
  {
    style.position = 'absolute';
    style.cursor = 'move';
    updatePosition();
    onmousedown = moveBegin;
  }
}

//class ------------------------------------------------------------------------
function Button(id, imgFile, hint, clickHandler)
{
  document.writeln('<img id="' + id + '" src="' + imgFile + '" title="' + hint + '" alt="" />');
  var me = document.getElementById(id);

  this.GetId = function() { return me.id; };

  this.GetImgSrc = function() { return me.src; };
  this.SetImgSrc = function(s) { me.src = s };

  this.GetHint = function() { return me.title; };
  this.SetHint = function(h) { me.title = h };

  this.GetOnClick = function() { return me.onclick; };
  this.SetOnClick = function(c) { me.onclick = c };
  this.UnSetOnClick = function() { me.onclick = null; };

  this.Hide = function() { me.style.visibility = 'hidden'; };
  this.Show = function() { me.style.visibility = 'visible'; };

  this.SetOnClick(clickHandler);
}
