function log () {
	try {
		console.log.apply(this, arguments);
	} catch (e) {}
}

/* SETTABLE */
var MARGIN = 150; // pixels added around edges of dragliner / zoom
var SIZES = [[72, 5]];
var ZOOM = 10; // SIZES[1][0] / SIZES[0][0];
var OVERVIEWREDUCE = 5; /* factor to reduce sizes[0] to the overview */

/* CALCULATED FROM ABOVE */
SIZES.push([SIZES[0][0] * ZOOM, SIZES[0][1] * ZOOM]);
var ZMARGIN = ZOOM * MARGIN;
var imagesize = SIZES[0][0];
var bordersize = SIZES[0][1];
var cellsize = imagesize + bordersize;
var zimagesize = imagesize * ZOOM;
var zbordersize = bordersize * ZOOM;
var zcellsize = cellsize * ZOOM;

var zoomed = false;
var imgidstoload = new Array();
var groups;
var imageDataById = {};

function onLoadImageDone(e) {
	// console.log("onLoadImageDone");
	if (imgidstoload.length > 0) {
		checkForImagesToLoad();
	} else {
		// log("done loading images");
	}
}


function isimageonscreen (id) {
	if (!zoomed) return false;
	var z = $('zoom');
	var ox = -parseInt(z.style.left);
	var oy = -parseInt(z.style.top);
	var ww = getWindowWidth();
	var wh = getWindowHeight();
// 	console.log("origin: ", ox+","+oy+":"+ww+"x"+wh);
	var imgdata = imageDataById[id];
	var zelt = imgdata.zoomdiv
// 	console.log("zoomdiv", zelt, zelt.parentNode);
	var zx = parseInt(zelt.parentNode.style.left) + parseInt(zelt.style.left);
	var zy = parseInt(zelt.parentNode.style.top) + parseInt(zelt.style.top);
	var zw = zimagesize;
	var zh = zimagesize;
// 	console.log("image: ", zx+","+zy+":"+zw+"x"+zh);
	return (((zx + zw) > ox) && ((zy + zh) > oy) &&
	        (zx < (ox + ww)) && (zy < (oy + wh)));
}

function checkForImagesToLoad () {
	if (!zoomed) return;
	if (imgidstoload.length == 0) return;
	// console.log("checkForImagesToLoad", imgidstoload.length);

	for (var i=0; i<imgidstoload.length; i++) {
		var imgid = imgidstoload[i];
		if (isimageonscreen(imgid)) {
			// remove item from list
			// imgidstoload.splice(i, 1);

			// load it
			loadImage(imgid);
			return;
		}
	}
	// not now? try again later
	window.setTimeout(checkForImagesToLoad, 1000);
}
// window.setInterval(checkForImagesToLoad, 1000);

function removeItem (list, thing) {
	for (var i=0; i<list.length; i++) {
		if (list[i] == thing) {
			list.splice(i, 1);
			return true;
		}
	}
	return false;
}

function loadImage (id) {
/*	console.log("loadImage", id);*/
	var idata = imageDataById[id];
	var zdiv = idata.zoomdiv;
	var group = idata.group;
	var imgsrc = idata.imgsrc;
	zdiv.className = "image";
	idata.zoomimg.onload = onLoadImageDone;
	idata.zoomimg.src = "imagesizer.php?w="+zimagesize+"&h="+zimagesize+"&src=" + group.path + "/" + imgsrc;
	removeItem(imgidstoload, id);
	// data.zoomimg.border = "0";
}

function setZoomed (z, imgid) {
	if (zoomed == z) return;
	zoomed = z;

	$('zoomout').style.visibility = zoomed ? 'visible' : 'hidden';

	var d = $('dragliner');
	var z = $('zoom');

	var ww = getWindowWidth();
	var wh = getWindowHeight();

	if (scrollToIntervalID) {
		window.clearInterval(scrollToIntervalID);
		scrollToIntervalID = undefined;
	}

	if (zoomed) {
		// going unzoomed to zoomed
		// set zoom layer position based on dragliner
		// use zoomElement

		var d = $('dragliner');
		var ox = -parseInt(d.style.left);
		var oy = -parseInt(d.style.top);

		var zelt = $(imgid);
		var zx = parseInt(zelt.parentNode.style.left) + parseInt(zelt.style.left);
		zx += (cellsize/2);
		var zy = parseInt(zelt.parentNode.style.top) + parseInt(zelt.style.top);
		zy += (cellsize/2);

//      SET POSITION SUCH THAT it stays where it was on screen
// 		var nox = (zx * ZOOM) + (ox - zx);
// 		var noy = (zy * ZOOM) + (oy - zy);

//		SET POSITION SO THAT IT BECOMES CENTERED ON THE SCREEN
		var nox = (zx * ZOOM) - (ww/2);
		var noy = (zy * ZOOM) - (wh/2);
 
		setScrollOrigin(Math.round(nox), Math.round(noy));
		d.style.visibility = "hidden";
		z.style.visibility = "visible";
		
		// IMAGE LOADING
		if (imgid) {
			var idata = imageDataById[imgid];
			if (idata.zoomdiv.className == "image_notloaded") {
				loadImage(imgid);
			} else {
				checkForImagesToLoad();
			}
		}

	} else {
		var zx = -parseInt(z.style.left);
		var zy = -parseInt(z.style.top);
		zx += (ww/2);
		zy += (wh/2);
		zx /= ZOOM;
		zy /= ZOOM;
		zx -= (ww/2);
		zy -= (wh/2);

		setScrollOrigin(Math.round(zx), Math.round(zy));

		$('dragliner').style.visibility = "visible";
		$('zoom').style.visibility = "hidden";
	}	
}

function imageOnMouseDown (evt) {
	var elt = Event.element(evt);
	var div = Event.findElement(evt, "div");
	imageClickPosX = Event.pointerX(evt);
	imageClickPosY = Event.pointerY(evt);
}

function imageOnClick (evt) {
	var elt = Event.element(evt);
	var div = Event.findElement(evt, "div");
	// log("imageOnClick", elt, div, div.id);
	var dx = Math.abs(Event.pointerX(evt) - imageClickPosX);
	var dy = Math.abs(Event.pointerY(evt) - imageClickPosY);
	// DO CLICK WHEN NOT DRAGGED
	if ((dx < 2) && (dy < 2)) {
		doImageClick(div.id);
	}
}

var imageClickPosX = undefined;
var imageClickPosY = undefined;

function zoomImageOnMouseDown (evt) {
	var elt = Event.element(evt);
	var div = Event.findElement(evt, "div");
	// log("imageOnClick", elt, div, div.id);
	// doImageClick(div.id.substr(1));
	
	imageClickPosX = Event.pointerX(evt);
	imageClickPosY = Event.pointerY(evt);
}

function zoomImageOnClick (evt) {
	var dx = Math.abs(Event.pointerX(evt) - imageClickPosX);
	var dy = Math.abs(Event.pointerY(evt) - imageClickPosY);
	// DO CLICK WHEN NOT DRAGGED
	if ((dx < 2) && (dy < 2)) {
		var elt = Event.element(evt);
		var div = Event.findElement(evt, "div");
		// log("imageOnClick", elt, div, div.id);
		doImageClick(div.id.substr(1));
	}
}

function doImageClick(id) {
	// log("doImageClick", id);
	if (!zoomed) {
		setZoomed(true, id);
	} else {
		// center on image
		var zelt = imageDataById[id].zoomdiv;
		var zx = parseInt(zelt.parentNode.style.left) + parseInt(zelt.style.left);
		zx += (zimagesize/2);
		var zy = parseInt(zelt.parentNode.style.top) + parseInt(zelt.style.top);
		zy += (zimagesize/2);
		zx -= (getWindowWidth()/2);
		zy -= (getWindowHeight()/2);
		// console.log("zx, zy", zx, zy);
		scrollTo(Math.round(zx), Math.round(zy));
		// setZoomed(false);
	}
}

function linerOnDrag () {
	if (scrollToIntervalID) {
		window.clearInterval(scrollToIntervalID);
		scrollToIntervalID = undefined;
	}
	updateCurrentFocus();
}

function zoomOnDrag () {
	if (scrollToIntervalID) {
		window.clearInterval(scrollToIntervalID);
		scrollToIntervalID = undefined;
	}
	updateCurrentFocus();
}

function init() {
	new Draggable("dragliner", { starteffect: undefined, onDrag: linerOnDrag, endeffect: undefined } );
	new Draggable("zoom", { starteffect: undefined, onDrag: zoomOnDrag, endeffect: undefined } );
    dolayout(groups);
}

function pathToGroupName (path) {
	// strip "f/"
	path = path.substr(2);
	return path.replace("/", "&gt;<br /> ");
}

var scrollToIntervalID = undefined;
var scrollToX = 0, scrollToY = 0;

function setScrollOrigin (x, y) {
	if (!zoomed) {
		var d = $('dragliner');
		d.style.left = -x + "px";
		d.style.top = -y + "px";
		updateCurrentFocus();
	} else {
		var z = $('zoom');
		z.style.left = -x + "px";
		z.style.top = -y + "px";
		updateCurrentFocus();
	}
}

function divhaspoint (d, x, y) {
	var dx = parseInt(d.style.left);
	var dy = parseInt(d.style.top);
	var dw = parseInt(d.style.width);
	var dh = parseInt(d.style.height);
	return ((x >= dx) && (x < (dx + dw)) && (y >= dy) && (y < (dy + dh)));
}

var curFocusGroup = null;
function setFocusGroup (fg) {
	if (curFocusGroup == fg) return;
	if (curFocusGroup != null) {
		// cleanup
		// curFocusGroup.div.style.background = null;
		curFocusGroup.overviewdiv.style.background = "#444";
	}
	curFocusGroup = fg;
	// log("focusGroup", fg);
	if (curFocusGroup != null) {
		// setup
		// console.log("setFocusGroup: " + fg.name + " / " + fg);
		// curFocusGroup.div.style.background = "blue";
		curFocusGroup.overviewdiv.style.background = "#888";
	}
}

function updateCurrentFocus () {
	// 1. calculate the current center point of the dragliner
	var d = zoomed ? $('zoom') : $('dragliner');
	var dx = -parseInt(d.style.left);
	var dy = -parseInt(d.style.top);
	var ww = getWindowWidth();
	var wh = getWindowHeight();
	var cx = Math.round(dx + (ww/2));
	var cy = Math.round(dy + (wh/2));
	// console.log("center pos: " + cx + "," + cy);
	var focusgroup = null;
	for (var i=0; i<groups.length; i++) {
		var g = groups[i];
		if (divhaspoint(zoomed ? g.zoomdiv : g.div, cx, cy)) {
			focusgroup = g;
			break;
		}
	}
	setFocusGroup(focusgroup);
}

function scrollToInterval () {
	// console.log("scrollToInterval");
	var d = zoomed ? $('zoom') : $('dragliner');
	var curx = -parseInt(d.style.left);
	var cury = -parseInt(d.style.top);
	var dx = (scrollToX - curx);
	var dy = (scrollToY - cury);
	if (Math.abs(dx) > 5 || Math.abs(dy) > 5) {
		var divx = 15; // Math.max(1, Math.abs(dx)/20);
		var stepx = (dx / divx);
		if (stepx != 0 && Math.abs(stepx) < 1) stepx = (dx < 0) ? -1 : 1;

		var divy = 15; // Math.max(1, Math.abs(dy)/20);
		var stepy = (dy / divy);
		if (stepy != 0 && Math.abs(stepy) < 1) stepy = (dy < 0) ? -1 : 1;
		setScrollOrigin(Math.round(curx + stepx), Math.round(cury + stepy));
	} else {
		setScrollOrigin(scrollToX, scrollToY);
		window.clearInterval(scrollToIntervalID);
		scrollToIntervalID = undefined;
	}
}

function scrollTo (x, y) {
	// console.log("myScrollTo", x +", "+y);
	scrollToX = x - 40;
	scrollToY = y - 20;
	if (scrollToIntervalID == undefined) {
		scrollToIntervalID = window.setInterval(scrollToInterval, 25);
	}
}

function groupForPath (path) {
	for (var g=0; g<groups.length; g++) {
		if (groups[g].path == path) return groups[g];
	}
}

function doGroupIconClick(grouppath) {
	// console.log("groupIconClick", grouppath);
	setZoomed(false);

	var g = groupForPath(grouppath);
	var gx = parseInt(g.div.style.left);
	var gy = parseInt(g.div.style.top);
	var gw = parseInt(g.div.style.width);
	var gh = parseInt(g.div.style.height);

	var sw = getWindowWidth();
	var sh = getWindowHeight();

	// center group horizontally on screen
	var newscrollleft = Math.round(gx + ((gw - sw)/2));
	// var newscrolltop = Math.round(gy + ((gh - sh)/2));
	// center group vertically -- but make sure top is visible
	// ie no more than the (gy - some border value)
	var newscrolltop = Math.min(gy - 20, Math.round(gy + ((gh - sh)/2)));
	scrollTo(newscrollleft, newscrolltop);
}

var groupIconCount = 0;
function groupIconOnClick (evt) {
	var div = Event.findElement(evt, "div");
	// log("groupIconOnClick", div, div.grouppath);
	doGroupIconClick(div.grouppath);
}

function createGroupOverview (group) {
	// console.log("createGroupOverview", group.path);
	var d = document.createElement("div");
	d.className = "groupicon";
	d.grouppath = group.path;
	d.id = "groupicon" + (++groupIconCount);
	var dp = document.createElement("p");
	dp.innerHTML = pathToGroupName(group.path);
	d.appendChild(dp);

	var rimagesize = SIZES[0][0] / OVERVIEWREDUCE;
	var rbordersize = SIZES[0][1] / OVERVIEWREDUCE;
	var rcellsize = rimagesize + rbordersize;

	d.style.left = ((group.col-1) * rcellsize) + "px";
	d.style.top = ((group.row-1) * rcellsize) + "px";
	d.style.width = (group.cols * rcellsize) + "px";
	d.style.height = (group.rows * rcellsize) + "px";

	$('overview').appendChild(d);
	Event.observe(d.id, "click", groupIconOnClick);
	group.overviewdiv = d;
}

function dolayout(g) {
	groups = g;
	var totalcols = 0;
	var totalrows = 0;
	var imgid = 1;

	for (var g=0; g<groups.length; g++) {
		var group = groups[g];
		// console.log("group", group.name);
		var groupdiv = document.createElement("div");

		group.div = groupdiv;
		groupdiv.obj = group;
		groupdiv.className = "group";
		groupdiv.style.left = MARGIN + ((group.col-1) * cellsize) + "px";
		groupdiv.style.top = MARGIN + ((group.row-1) * cellsize) + "px";
		groupdiv.style.width = (group.cols * cellsize)  + "px";
		groupdiv.style.height = (group.rows * cellsize) + "px";

		totalcols = Math.max(totalcols, group.col + group.cols - 1);
		totalrows = Math.max(totalrows, group.row + group.rows - 1);

		$('dragliner').appendChild(groupdiv);

		// CREATE GROUP OVERVIEW PALETTE
		createGroupOverview(group);

		// ZOOMED GROUP
		var zgroupdiv = document.createElement("div");

		group.zoomdiv = zgroupdiv;
		zgroupdiv.obj = group;
		zgroupdiv.className = "group";
		zgroupdiv.style.left = ZMARGIN + ((group.col-1) * zcellsize) + "px";
		zgroupdiv.style.top = ZMARGIN + ((group.row-1) * zcellsize) + "px";
		zgroupdiv.style.width = (group.cols * zcellsize) + "px";
		zgroupdiv.style.height = (group.rows * zcellsize) + "px";
		$('zoom').appendChild(zgroupdiv);

		// PLACE IMAGES
		var c=0;
		var r=0;

		for (var i=0; i<group.images.length; i++) {
			var image = group.images[i];

			var idiv = document.createElement("div");
			idiv.className = "image";
			idiv.id = "img"+imgid;

			var img = document.createElement("img");
			img.setAttribute("alt", image);
			// a.setAttribute("title", image);
			img.alt = image;
            // first version using imagesizer
			//img.src = "imagesizer.php?w="+imagesize+"&h="+imagesize+"&src=" + group.path + "/" + image;
            // (php) preg_replace("/^f\//", "store/images/", $path['path'])."/".$path['file']."_$w"."x$h".".".$path['ext'];
            var image_no_ext = image.substr(0, image.lastIndexOf('.')) || image;
            img.src = "store/images/" + group.path.substr(2) + "/" + image_no_ext + "_" + imagesize + "x" + imagesize + ".jpg";            
            // log("img.src", img.src);
			var GROUPPAD = 0;
			idiv.style.left = GROUPPAD + (c*cellsize)+"px";
			idiv.style.top = GROUPPAD + (r*cellsize)+"px";
			idiv.style.width = (cellsize-bordersize)+"px";
			idiv.style.height = (cellsize-bordersize)+"px";

			idiv.appendChild(img);
			groupdiv.appendChild(idiv);

			Event.observe(idiv.id, "mousedown", imageOnMouseDown);
			Event.observe(idiv.id, "click", imageOnClick);

			// wacky IE hack to re-assert the onclick handler in particular
			// a.parentNode.innerHTML = a.parentNode.innerHTML;

			var zidiv = document.createElement("div");
			zidiv.className = "image_notloaded";
			zidiv.id = "zimg"+imgid;

			zidiv.style.left = (GROUPPAD*ZOOM) + (c*zcellsize)+"px";
			zidiv.style.top = (GROUPPAD*ZOOM) + (r*zcellsize)+"px";
			zidiv.style.width = (zcellsize-zbordersize)+"px";
			zidiv.style.height = (zcellsize-zbordersize)+"px";

			var zimg = document.createElement("img");
			zidiv.appendChild(zimg);
			zgroupdiv.appendChild(zidiv);

			Event.observe(zidiv.id, "click", zoomImageOnClick);
			Event.observe(zidiv.id, "mousedown", zoomImageOnMouseDown);
			
			// create Image data object to record refs
			var imgobj = {};
			imgobj.group = group;
			imgobj.id = idiv.id;
			imgobj.div = idiv;
			imgobj.zoomdiv = zidiv;
			imgobj.zoomimg = zimg;
			imgobj.imgsrc = image;
			imageDataById[imgobj.id] = imgobj;

			imgidstoload.push(idiv.id);

			imgid += 1;
			if (++c >= group.cols) { c = 0; r += 1; }
		}

	}
	// console.log("cols,rows:", totalcols + "," + totalrows);
	// resize stuff
	$('dragliner').style.width = (MARGIN*2) + (totalcols * cellsize) + "px";
	$('dragliner').style.height = (MARGIN*2) + (totalrows * cellsize) + "px";

	$('zoom').style.width = (totalcols * zcellsize) + "px";
	$('zoom').style.height = (totalrows * zcellsize) + "px";

	$('overview').style.width = (totalcols * (cellsize / OVERVIEWREDUCE)) + "px";
	$('overview').style.height = (totalrows * (cellsize / OVERVIEWREDUCE)) + "px";	
	$('overlay').style.width = (totalcols * (cellsize / OVERVIEWREDUCE)) + 40 + "px";
	$('overlay').style.height = (totalrows * (cellsize / OVERVIEWREDUCE)) + 30 + "px";	

	$('title').style.width = $('overview').style.width;
}

function getWindowWidth() {
	if (window.innerWidth!=window.undefined) return window.innerWidth;
	if (document.compatMode=='CSS1Compat') return document.documentElement.clientWidth;
	if (document.body) return document.body.clientWidth;
	return window.undefined;
}

function getWindowHeight() {
	if (window.innerHeight!=window.undefined) return window.innerHeight;
	if (document.compatMode=='CSS1Compat') return document.documentElement.clientHeight;
	if (document.body) return document.body.clientHeight;
	return window.undefined;
}


