// SpryPanAndZoomPlugin.js - version 0.2 - Spry Pre-Release 1.7

//

// Copyright (c) 2008. Adobe Systems Incorporated.

// All rights reserved.

//

// Redistribution and use in source and binary forms, with or without

// modification, are permitted provided that the following conditions are met:

//

//   * Redistributions of source code must retain the above copyright notice,

//     this list of conditions and the following disclaimer.

//   * Redistributions in binary form must reproduce the above copyright notice,

//     this list of conditions and the following disclaimer in the documentation

//     and/or other materials provided with the distribution.

//   * Neither the name of Adobe Systems Incorporated nor the names of its

//     contributors may be used to endorse or promote products derived from this

//     software without specific prior written permission.

//

// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"

// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE

// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE

// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE

// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR

// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF

// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)

// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE

// POSSIBILITY OF SUCH DAMAGE.



(function() { // BeginSpryComponent



if (typeof Spry == "undefined" || !Spry.Widget || !Spry.Widget.ImageSlideShow)

{

	alert("SpryPanAndZoomPlugin.js requires SpryImageSlideShow.js!");

	return;

}



var gPZP = Spry.Widget.ImageSlideShow.PanAndZoomPlugin = {

	config: {

		defaultPanZoomSettings: [

			[  50,  50, 200,  50,  50, 100 ], // Zoom out from center.

	

			[   0,   0, 200, 100, 100, 100 ], // Pan from upper-left to lower-right.

			[ 100, 100, 200,   0,   0, 100 ], // Pan from lower-right to upper-left.

	

			[   0, 100, 200, 100,   0, 100 ], // Pan from lower-left to upper-right.

			[ 100,   0, 200,   0, 100, 100 ], // Pan from upper-right to lower-left.

	

			[  50,   0, 200,  50, 100, 100 ], // Pan from top to bottom.

			[  50, 100, 200,  50,   0, 100 ], // Pan from bottom to top.

	

			[   0,  50, 200, 100,  50, 100 ], // Pan from left to right.

			[ 100,  50, 200,   0,  50, 100 ]  // Pan from right to left.

		]

	},



	initialize: function(ss)

	{

		ss.panAndZoomInfo = { animations: [], pzSettings: [] };

		ss.addObserver(this);

	},



	fitAtoBRatio: function(aW, aH, bW, bH)

	{

		return Math.max(bW/aW, bH/aH);

	},



	onPostAttachViewBehaviors: function(ss,evt)

	{

		var clip = Spry.$$("." + ss.clipClass, ss.element)[0];

		ss.makePositioned(clip);

	

		Spry.$$("." + ss.clipClass + " img", ss.element).forEach(function(n){ n.style.top = n.style.left = 0; n.style.position = "absolute"; });

	},



	onPostExtractImageInfo: function(ss, evt)

	{

		var re = evt.repeatingElements;

		var pzs = ss.panAndZoomInfo.pzSettings;



		for (var i = 0; i < re.length; i++)

		{

			var e = re[i];



			var v = e.getAttribute("rel");

			if (!v)

				v = e.getAttribute("alt");



			var p = pzs[i] = new Object;



			if (v && v.search(/\[(\s*\d+\s*,){5}\s*\d+\s*\]/) != -1)

			{

				var m = v.match(/\[(\s*\d+\s*,){5}\s*\d+\s*\]/);

				if (m)

				{

					var pz = m[0].replace(/\[|\|\s*]/g, "").split(",");

					p.x1 = parseFloat(pz[0]);

					p.y1 = parseFloat(pz[1]);

					p.z1 = parseFloat(pz[2]);

					p.x2 = parseFloat(pz[3]);

					p.y2 = parseFloat(pz[4]);

					p.z2 = parseFloat(pz[5]);

				}

			}

		}

	},



	onPostStartSlideShow: function(ss, evt)

	{

		var slideIndex = ss.getCurrentSlideIndex();

		if (slideIndex >= 0)

			gPZP.setupSlide(ss, ss.getCurrentSlide(), slideIndex);

	},

	

	onPostStopSlideShow: function(ss, evt)

	{

		gPZP.stopAnimations(ss);

	},

	

	addAnimation: function(ss, anim)

	{

		ss.panAndZoomInfo.animations.push(anim);

		anim.addObserver({ onAnimationComplete: function(){ gPZP.removeAnimation(ss, anim); } });

	},



	removeAnimation: function(ss, anim)

	{

		var anims = ss.panAndZoomInfo.animations;

		if (anims)

		{

			for (var i = 0; i < anims.length; i++)

				if (anims[i] == anim)

				{

					anims.splice(i, 1);

					return;

				}

		}

	},



	stopAnimations: function(ss)

	{

		var anims = ss.panAndZoomInfo.animations;

		while (anims && anims.length)

			anims.pop().stop();

	},



	getPanZoomSettings: function(ss, slideIndex)

	{

		var result = {};



		var info = ss.imageInfo[slideIndex];

		

		result.width = info.width;

		result.height = info.height;



		// Get any pan and zoom settings from the specified element.

	

		Spry.Widget.setOptions(result, ss.panAndZoomInfo.pzSettings[slideIndex]);

	

		// If the element had no pan and zoom settings, pick a random

		// set from the defaults.

	

		if (typeof result.x1 == "undefined")

		{

			var pzs = gPZP.config.defaultPanZoomSettings[Math.round(Math.random() * (gPZP.config.defaultPanZoomSettings.length - 1))];

	

			result.x1 = pzs[0];

			result.y1 = pzs[1];

			result.z1 = pzs[2];

			result.x2 = pzs[3];

			result.y2 = pzs[4];

			result.z2 = pzs[5];

		}

	

		return result;

	},



	getCenteredClippedViewRect: function(x, y, iw, ih, vw, vh)

	{

		var hvw = vw / 2;

		var hvh = vh / 2;

	

		var vx = x - hvw;

		var vy = y - hvh;

	

		var vx2 = x + hvw;

		var vy2 = y + hvh;

	

		var pos = { x: vx, y: vy };

	

		if (vx < 0)

			pos.x = 0;

		else if (vx2 > iw)

			pos.x = iw - vw;

	

		if (vy < 0)

			pos.y = 0;

		else if (vy2 > ih)

			pos.y = ih - vh;

	

		return { x: pos.x, y: pos.y, w: vw, h: vh };

	},





	setupSlide: function(ss, slide, slideIndex)

	{

		if (!ss || !slide)

			return;

	

		// Get the dimensions of the clip view.

	

		var clip = Spry.$$("." + ss.clipClass, ss.element)[0];

		var cw = clip.offsetWidth;

		var ch = clip.offsetHeight;

	

		// Now get the original dimensions of the image

		// in the current slide and calculate the ratio

		// that will cause the image to minimally fill up

		// the clip view area.

	

		var ele = Spry.$$("img", slide)[0];

	

		var kb = gPZP.getPanZoomSettings(ss, slideIndex);

	

		var iw = kb.width;

		var ih = kb.height;

	

		var ratio = gPZP.fitAtoBRatio(iw, ih, cw, ch);

	

		if (ss.isInPlayMode())

		{

			var startZoom = ratio * kb.z1 / 100;

			var endZoom   = ratio * kb.z2 / 100;

		

			var sw = iw * startZoom;

			var sh = ih * startZoom;

			var sx = sw * kb.x1 / 100;

			var sy = sh * kb.y1 / 100;

		

			var startRect = gPZP.getCenteredClippedViewRect(sx, sy, sw, sh, cw, ch);

		

			var ew = iw * endZoom;

			var eh = ih * endZoom;

			var ex = ew * kb.x2 / 100;

			var ey = eh * kb.y2 / 100;

		

			var endRect = gPZP.getCenteredClippedViewRect(ex, ey, ew, eh, cw, ch);

		

			ele.style.width  = sw + "px";

			ele.style.height = sh + "px";

			ele.style.left   = -startRect.x + "px";

			ele.style.top    = -startRect.y + "px";

	

			var anim = new Spry.Effect.CSSAnimator(ele, "top: " + (-endRect.y) + "px; left: " + (-endRect.x) + "px; width: " + ew + "px; height: " + eh + "px;", { dropFrames: ss.dropFrames, duration: ss.displayInterval + (ss.transitionDuration) });

			gPZP.addAnimation(ss, anim);

			anim.start();

		}

		else

		{

			if (iw > cw || ih > ch)

			{

				var ratio = gPZP.fitAtoBRatio(cw, ch, iw, ih);

	

				iw = Math.round(iw / ratio);

				ih = Math.round(ih / ratio);

			}

	

			ele.style.width = iw + "px";

			ele.style.height = ih + "px";

			ele.style.left = Math.round((cw - iw) / 2) + "px";

			ele.style.top = Math.round((ch - ih) / 2) + "px";

		}

	},



	onPostShowSlide: function(ss, evt)

	{

		if (evt.slideIndex >= 0)

			gPZP.setupSlide(ss, evt.target, evt.slideIndex);

	}

};



})(); // EndSpryComponent


