/*
Animated GIF FrameViewer
Version: 0.9
Copyright (c) 2010 - Lucas Vieira
http://toxicdump.org/
*/
var FrameViewer = {
	config: {
		className: 'frameviewer',
		hideDelay: 100,
		unitSize: 15,
		backgroundColor: "#5D4E3C",
		borderColor: "#907B63",
		textColor: "#DFB985",
		useControlsAbove: false,
		fixInterpolation: true,
		service: "http://toxicdump.org/pixelart/tools/frameviewer/",
		skin: "http://toxicdump.org/pixelart/tools/frameviewer/buttons.png"
	},
	useZoom: false,
	browser: null,
	instances: null,
	images: null,
	tools: {
		hasClass: function(obj) {
			if (typeof(ForceFrameViewer) != 'undefined') return true;
			var FM = FrameViewer;
			var classes = obj.className.split(" "), c;
			for(c in classes) {
				if (classes[c].toLowerCase() == FM.config.className.toLowerCase()) return true;
			}
			return false;
		},
		addEvent: function(obj,type,fn) {
			if (obj.attachEvent) {
				obj['e'+type+fn] = fn;
				obj[type+fn] = function(){obj['e'+type+fn]( window.event );}
				obj.attachEvent( 'on'+type, obj[type+fn] );
			} else {
				obj.addEventListener( type, fn, false );
			}
		},
		getAbsolutePosition: function(obj) {
			var pos = [0,0];
			while (obj != document.body) {
				pos[0] += obj.offsetLeft;
				pos[1] += obj.offsetTop;
				obj = obj.offsetParent;
			}
			return pos;
		},
		detectBrowser: function() {
			FrameViewer.browser = {
				ie: /msie/i.test(navigator.userAgent) && !/opera/i.test(navigator.userAgent),
				ie6: !(typeof document.body.style.maxHeight != "undefined"),
				ie7: !(navigator.appVersion.indexOf("MSIE 7.")==-1),
				fx: /Firefox[\/\s](\d+\.\d+)/.test(navigator.userAgent)
			}
		}
	},
	init: function() {
		if (!document.body) {
			setTimeout("FrameViewer.init()",50);
			return;
		}
		
		var FM = FrameViewer, i;
		if (FM.instances) return;
		
		FM.tools.detectBrowser();
		
		/* Disable FrameViewer if in IE6 or IE7: fuck that shit! */
		if (FM.browser.ie6 || FM.browser.ie7) return;
		
		if (typeof(FrameViewerConfig) == 'object') {
			for(i in FrameViewerConfig) {
				FM.config[i] = FrameViewerConfig[i];
			}
		}
		FM.useZoom = (typeof(zoomImg) == 'function');
		
		var imgs = document.body.getElementsByTagName('img');
		
		FM.instances = [];
		FM.images = {};
		
		for(i = 0;i < imgs.length;i++) {
			if ((FM.tools.hasClass(imgs[i])) && (imgs[i].src.split(".").pop().toLowerCase() == 'gif')) FM.addImage(imgs[i]);
		}
	},
	addImage: function(img) {
		var FM = FrameViewer;
		
		var box = document.createElement('div');
		box.id = 'FrameViewer-'+FM.instances.length;
		box.style.display = 'inline-block';
		box.style.position = 'relative';
		
		img.parentNode.insertBefore(box,img);
		box.appendChild(img);
		
		FM.tools.addEvent(box,'mouseover',FrameViewer.mouseOver);
		FM.tools.addEvent(box,'mouseout',FrameViewer.mouseOut);
		
		// Handle native zoom actions
		if (FM.useZoom) FM.tools.addEvent(box,'click',FrameViewer.handleNativeZoom);
		
		if (FM.config.fixInterpolation) {
			if (FM.browser.fx) img.style.setProperty("image-rendering","-moz-crisp-edges","");
			if (FM.browser.ie) img.style.msInterpolationMode = "nearest-neighbor";
		}
		
		FM.instances.push({
			object: box,
			ctrls: null,
			pos: null,
			image: img,
			imageStyle: img.style,
			window: null,
			frames: null,
			src: img.src,
			zoom: 1,
			cur: 0,
			active: false,
			timer: null,
			disabled: false
		});
		
		FM.images[img.src] = {
			state: null
		};
	},
	mouseOver: function(e) {
		var FM = FrameViewer;
		
		var id = parseInt(this.id.split("-").pop());
		
		if (!FM.instances[id]) return;
		if (FM.instances[id].ctrls) {
			clearTimeout(FM.instances[id].timer);
			return;
		}
		
		var ctrls = document.createElement('div');
		ctrls.style.color = FM.config.textColor;
		ctrls.style.border = "1px solid "+FM.config.borderColor;
		ctrls.style.backgroundColor = FM.config.backgroundColor;
		ctrls.style.position = 'absolute';
		ctrls.style.width = (FM.config.unitSize*6)+'px';
		ctrls.style.height = FM.config.unitSize+'px';
		
		FM.tools.addEvent(ctrls,'mouseover',FrameViewer.mouseOverControls);
		FM.tools.addEvent(ctrls,'mouseout',FrameViewer.mouseOut);
		
		ctrls.id = "FrameViewerControls-"+id;
		ctrls.style.textAlign = 'center';
		ctrls.style.fontSize = '10px';
		ctrls.style.fontFamily = "sans-serif";
		ctrls.style.lineHeight = FM.config.unitSize+'px';
		ctrls.style.zIndex = 99999;
		
		document.body.appendChild(ctrls);
		
		FM.instances[id].ctrls = ctrls;
		
		FM.updateCtrlsPos(id);
		FM.updateControls(id);
		
	},
	mouseOut: function(e) {
		var FM = FrameViewer;
		var id = parseInt(this.id.split("-").pop());
		if (!FM.instances[id]) return;
		FM.instances[id].timer = setTimeout("FrameViewer.hideControls("+id+");",FM.config.hideDelay);
	},
	mouseOverControls: function(e) {
		var FM = FrameViewer;
		var id = parseInt(this.id.split("-").pop());
		if (!FM.instances[id]) return;
		if (FM.instances[id].ctrls) {
			clearTimeout(FM.instances[id].timer);
			return;
		}
	},
	updateCtrlsPos: function(id) {
		var FM = FrameViewer;
		var pos = FM.tools.getAbsolutePosition(FM.instances[id].object);
		if (!FM.instances[id].ctrls) return;
		var ctrls = FM.instances[id].ctrls;
		pos[0] = Math.floor(pos[0]+(FM.instances[id].object.offsetWidth/2)-(FM.config.unitSize*3)-1);
		pos[1] = (pos[1]+(FM.config.useControlsAbove?-(FM.config.unitSize+2):FM.instances[id].object.offsetHeight));
		if (pos[0] < 0) pos[0] = 0;
		ctrls.style.left = pos[0]+"px";
		ctrls.style.top = pos[1]+"px";
	},
	handleNativeZoom: function(e) {
		var FM = FrameViewer;
		var id = parseInt(this.id.split("-").pop());
		FM.updateCtrlsPos(id);
	},
	hideControls: function(id) {
		var FM = FrameViewer;
		var ctrls = FM.instances[id].ctrls;
		ctrls.parentNode.removeChild(ctrls);
		ctrls = null;
		FM.instances[id].ctrls = null;
	},
	activate: function(id) {
		var FM = FrameViewer;
		
		FM.instances[id].active = true;
		FM.loadFrames(id);
		
	},
	loadFrames: function(id) {
		var FM = FrameViewer;
		var state = FM.images[FM.instances[id].src].state;
		if (state == 'ready') {
			FM.updateControls(id);
			FM.replaceImage(id);
		} else if (state == null) {
			FM.images[FM.instances[id].src].state = 'loading';
			
			var l = document.createElement('script');
			l.type = 'text/javascript';
			l.src = FM.config.service+"?id="+id+"&url="+escape(FM.instances[id].src);
			document.body.appendChild(l);
			
			FM.updateControls(id);
		} else if (state == 'downloading') {
			FM.updateControls(id);
		}
	},
	getFrames: function(id) {
		var FM = FrameViewer;
		var url = FM.instances[id].src;
		
		FM.images[url].state = "downloading";
		FM.updateControls(id);
		
		FM.images[url].image = new Image();
		FM.images[url].image.src = FM.images[url].frames;
		FM.images[url].timer = setTimeout("FrameViewer.checkImage(\""+url+"\");",100);
		
	},
	noFrames: function(id) {
		var FM = FrameViewer;
		var url = FM.instances[id].src;
		FM.images[url].state = "static";
		FM.instances[id].disabled = true;
		FM.updateControls(id);
	},
	tooBig: function(id) {
		var FM = FrameViewer;
		var url = FM.instances[id].src;
		FM.images[url].state = "toobig";
		FM.instances[id].disabled = true;
		FM.updateControls(id);
	},
	error: function(id) {
		var FM = FrameViewer;
		var url = FM.instances[id].src;
		FM.images[url].state = "error";
		FM.instances[id].disabled = true;
		FM.updateControls(id);
	},
	checkImage: function(img) {
		var FM = FrameViewer;
		if (FM.images[img].image.complete) {
			FM.images[img].state = "ready";
			FM.updateAllControls(img);
			FM.replaceAllImages(img);
		} else {
			FM.images[img].timer = setTimeout("FrameViewer.checkImage(\""+img+"\");",100);
		}
	},
	updateAllControls: function(img) {
		var FM = FrameViewer;
		for (var i = 0; i < FM.instances.length;i++) {
			if (FM.instances[i].src == img) {
				FM.updateControls(i);
			}
		}
	},
	replaceAllImages: function(img) {
		var FM = FrameViewer;
		for (var i = 0; i < FM.instances.length;i++) {
			if (FM.instances[i].src == img) {
				FM.replaceImage(i);
			}
		}
	},
	replaceImage: function(id) {
		var FM = FrameViewer, o;
		if (FM.instances[id].active) {
			
			
			FM.instances[id].image.style.display = "none";
			
			var url = FM.instances[id].src;
			if (FM.images[url].state != "ready") {
				FM.images[url].state = "error";
				FM.updateControls(id);
				return;
			}
			
			// Irrelevant use of the floor function. A weird fix for some idiotic bug in Chrome.
			if (FM.useZoom) {
				FM.instances[id].zoom = Math.floor(FM.instances[id].image.width / FM.images[url].size[0]);
				var z = Math.floor(FM.instances[id].image.width / FM.images[url].size[0]);
				FM.instances[id].zoom = z;
			} else {
				FM.instances[id].zoom = 1;
			}

			
			o = document.createElement('div');
			o.style.position = 'relative';
			o.style.display = "inline-block";
			o.style.width = (FM.images[url].size[0] * FM.instances[id].zoom)+"px";
			o.style.height = (FM.images[url].size[1] * FM.instances[id].zoom)+"px";
			o.style.maxWidth = o.style.width;
			o.style.maxHeight = o.style.height;
			o.style.overflow = 'hidden';
			FM.instances[id].object.appendChild(o);
			FM.instances[id].window = o;
			
			
			var img = FM.images[url].image.cloneNode(false);
			img.style.position = 'absolute';
			img.id = "FrameViewerFrames-"+id;
			img.style.width = (FM.instances[id].zoom * FM.images[url].size[0] * FM.images[url].divs[0])+"px";
			img.style.height = (FM.instances[id].zoom * FM.images[url].size[1] * FM.images[url].divs[1])+"px";
			img.style.maxWidth = img.style.width;
			img.style.maxHeight = img.style.height;

			if (FM.config.fixInterpolation) {
				if (FM.browser.fx) img.style.setProperty("image-rendering","-moz-crisp-edges","");
				if (FM.browser.ie) img.style.msInterpolationMode = "nearest-neighbor";
			}
			
			FM.tools.addEvent(img,'click',FrameViewer.handleFrameZoom);
			
			FM.instances[id].window.appendChild(img);
			FM.instances[id].frames = img;
			FM.updateFrame(id);
		} else {
			FM.instances[id].image.style.display = "";
			FM.instances[id].window.removeChild(FM.instances[id].frames);
			FM.instances[id].frames = null;
			FM.instances[id].object.removeChild(FM.instances[id].window);
			FM.instances[id].window = null;
			FM.hideControls(id);
		}
	},
	handleFrameZoom: function(e) {
		if (typeof(zoomImg) == 'function') {
			var FM = FrameViewer,
				id = parseInt(this.id.split("-").pop());
			
			if (document.createEvent) {
				var evObj = document.createEvent('MouseEvents');
				evObj.initMouseEvent('click',true,false,window,0,0,0,0,0,e.ctrlKey,e.altKey,e.shiftKey,false,0,null);
				FM.instances[id].image.dispatchEvent(evObj);
			} else if (document.createEventObject) {
				var evObj = document.createEventObject();
				evObj.ctrlKey = e.ctrlKey;
				evObj.shiftKey = e.shiftKey;
				evObj.altKey = e.altKey;
				FM.instances[id].image.fireEvent('onclick',evObj);
			}
			FM.updateFrameZoom(id);
		}
	},
	updateFrameZoom: function(id) {
		var FM = FrameViewer,
			img = FM.instances[id].frames,
			url = FM.instances[id].src,
			win = FM.instances[id].window;
		
		// IE doesn't update the image width unless it's visible. Quick fix.
		if (FM.browser.ie) FM.instances[id].image.style.display = "";
		FM.instances[id].zoom = Math.floor(FM.instances[id].image.width / FM.images[url].size[0]);
		if (FM.browser.ie) FM.instances[id].image.style.display = "none";
		
		img.style.width = (FM.instances[id].zoom * FM.images[url].size[0] * FM.images[url].divs[0])+"px";
		img.style.height = (FM.instances[id].zoom * FM.images[url].size[1] * FM.images[url].divs[1])+"px";
		win.style.width = (FM.images[url].size[0] * FM.instances[id].zoom)+"px";
		win.style.height = (FM.images[url].size[1] * FM.instances[id].zoom)+"px";
		
		img.style.maxWidth = img.style.width;
		img.style.maxHeight = img.style.height;
		win.style.maxWidth = win.style.width;
		win.style.maxHeight = win.style.height;
		
		FM.updateFrame(id);
	},
	updateControls: function(id) {
		var FM = FrameViewer,
			ctrls = FM.instances[id].ctrls,
			o;
		
		if (!ctrls) return;
		
		while (ctrls.firstChild) {
			o = ctrls.firstChild;
			ctrls.removeChild(o);
			o = null;
		}
		
		if (FM.instances[id].active) {
			var state = FM.images[FM.instances[id].src].state;
			if (state == "static") {
				o = document.createTextNode('image is static');
				ctrls.appendChild(o);
			} else if (state == "toobig") {
				o = document.createTextNode('image is too big');
				ctrls.appendChild(o);
			} else if (state == "error") {
				o = document.createTextNode('failed :(');
				ctrls.appendChild(o);
			} else if (state == 'ready') {
				o = FM.addButton(id);
				o.href = "javascript:FrameViewer.prevFrame("+id+");";
				o.style.left = "0"; o.style.top = "0";
				o.style.backgroundPosition = "0 0";
				o.title = "Previous frame";
				ctrls.appendChild(o);
			
				o = FM.addButton(id);
				o.href = "javascript:FrameViewer.nextFrame("+id+");";
				o.style.left = FM.config.unitSize+"px"; o.style.top = "0";
				o.style.backgroundPosition = (-FM.config.unitSize)+"px 0";
				o.title = "Next frame";
				ctrls.appendChild(o);
				
				o = FM.addButton(id);
				o.href = "javascript:FrameViewer.deactivate("+id+");";
				o.style.left = (FM.config.unitSize*5)+"px"; o.style.top = "0";
				o.style.backgroundPosition = (-FM.config.unitSize*4)+"px 0";
				o.title = "Restore animation";
				ctrls.appendChild(o);
				
				/* COMING SOON: Settings!
				o = FM.addButton(id);
				o.href = "javascript:FrameViewer.settings();";
				o.style.left = (FM.config.unitSize*6)+"px"; o.style.top = "0";
				o.style.backgroundPosition = (-FM.config.unitSize*5)+"px 0";
				o.title = "Settings";
				ctrls.appendChild(o);
				*/
				
				o = document.createElement('div');
				o.style.position = 'absolute';
				o.style.left = (FM.config.unitSize*2)+"px"; o.style.top = "0";
				o.style.width = (FM.config.unitSize*3)+"px"; o.style.height = FM.config.unitSize+"px";
				o.style.fontFamily = "monospace";
				o.style.fontSize = "10px";
				o.style.color = FM.config.textColor;
				FM.instances[id].pos = o;
				ctrls.appendChild(o);
				FM.updatePosition(id);
				
				
			} else if (state == 'loading') {
				o = document.createTextNode('processing...');
				ctrls.appendChild(o);
			} else if (state == 'downloading') {
				o = document.createTextNode('loading...');
				ctrls.appendChild(o);
			}
		} else {
			o = document.createElement('a');
			o.style.color = FM.config.textColor;
			o.style.textDecoration = "none";
			o.innerHTML = 'view frames';
			o.href = 'javascript:FrameViewer.activate('+id+')';
			ctrls.appendChild(o);
		}
	
	},
	addButton: function(id) {
		var FM = FrameViewer,
			ctrls = FM.instances[id].ctrls,
			o;
		
		o = document.createElement('a');
		
		o.style.display = "block";
		o.style.height = o.style.width = FM.config.unitSize+"px";
		o.style.position = "absolute";
		o.style.outline = "none";
		o.style.backgroundImage = "url('"+FM.config.skin+"')";
		
		return o;
	},
	updatePosition: function(id) {
		var FM = FrameViewer;
		if (FM.instances[id].pos) {
			var pos = FM.instances[id].pos,
				url = FM.instances[id].src;
			pos.innerHTML = (FM.instances[id].cur+1)+"/"+FM.images[url].num;
		}
	},
	prevFrame: function(id) {
		var FM = FrameViewer;
		FM.instances[id].cur--;
		if (FM.instances[id].cur < 0) FM.instances[id].cur += FM.images[FM.instances[id].src].num;
		FM.updateFrame(id);
	},
	nextFrame: function(id) {
		var FM = FrameViewer;
		FM.instances[id].cur++;
		if (FM.instances[id].cur >= FM.images[FM.instances[id].src].num) FM.instances[id].cur -= FM.images[FM.instances[id].src].num;
		FM.updateFrame(id);
	},
	updateFrame: function(id) {
		var FM = FrameViewer;
		var url = FM.instances[id].src;
		FM.instances[id].frames.style.left = -(FM.instances[id].cur % FM.images[url].divs[0] * FM.images[url].size[0] * FM.instances[id].zoom)+"px";
		FM.instances[id].frames.style.top = -(Math.floor(FM.instances[id].cur / FM.images[url].divs[0]) * FM.images[url].size[1] * FM.instances[id].zoom)+"px";
		FM.updatePosition(id);
	},
	deactivate: function(id) {
		var FM = FrameViewer;
		FM.instances[id].active = false;
		FM.replaceImage(id);
	}
}
if (window.addEventListener) {  
	window.addEventListener('load',FrameViewer.init,false);
} else {
	window.attachEvent('onload',FrameViewer.init);
};
if (document.body) FrameViewer.init();
