 // Effects.js - (C) 2007 Grand City Property Management GmbH
 //
 // Used for fading / zooming effects, such as image zooming.
 // Requires: EffectsHTML.js
 //
 //////////////////////////////
 //
 // ZOOM IMAGE functions

 // Settings

 var includeCaption = 1; // Turn on the "caption" feature, and write out the caption HTML
 var zoomTime = 5; // Milliseconds between frames of zoom animation
 var zoomSteps = 15; // Number of zoom animation frames
 var fade = 1; // Fade images in / out
 var minBorder = 90; // Amount of padding between large, scaled down images, and the window edges

 var zoomImageURI = 'images-global/zoom/'; // Location of the zoom images

 // Init. Do not add anything below this line, unless it's something awesome.

 var myWidth = 0, myHeight = 0, myScroll = 0; myScrollWidth = 0; myScrollHeight = 0;
 var zoomOpen = false, preloadFrame = 1, preloadActive = false, preloadTime = 0, imgPreload = new Image();

 var zoomActive = new Array(); var zoomTimer = new Array();
 var zoomOrigW = new Array(); var zoomOrigH = new Array();
 var zoomOrigX = new Array(); var zoomOrigY = new Array();

 var zoomID = "ZoomBox";
 var theID = "ZoomImage";
 var theCap = "ZoomCaption";
 var theCapDiv = "ZoomCapDiv";
 
 // Zoom: Setup The Page! Called onLoad();

 function setupZoom() {
 prepZooms();
 insertZoomHTML();
 zoomdiv = document.getElementById(zoomID);
 zoomimg = document.getElementById(theID);
 }

 // Zoom: Inject Javascript functions into zoomable href's, one by one.
 // This is done at page load time via an onLoad() handler.

 function prepZooms() {
 if (! document.getElementsByTagName) {
 return;
 }
 var links = document.getElementsByTagName("a");
 for (i = 0; i < links.length; i++) {
 if (links[i].getAttribute("href") && (links[i].getAttribute("rel"))) {
 if (links[i].getAttribute("rel").indexOf("zoom:") == 0) {
 links[i].onclick = function () { zoomClick(this); return false; };
 links[i].onmouseover = function () { zoomPreload(this); };
 }
 }
 }
 }

 // Zoom: Preload a zoom image when hovering over the thumbnail, then set the image once the preload is complete.
 // Preloaded image is stored in imgPreload() and swapped out in the zoom function.

 function zoomPreload(from) {

 var theimage = from.getAttribute("href");
 // console.log("PRELOAD START: "+theimage);

 // Only preload if we have to, i.e. the image isn't this image already

 if (imgPreload.src.indexOf(from.getAttribute("href").substr(from.getAttribute("href").lastIndexOf("/"))) == -1) {
 preloadActive = true;
 imgPreload = new Image();

 // Set a function to fire when the preload is complete, setting flags along the way.

 imgPreload.onload = function() {
 // console.log("PRELOAD END");
 preloadActive = false;
 }

 // Load it!
 imgPreload.src = theimage;
 }
 }

 // Zoom: Start the preloading animation cycle.

 function preloadAnimStart() {
 preloadTime = new Date();
 document.getElementById("ZoomSpin").style.left = (myWidth /2 ) + 'px';
 document.getElementById("ZoomSpin").style.top = ((myHeight /2 ) + myScroll) + 'px';
 document.getElementById("ZoomSpin").style.visibility = "visible";
 preloadFrame = 1;
 document.getElementById("SpinImage").src = zoomImageURI+'zoom-spin-'+preloadFrame+'.png';
 preloadAnimTimer = setInterval("preloadAnim()", 100);
 }

 // Until we've been preloading for one second, just chill out in here.
 //
 // function preloadAnimPending(from) {
 // if (preloadActive != false) {
 // if ((new Date() - preloadTime) > 1000) {
 // document.getElementById("ZoomSpin").style.visibility = "visible";
 // clearInterval(preloadAnimTimer);
 // preloadAnimTimer = setInterval("preloadAnim()", 100);
 // }
 // else {
 // // Stay in this loop and don't do anything while we wait one second
 // }
 // } else {
 // clearInterval(preloadAnimTimer);
 // zoomIn(preloadFrom);
 // }
 // }

 // Zoom: Display and ANIMATE the jibber jabber widget. Once preloadActive is false, bail and zoom it up!

 function preloadAnim(from) {
 if (preloadActive != false) {
 document.getElementById("SpinImage").src = zoomImageURI+'zoom-spin-'+preloadFrame+'.png';
 preloadFrame++;
 if (preloadFrame > 12) preloadFrame = 1; } else {
 document.getElementById("ZoomSpin").style.visibility = "hidden";
 clearInterval(preloadAnimTimer);
 zoomIn(preloadFrom);
 }
 }

 // Zoom: We got a click! Should we do the zoom? Or wait for the preload to complete?

 function zoomClick(from) {

 // TODO: Double check that imgPreload src = clicked src

 // Get browser dimensions
 getSize();

 if (preloadActive == true) {
 // Preloading is otherwise still going on. So wait.
 preloadFrom = from;
 preloadAnimStart();
 } else {
 // Otherwise, we're loaded: do the zoom!
 zoomIn(from);
 }
 }

 // Zoom: Move an element in to endH endW, using zoomHost as a starting point.
 // "from" is an object reference to the href that spawned the zoom.

 function zoomIn(from) {

 zoomimg.src = from.getAttribute("href");

 // Determine the zoom settings from where we came from, the element in the <a>.
 // If there's no element in the <a>, or we can't get the width, make stuff up

 if (from.childNodes[0].width) {
 startW = from.childNodes[0].width;
 startH = from.childNodes[0].height;
 startPos = findElementPos(from.childNodes[0]);
 } else {
 startW = 50;
 startH = 12;
 startPos = findElementPos(from);
 }

 hostX = startPos[0];
 hostY = startPos[1];

 // Make up for a scrolled containing div.
 // TODO: This HAS to move into findElementPos.

 if (document.getElementById('scroller')) {
 hostX = hostX - document.getElementById('scroller').scrollLeft;
 }

 // Determine the target zoom settings

 endW = imgPreload.width;
 endH = imgPreload.height;

 // TODO: need to get "rollover" setting somehow.

 // Don't act if we're already doing something.

 if (zoomActive[theID] != true) {

 // Clear everything out just in case something is already open

 document.getElementById("ShadowBox").style.visibility = "hidden";
 document.getElementById("ZoomClose").style.visibility = "hidden";

 // Set the CAPTION if turned on

 if (includeCaption == 1) {
 zoomcap = document.getElementById(theCap);
 zoomcapd = document.getElementById(theCapDiv);

 if (from.getAttribute('title') && includeCaption == 1) {
 zoomcapd.style.display = 'block';
 zoomcap.innerHTML = from.getAttribute('title');
 } else {
 zoomcapd.style.display = 'none';
 }

 }

 // Store original position in an array for future zoomOut.

 zoomOrigW[theID] = startW;
 zoomOrigH[theID] = startH;
 zoomOrigX[theID] = hostX;
 zoomOrigY[theID] = hostY;

 // Now set the starting dimensions

 zoomimg.style.width = startW + 'px';
 zoomimg.style.height = startH + 'px';
 zoomdiv.style.left = hostX + 'px';
 zoomdiv.style.top = hostY + 'px';

 // Show the zoom box, make it invisible

 if (fade == 1) {
 setOpacity(0, zoomID);
 }
 zoomdiv.style.visibility = "visible";

 // If it's too big to fit in the window, shrink the width and height to fit (with ratio).

 sizeRatio = endW / endH;
 if (endW > myWidth - minBorder) {
 endW = myWidth - minBorder;
 endH = endW / sizeRatio;
 }
 if (endH > myHeight - minBorder) {
 endH = myHeight - minBorder;
 endW = endH * sizeRatio;
 }
 zoomChangeX = ((myWidth /2 ) - (endW /2 ) - hostX);
 zoomChangeY = (((myHeight /2 ) - (endH /2 ) - hostY) + myScroll);
 zoomChangeW = (endW - startW);
 zoomChangeH = (endH - startH);

 // console.log("X: "+zoomChangeX+" Y: "+zoomChangeY+" W: "+zoomChangeW+" H: "+zoomChangeH);

 // Setup Zoom

 zoomCurrent = 0;

 // Setup Fade with Zoom, If Requested

 if (fade == 1) {
 fadeCurrent = 0;
 fadeAmount = (0 - 100) / zoomSteps;
 } else {
 fadeAmount = 0;
 }

 // Do It!

 zoomTimer[theID] = setInterval("zoomElement('"+zoomID+"', '"+theID+"', "+zoomCurrent+", "+startW+", "+zoomChangeW+", "+startH+", "+zoomChangeH+", "+hostX+", "+zoomChangeX+", "+hostY+", "+zoomChangeY+", "+zoomSteps+", "+fade+", "+fadeAmount+", 'zoomDoneIn(zoomID)')", zoomTime);
 zoomActive[theID] = true;
 }
 }

 // Zoom it back out.

 function zoomOut() {

 // Check to see if something is happening/open

 if (zoomActive[theID] != true) {

 // First, get rid of the shadow if necessary

 document.getElementById("ShadowBox").style.visibility = "hidden";
 document.getElementById("ZoomClose").style.visibility = "hidden";

 // Now, figure out where we came from, to get back there

 startX = parseInt(zoomdiv.style.left);
 startY = parseInt(zoomdiv.style.top);
 startW = zoomimg.width;
 startH = zoomimg.height;
 zoomChangeX = zoomOrigX[theID] - startX;
 zoomChangeY = zoomOrigY[theID] - startY;
 zoomChangeW = zoomOrigW[theID] - startW;
 zoomChangeH = zoomOrigH[theID] - startH;

 // Setup Zoom

 zoomCurrent = 0;

 // Setup Fade with Zoom, If Requested

 if (fade == 1) {
 fadeCurrent = 0;
 fadeAmount = (100 - 0) / zoomSteps;
 } else {
 fadeAmount = 0;
 }

 // Do It!

 zoomTimer[theID] = setInterval("zoomElement('"+zoomID+"', '"+theID+"', "+zoomCurrent+", "+startW+", "+zoomChangeW+", "+startH+", "+zoomChangeH+", "+startX+", "+zoomChangeX+", "+startY+", "+zoomChangeY+", "+zoomSteps+", "+fade+", "+fadeAmount+", 'zoomDone(zoomID, theID)')", zoomTime);
 zoomActive[theID] = true;
 }
 }

 // Finished Zooming In

 function zoomDoneIn(zoomdiv, theID) {

 // Note that it's open

 zoomOpen = true;

 // Make sure they are gone

 setOpacity(0, "ShadowBox");
 setOpacity(0, "ZoomClose");

 // Position the shadow behind the zoomed in image.

 zoomdiv = document.getElementById(zoomdiv);
 shadowdiv = document.getElementById("ShadowBox");

 shadowLeft = parseInt(zoomdiv.style.left) - 13;
 shadowTop = parseInt(zoomdiv.style.top) - 8;
 shadowWidth = zoomdiv.offsetWidth + 26;
 shadowHeight = zoomdiv.offsetHeight + 26;

 shadowdiv.style.width = shadowWidth + 'px';
 shadowdiv.style.height = shadowHeight + 'px';
 shadowdiv.style.left = shadowLeft + 'px';
 shadowdiv.style.top = shadowTop + 'px';

 // Display Shadow and Zoom

 document.getElementById("ShadowBox").style.visibility = "visible";
 fadeElementSetup("ShadowBox", 0, 100, 5);
 document.getElementById("ZoomClose").style.visibility = "visible";
 fadeElementSetup("ZoomClose", 0, 100, 5);

 }

 // Finished Zooming Out

 function zoomDone(zoomdiv, theID) {

 // No longer open

 zoomOpen = false;

 // Clear stuff out, clean up

 zoomOrigH[theID] = "";
 zoomOrigW[theID] = "";
 document.getElementById(zoomdiv).style.visibility = "hidden";
 zoomActive[theID] == false;
 }

 // Actually zoom the element

 function zoomElement(zoomdiv, theID, zoomCurrent, zoomStartW, zoomChangeW, zoomStartH, zoomChangeH, zoomStartX, zoomChangeX, zoomStartY, zoomChangeY, zoomSteps, fade, fadeAmount, execWhenDone) {

 // console.log("Zooming Step #"+zoomCurrent+ " of "+zoomSteps+" (zoom " + zoomStartW + "/" + zoomChangeW + ") (zoom " + zoomStartH + "/" + zoomChangeH + ") (zoom " + zoomStartX + "/" + zoomChangeX + ") (zoom " + zoomStartY + "/" + zoomChangeY + ") Fade: "+fadeAmount);

 // Test if we're done, or if we continue

 if (zoomCurrent == (zoomSteps + 1)) {
 zoomActive[theID] = false;
 clearInterval(zoomTimer[theID]);

 if (execWhenDone != "") {
 eval(execWhenDone);
 }
 } else {

 // Do the Fade!

 if (fade != 0) {
 if (fadeAmount < 0) {
 setOpacity(Math.abs(zoomCurrent * fadeAmount), zoomdiv);
 } else {
 setOpacity(100 - (zoomCurrent * fadeAmount), zoomdiv);
 }
 }

 // Calculate this step's difference, and move it!

 moveW = cubicInOut(zoomCurrent, zoomStartW, zoomChangeW, zoomSteps);
 moveH = cubicInOut(zoomCurrent, zoomStartH, zoomChangeH, zoomSteps);
 moveX = cubicInOut(zoomCurrent, zoomStartX, zoomChangeX, zoomSteps);
 moveY = cubicInOut(zoomCurrent, zoomStartY, zoomChangeY, zoomSteps);

 document.getElementById(zoomdiv).style.left = moveX + 'px';
 document.getElementById(zoomdiv).style.top = moveY + 'px';
 zoomimg.style.width = moveW + 'px';
 zoomimg.style.height = moveH + 'px';

 zoomCurrent++;

 clearInterval(zoomTimer[theID]);
 zoomTimer[theID] = setInterval("zoomElement('"+zoomdiv+"', '"+theID+"', "+zoomCurrent+", "+zoomStartW+", "+zoomChangeW+", "+zoomStartH+", "+zoomChangeH+", "+zoomStartX+", "+zoomChangeX+", "+zoomStartY+", "+zoomChangeY+", "+zoomSteps+", "+fade+", "+fadeAmount+", '"+execWhenDone+"')", zoomTime);
 }
 }

 // Zoom Rollover Functions
 // To be re-added

 function zoomMouseOver() {
 // if (rollOverImg) {
 // if (document.getElementById("ZoomImage").src != rollOverImg) {
 // document.getElementById("ZoomImage").src = rollOverImg;
 // }
 // }
 }

 function zoomMouseOut() {
 // if (rollOverImg) {
 // if (document.getElementById("ZoomImage").src != image) {
 // document.getElementById("ZoomImage").src = image;
 // }
 // }
 }

 ////////////////////////////
 //
 // FADE Functions
 //

 function fadeOut(elem) {
 if (elem.id) {
 fadeElementSetup(elem.id, 100, 0, 10);
 }
 }

 function fadeIn(elem) {
 if (elem.id) {
 fadeElementSetup(elem.id, 0, 100, 10);
 }
 }

 // Fade: Initialize the fade function

 var fadeActive = new Array();
 var fadeQueue = new Array();
 var fadeTimer = new Array();
 var fadeClose = new Array();

 function fadeElementSetup(theID, fdStart, fdEnd, fdSteps, fdClose) {
 if (fadeActive[theID] == true) {
 // Already animating, queue up this command
 fadeQueue[theID] = new Array(theID, fdStart, fdEnd, fdSteps);
 } else {
 fadeSteps = fdSteps;
 fadeCurrent = 0;
 fadeAmount = (fdStart - fdEnd) / fadeSteps;
 fadeTimer[theID] = setInterval("fadeElement('"+theID+"', '"+fadeCurrent+"', '"+fadeAmount+"', '"+fadeSteps+"')", 15);
 fadeActive[theID] = true;
 if (fdClose == 1) {
 fadeClose[theID] = true;
 } else {
 fadeClose[theID] = false;
 }
 }
 }

 // Fade: Do the fade. This function will call itself, modifying the parameters, so
 // many instances can run concurrently.

 function fadeElement(theID, fadeCurrent, fadeAmount, fadeSteps) {

 if (fadeCurrent == fadeSteps) {

 // We're done, so clear.
 clearInterval(fadeTimer[theID]);
 fadeActive[theID] = false;

 // Should we close it?

 if (fadeClose[theID] == true) {
 document.getElementById(theID).style.visibility = "hidden";
 }

 // Hang on.. did a command queue while we were working? If so, make it happen now

 if (fadeQueue[theID] && fadeQueue[theID] != false) {
 fadeElementSetup(fadeQueue[theID][0], fadeQueue[theID][1], fadeQueue[theID][2], fadeQueue[theID][3]);
 fadeQueue[theID] = false;
 }

 } else {

 fadeCurrent++;

 // Set the opacity depending on if we're adding or subtracting (pos or neg)
 if (fadeAmount < 0) {
 setOpacity(Math.abs(fadeCurrent * fadeAmount), theID);
 } else {
 setOpacity(100 - (fadeCurrent * fadeAmount), theID);
 }

 // Keep going, and send myself the updated variables
 clearInterval(fadeTimer[theID]);
 fadeTimer[theID] = setInterval("fadeElement('"+theID+"', '"+fadeCurrent+"', '"+fadeAmount+"', '"+fadeSteps+"')", 15);
 }
 }

 ////////////////////////////
 //
 // UTILITY functions
 //

 // Utility: Set the opacity, compatible with a number of browsers. Value from 0 to 100.

 function setOpacity(opacity, theID) {

 var object = document.getElementById(theID).style;

 // If it's 100, set it to 99 for Firefox.

 if (navigator.userAgent.indexOf("Firefox") != -1) {
 if (opacity == 100) { opacity = 99.9999; } // This is majorly retarded
 }

 // Multi-browser opacity setting

 object.filter = "alpha(opacity=" + opacity + ")"; // IE/Win
 //object.KhtmlOpacity = (opacity / 100); // Safari 1.1 or lower, Konqueror
 //object.MozOpacity = (opacity / 100); // Older Mozilla+Firefox
 object.opacity = (opacity / 100); // Safari 1.2, Firefox+Mozilla

 }

 // Utility: Math functions for animation calucations - From http://www.robertpenner.com/easing/
 //
 // t = time, b = begin, c = change, d = duration
 // time = current frame, begin is fixed, change is basically finish - begin, duration is fixed (frames),

 function linear(t, b, c, d)
 {
 return c*t/d + b;
 }

 function sineInOut(t, b, c, d)
 {
 return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b;
 }

 function cubicIn(t, b, c, d) {
 return c*(t/=d)*t*t + b;
 }

 function cubicOut(t, b, c, d) {
 return c*((t=t/d-1)*t*t + 1) + b;
 }

 function cubicInOut(t, b, c, d)
 {
 if ((t/=d/2) < 1) return c/2*t*t*t + b;
 return c/2*((t-=2)*t*t + 2) + b;
 }

 function bounceOut(t, b, c, d)
 {
 if ((t/=d) < (1/2.75)){
 return c*(7.5625*t*t) + b;
 } else if (t < (2/2.75)){
 return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
 } else if (t < (2.5/2.75)){
 return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
 } else {
 return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
 }
 }


 // Utility: Get the size of the window, and set myWidth and myHeight

 function getSize() {
 if (document.all) {
 // IE4+ or IE6+ in standards compliant
 myWidth = (document.documentElement.clientWidth) ? document.documentElement.clientWidth : document.body.clientWidth;
 myHeight = (document.documentElement.clientHeight) ? document.documentElement.clientHeight : document.body.clientHeight;
 myScroll = (document.documentElement.scrollTop) ? document.documentElement.scrollTop : document.body.scrollTop;
 } else {
 // Non-IE
 myWidth = window.innerWidth;
 myHeight = window.innerHeight;
 myScroll = window.pageYOffset;
 }

 // Core code from - quirksmode.org
 if (window.innerHeight && window.scrollMaxY) {
 myScrollWidth = document.body.scrollWidth;
 myScrollHeight = window.innerHeight + window.scrollMaxY;
 } else if (document.body.scrollHeight > document.body.offsetHeight) { // all but Explorer Mac
 myScrollWidth = document.body.scrollWidth;
 myScrollHeight = document.body.scrollHeight;
 } else { // Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari
 myScrollWidth = document.body.offsetWidth;
 myScrollHeight = document.body.offsetHeight;
 }
 }

 // Utility: Find the Y position of an element on a page. Return Y and X as an array

 function findElementPos(elemFind)
 {
 var elemX = 0;
 var elemY = 0;
 do {
 elemX += elemFind.offsetLeft;
 elemY += elemFind.offsetTop;
 } while ( elemFind = elemFind.offsetParent )

 //console.log("Found element "+elemFind+" at "+elemY+"/"+elemX);

 return Array(elemX, elemY);
}
