var kDefaultMagnifierSize = 2; // index into the arrays below
var kMagnifierSizes = new Array(0, 100, 150, 300);
var kMagnifierSizeNames = new Array('off', 'small', 'medium', 'large');
var kControllerPrefix = 'magnifier:&nbsp;';
var kShadowPadding = 14;
var kDefaultMagnifierOffsetX = .9;
var kDefaultMagnifierOffsetY = .8;

function MagnifierPosition()
{	
	this.style.left = Math.round(this.xPosition - 1 - this.size/2) + "px"; // -1 to account for the border
	this.style.top = Math.round(this.yPosition - 1 - this.size/2) + "px";
    
	this.shadow.style.left = Math.round(this.xPosition - this.size/2 - kShadowPadding) + "px";
	this.shadow.style.top = Math.round(this.yPosition - this.size/2 - kShadowPadding) + "px";
    
	var magnifierCenterX = Math.round((GetElementLeft(this.normalImage) - this.xPosition) * this.xMultiplier + this.size/2);
	var	magnifierCenterY = Math.round((GetElementTop(this.normalImage)  - this.yPosition) * this.yMultiplier + this.size/2);

	this.style.backgroundPosition = ( magnifierCenterX) + "px " +
									( magnifierCenterY) + "px";
}

function ControllerSizeButtonClick(event)
{
	if (!event) event = window.event;
    
	var button = event.currentTarget || event.srcElement;
    
	button.parentNode.magnifier.resize(button.magnifierSize);
}

function MagnifierResize(size)
{
	this.size = kMagnifierSizes[size];
	this.snapToEdge();
    
	for (var i=0; i < this.controller.sizeButtons.length; i++)
	{
		if (i == size)
			this.controller.sizeButtons[i].className = "magnifierControllerButtonSelected";
		else
			this.controller.sizeButtons[i].className = "magnifierControllerButton";
	}
    
	if (this.size == 0)
	{
		this.shadow.style.display = "none";
		this.style.display = "none";
	}
	else
	{
		var shadow = this.shadow;
		var shadowSize = this.size + 2 * kShadowPadding;
    	
		// MSIE 5.x/6.x must be treated specially in order to make them use the PNG alpha channel
		var shadowImageSrc = "http://www.photility.com/MagnifierSample/shadow" + size + ".PNG";
		if (shadow.runtimeStyle)
			shadow.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" +
											shadowImageSrc +
											"', sizingMethod='scale')";
		else
			shadow.style.backgroundImage = "url(" + shadowImageSrc + ")";
		
		shadow.style.width = shadowSize + "px";
		shadow.style.height = shadowSize + "px";
		shadow.style.display = "block";
    	
		if (this.runtimeStyle)  // msie counts the border as being part of the width
			this.size += 2*this.style.borderWidth;     // must compensate
    	
		this.style.width = this.size + "px";
		this.style.height = this.size + "px";
		this.style.display = "block";

		this.position();
	}
}

function MagnifierMouseDown(event)
{
	if (!event) event = window.event;
    
	document.body.magnifier = this;
	this.inDrag = true;
	if (event.pageX)
	{
		this.startX = event.pageX;
		this.startY = event.pageY;
	}
	else if (event.clientX)
	{
		this.startX = event.clientX;
		this.startY = event.clientY;
	}
	else
	{
		alert("don't know how to get position out of event");
		return;
	}

	this.style.cursor = "default";
}

function MagnifierMouseUp()
{
    var magnifier = this.magnifier; // we're actually in the body's onmousemove handler

	if (magnifier != null && magnifier.inDrag)
	{
		magnifier.inDrag = false;
		magnifier.style.cursor = "move";
		magnifier = null;
	}
}

function SnapToEdge()
{
    var imageLeft = GetElementLeft(this.normalImage);
    var imageRight = imageLeft + this.normalImage.width;
    var imageTop = GetElementTop(this.normalImage);
    var imageBottom = imageTop + this.normalImage.height;
    
    if (this.xPosition > imageRight ||
        (this.xPosition + this.size) < imageLeft || 
        this.yPosition > imageBottom ||
        (this.yPosition + this.size) < imageTop)
    {
        this.xPosition = imageLeft + (this.offsetX) * this.normalImage.width;
    	this.yPosition = imageTop  + (this.offsetY) * this.normalImage.height;
    	this.position();
    }
}

function MagnifierDrag(event)
{
	if (!event) event = window.event;
	var magnifier = this.magnifier; // we're actually in the body's onmousemove handler
    
	if (magnifier && magnifier.inDrag)
	{
	    if (event.button != 1)
	    {
	        MagnifierMouseUp();
	        return;
	    }

		var eventX;
		var eventY;
    	
		if (event.pageX)
		{
			eventX = event.pageX;
			eventY = event.pageY;
		}
		else if (event.clientX)
		{
			eventX = event.clientX;
			eventY = event.clientY;
		}
		else
		{
			return;
		}
    	
    	magnifier.xPosition = magnifier.xPosition + eventX - magnifier.startX;
    	magnifier.yPosition = magnifier.yPosition + eventY - magnifier.startY;
    
		magnifier.startX = eventX;
		magnifier.startY = eventY;
    	
		magnifier.position();
      	}
}

function loadMagnifier(baseID, zoomedURL, magnifierSize, offsetX, offsetY)
{
	// get the divs
	var magnifier = document.createElement("div");
	var base = document.getElementById(baseID);

	// get the regular image
	magnifier.normalImage = null;
	for (var i=0; i < base.childNodes.length; i++)
	{
		if (base.childNodes[i].tagName &&
			base.childNodes[i].tagName.toLowerCase() == "img")
		{
			magnifier.normalImage = base.childNodes[i];
			break;
		}
	}
    
	if (magnifier.normalImage == null)
	{
		//alert("couldn't find normal image for magnifier " + baseID);
		return;
	}

	// get the zoomed image (load as early as possible)
	if (zoomedURL == null) zoomedURL = magnifier.normalImage.src
	zoomedImage = document.createElement("img");
	zoomedImage.src = zoomedURL;

    // handle default parameters
    if (magnifierSize == null) magnifierSize = kDefaultMagnifierSize;
    magnifier.offsetX = (offsetX == null) ? kDefaultMagnifierOffsetX : offsetX;
    magnifier.offsetY = (offsetY == null) ? kDefaultMagnifierOffsetY : offsetY;
        	
	magnifier.xMultiplier = zoomedImage.width / magnifier.normalImage.width;
	magnifier.yMultiplier = zoomedImage.height / magnifier.normalImage.height;
	magnifier.size = kMagnifierSizes[magnifierSize];
	magnifier.xPosition = GetElementLeft(magnifier.normalImage) + (magnifier.offsetX) * magnifier.normalImage.width  ;
	magnifier.yPosition = GetElementTop(magnifier.normalImage)  + (magnifier.offsetY) * magnifier.normalImage.height ;
	magnifier.id = baseID + "Magnifier";
	magnifier.className = "magnifier";
    
	//
	// styles (only dynamic ones, rest are part of the class)
	//
	magnifier.style.backgroundImage = "url(" + zoomedURL + ")";
    magnifier.style.cursor = "move";
    magnifier.style.position = "absolute";
    magnifier.style.backgroundRepeat = "no-repeat";
    
    //
	// functions
	//
	magnifier.position = MagnifierPosition;
	magnifier.resize = MagnifierResize;
	magnifier.onmousedown = MagnifierMouseDown;
	magnifier.snapToEdge = SnapToEdge;
    // we attach the handlers to the body because if the user moves
    // the mouse fast enough, it'll go outside the boundaries of the
    // magnifier, and then the magnifier's mousemove handler won't fire
	document.body.onmouseup = MagnifierMouseUp;
	document.body.onmousemove = MagnifierDrag;  
    
    //
	// controller
	//
	var controller = document.createElement("span");
	controller.id = baseID + "MagnifierController";
	controller.className = "magnifierController";
	var controllerPrefix = document.createElement("span");
	controllerPrefix.innerHTML = kControllerPrefix;
	controllerPrefix.className = "magnifierControllerPrefix";
	controller.appendChild(controllerPrefix);
	controller.sizeButtons = new Array(kMagnifierSizes.length);

	for (var i=0; i < kMagnifierSizes.length; i++)
	{
		var button = document.createElement("span");
		button.innerHTML = kMagnifierSizeNames[i];
		button.className = "magnifierControllerButton";
		button.onclick = ControllerSizeButtonClick;
		button.magnifierSize = i;
    	
		controller.sizeButtons[i] = button;
		controller.appendChild(button);
	}
    
	//
	// shadow
	//
	var shadow = document.createElement("div");
	shadow.id = baseID + "MagnifierShadow";
	shadow.className = "magnifierShadow";
	shadow.style.position = "absolute";
    
    //
	// point objects at each other
	//
	magnifier.controller = controller;
	controller.magnifier = magnifier;
	magnifier.shadow = shadow;
    
	//
	// add to document and lay out
    //
	var controllerContainer = document.createElement("div");
	controllerContainer.className = "magnifierControllerContainer";
	controllerContainer.appendChild(controller);
	base.insertBefore(controllerContainer);
	base.appendChild(shadow);
	base.appendChild(magnifier);
	magnifier.resize(magnifierSize); // also positions
}

function GetElementLeft(eElement)
{
    var nLeftPos = eElement.offsetLeft;          // initialize var to store calculations
    var eParElement = eElement.offsetParent;     // identify first offset parent element  
    while (eParElement != null)
    {                                            // move up through element hierarchy
        nLeftPos += eParElement.offsetLeft;      // appending left offset of each parent
        eParElement = eParElement.offsetParent;  // until no more offset parents exist
    }
    return nLeftPos;                             // return the number calculated
}

function GetElementTop(eElement)
{
    var nTopPos = eElement.offsetTop;            // initialize var to store calculations
    var eParElement = eElement.offsetParent;     // identify first offset parent element  
    while (eParElement != null)
    {                                            // move up through element hierarchy
        nTopPos += eParElement.offsetTop;        // appending top offset of each parent
        eParElement = eParElement.offsetParent;  // until no more offset parents exist
    }
    return nTopPos;                              // return the number calculated
}
