if (!window.console)
        if (window.opera) window.console = {log: opera.postError}
        else window.console = {log: function () {}}/**/

;(function () {

if (![].push) {
	Array.prototype.push = function (x) {
		this [this.length] = x
	}
}

var main
var rocks = []

window.onload = function () {
	main = document.createElement ('div')
	main.id = 'main'

	anchors = document.getElementsByTagName ('a')
	function makeRock (anchor, i, name) {
		name = name ? name : i + 1
		var anchor = anchors [i]
		var dim = eval (anchor.getAttribute ('size'))

		var div = document.createElement ('div')
		var img = document.createElement ('img')
		div.style.width = dim [0] / dim [1] + 'em'
		var shade = Math.floor ((anchors.length - i) * 192 / anchors.length + 16)
//		div.style.backgroundColor = 'rgb(' + shade + ',' + shade + ',' + (shade + 32) + ')'
//		div.appendChild (document.createTextNode (name))
		div.appendChild (img)
		main.appendChild (div)

		//var size = 1 / Math.pow (i + 1, 0.8)
		var size = Math.random () * 2 + 1
		var y = Math.sqrt (size * 1e4 * dim [1] / dim [0])
		var x = y * dim [0] / dim [1]
		x = Math.ceil (x / 2) * 2
		y = Math.ceil (y / 2) * 2

		div.o = { ratio: 100 * dim [0] / dim [1]
		        , i: Math.random ()
			, dim: dim
			, proportions: [dim [0] * 1e4, dim [1] * 1e4]
			, proportions: [x, y]
			, coef: 1
			, origProportions: [x, y]
			, thumbs: thumbnailsSizes (dim [1])
			, thumbName: '-' + anchor.parentNode.id + '-' + anchor.firstChild.nodeValue
			, origName: anchor.parentNode.id + '/' + anchor.firstChild.nodeValue
			, div: div
			, img: img
			, rect: [0, 0, 0, 0]
			//, center: [0, 0]
			, anchor: anchor}
		return div.o
	}
	rocks = map (anchors, makeRock)
	rocks.sort (function (a,b) {return b.i - a.i})

/*	var controls = {center: {color: 'red'}, pole: {color: 'green'}}
	mapObject (controls, function (control) {
		var div = document.createElement ('div')
		div.style.position = 'absolute'
		div.style.border = '1px solid ' + control.color
		div.style.backgroundColor = 'transparent'
		div.style.width = '6px'
		div.style.height = '6px'
		control.div = div
		main.appendChild (div)
	})*/
	
	document.body.appendChild (main)
var IE7 = (navigator.appVersion.indexOf ("MSIE 7.") == -1) ? false : true
if (IE7) {
	main.style.height = (document.body.offsetHeight - 40) + 'px'
}

function mapObject (a, f) {
	var r = []
	for (var i in a) {
		var x = a [i]
		var y = f (x, i)
		if (y !== undefined) r.push (y)
	}
	return r
}

function map (a, f) {
	var r = []
	for (var i = 0; i < a.length ; i++) {
		var x = a [i]
		var y = f (x, i)
		if (y !== undefined) r.push (y)
	}
	return r
}

function intervalDistance (scalar, interval) {
	return scalar < interval [0] ? interval [0] - scalar : scalar <= interval [1] ? 0 : scalar - interval [1]
}

function visualDistance (point, rect) {
	var x = intervalDistance (point [0], [rect [0], rect [2]])
	var y = intervalDistance (point [1], [rect [1], rect [3]])
	return x * x  +  y * y
}

function snapToPole (box, rect, pole) {
	var r = []
	for (var k = 0; k < 2; k += 1) {
		var p = pole [k]
		var border0 = Math.round (box [k] * adjust [k + 2] / (adjust [k + 2] + adjust [k]))
		var border1 = box [k] - border0
		var a = rect [k] - p + border0
		var b = rect [k + 2] - p - border1
		var ab = (a * b < 0) ? [-border0, border1] :
			 (a < 0) ? [rect [k + 2] - p - box [k], rect [k + 2] - p]
				 : [rect [k] - p, rect [k] - p + box [k]]
		r [k] = ab [0] + p
		r [k + 2] = ab [1] + p
	}
	return r
}

function adjustedSquareDistance (a, b) {
	return Math.max (Math.abs (a [0] - b [0]) * adjustPath [0]
			,Math.abs (a [1] - b [1]) * adjustPath [1])
}

	var pole = [0, 0]
	var max = [-1, -1, 1, 1]
	var zoom = 1
	var padding
	var offset = [main.offsetWidth, main.offsetHeight]
	var client = [offset [0] / 2, offset [1] / 2]
	var diag = Math.sqrt (offset [0] * offset [0] + offset [1] * offset [1])
	var adjust = [diag / client [0]
		, diag / client [1]
		, diag / (offset [0] - client [0])
		, diag / (offset [1]- client [1])]
	client = false
	var adjustPath = []
	adjustPath [0] = Math.sqrt (offset [1] / offset [0])
	adjustPath [1] = 1 / adjustPath [0]

function layout () {
	max = [Infinity, Infinity, -Infinity, -Infinity]
//console.log (adjust)
	var rooms = [
			{ prox: [0, 0]
			, proportions: [Infinity, Infinity]
			, rect: [-Infinity, -Infinity, Infinity, Infinity]
			}]
	map (rocks, function (rock, i) {
//		rock.div.firstChild.nodeValue = rock.i + ':' + (i + 1)
		// filter large enough into roomy
		var roomy = []
		for (var j in rooms) {
			var room = rooms [j]
			if (rock.proportions [0] <= room.proportions [0] && rock.proportions [1] <= room.proportions [1]) {
				roomy.push (room)
			}
		}

		// Find the nearest into neigh
		var neigh
		var prox = Infinity
		map (roomy, function (room) {
			var rect = snapToPole (rock.proportions, room.rect, pole)
			var home = rock.rect ? adjustedSquareDistance ([(rock.rect [0] + rock.rect [2]) / 2, (rock.rect [1] + rock.rect [3]) / 2]
								     , [(rect [0] + rect [2]) / 2, (rect [1] + rect [3]) / 2])
					     : 0
//			var home = Math.sqrt (Math.pow (rock.rect [0] + rock.rect [2] - rect [0] - rect [2], 2)
//				 	    + Math.pow (rock.rect [1] + rock.rect [3] - rect [1] - rect [3], 2)) / 4
			var center = 0
			for (var j = 0; j < 4; j++) {
				var d = rect [j] - pole [j % 2]
				var c = Math.abs (d) * adjust [j % 2 + (d > 0 ? 2 : 0)]
				if (c > center) center = c
			}
			var penalty = 0.0 * Math.sqrt (home) + center

			if (penalty < prox) {
				neigh = room
				prox = penalty
			}
		})

		// Put rect in neigh
		var rect = rock.rect = snapToPole (rock.proportions, neigh.rect, pole)

//console.log (rect)
		// Cut rect out of rooms
		var res = []
		var hits = 0
		for (var j in rooms) {
			var room = rooms [j]
			var hit = false
			for (var k = 0; k < 4; k++) {
				var n = rect [k]
				var ro = room.rect [k]
				var rooo = room.rect [(k + 2) % 4]
//console.log (k, n, ro, rooo)
				// rect intersect room
				if (ro < n && n < rooo || ro > n && n > rooo) {
					if (hit || (rect [1 - k % 2] < room.rect [3 - k % 2] && rect [3 - k % 2] > room.rect [1 - k % 2]) ) {
						hit = true
						hits ++
						var newrect = room.rect.slice (0)
						newrect [(k + 2) % 4] = n
						var proportions = [distance (newrect [0], newrect [2]), distance (newrect [1], newrect [3])]
						var w = Math.min (Math.abs (newrect [0]), Math.abs (newrect [2]))
						w = w == Infinity ? 0 : w
						var h = Math.min (Math.abs (newrect [1]), Math.abs (newrect [3]))
						h = h == Infinity ? 0 : h
						var prox = [Math.max (w, h), Math.min (w,h)]
						//var prox = (w == Infinity ? 0 : w) + (h == Infinity ? 0 : h)
						var newroom =
							{ prox: prox
							, proportions: proportions
							, rect: newrect
							}
						check (newroom, room, rect, j, k, 'A')
						res.push (newroom)
//console.log ("A:", Math.abs(newrect [0]))
//console.log(prox, newrect)
					} else {
						check (room, room, rect, j, k, 'B')
						res.push (room)
						break
					}
				} else {
					if (!hit) {
						var s = sign (k - 1.5)
						if (s * ro > s * n) {
							check (room, room, rect, j, k, 'C')
							res.push (room)
							break
						}
					}
				}
			}
		}
//console.log (res.length - rooms.length, res.length, hits)
		rooms = res

		for (var j = 0; j < 4; j++) {
			var s = sign (j - 1.5)
			if (s * rect [j] > s * max [j]) {
				max [j] = rect [j]
			}
		}
	})
	
	zoom = 0
	padding = [0, 0]
//console.log (client, pole, max)
	if (client) {
		map (max, function (m, i) {
			var z = Math.abs (max [i] - pole [i % 2]) / client [i]
//console.log (z)
			if (z > zoom) zoom = z
		})

		for (var i = 0; i < 2; i++) {
			padding [i] = Math.floor (client [i] - (pole [i % 2] - max [i]) / zoom)
		}
	} else {
		var span = [(max [2] - max [0]) / offset [0]
			   ,(max [3] - max [1]) / offset [1]]
		var skelet = span [0] >= span [1] ? 0 : 1
		var side = (skelet + 1) % 2
		zoom = span [skelet]
		padding [side] = Math.floor ((offset [side] - (max [side + 2] - max [side]) / zoom) / 2) 
	}
//console.log (zoom, padding)
	map (rocks, function (rock) {
		rock.div.style.position = 'absolute'

		var off = Math.floor ((rock.rect [0] - max [0]) / zoom)
		rock.div.style.left = padding [0] + off + 'px'
		rock.div.style.width = Math.floor ((rock.rect [2] - max [0]) / zoom) - off+ 'px'

		var off = Math.floor ((rock.rect [1] - max [1]) / zoom)
		rock.div.style.top = padding [1] + off + 'px'
		var fontSize = Math.floor ((rock.rect [3] - max [1]) / zoom) - off
		rock.div.style.height = fontSize + 'px'

		var thumbs = rock.thumbs
		var j = thumbs.length - 1
		while (j >= 0 && thumbs [j] < fontSize) {
			j --
		}
var slow = false ? 'http://mola.mine.nu:8082/oxi/' : ''
		if (j != rock.currentThumb) {
			if (j == -1) {
				rock.img.src = slow + 'content/' + rock.origName
			} else {
				rock.img.src = slow + 'thumbs/' + thumbs [j] + rock.thumbName
			}
			rock.currentThumb = j
		}
	})

/*	controls.center.div.style.left = Math.floor (- max [0] / zoom) - 4 + 'px'
	controls.center.div.style.top = Math.floor (- max [1] / zoom) - 4 + 'px'

	controls.pole.div.style.left = Math.floor ((pole [0] - max [0]) / zoom) - 4 + 'px'
	controls.pole.div.style.top = Math.floor ((pole [1] - max [1]) / zoom) - 4 + 'px'*/
} layout ()

function mainresize () {
	var w = main.offsetWidth
	var h = main.offsetHeight
	if (offset [1] != h || offset [0] != w) {
		var diag = Math.sqrt ((h * h  +  w * w)
				    / (offset [1] * offset [1]  +  offset [0] * offset [0]))
		var a = [diag * offset [0] / w, diag * offset [1] / h]
		for (var i = 0; i < 4; i++) {
			adjust [i] = adjust [i] * a [i % 2]
		}

		adjustPath [0] = Math.sqrt (h / w)
		adjustPath [1] = 1 / adjustPath [0]
		offset [0] = w
		offset [1] = h
		client = false
		layout ()
	}
}

function mainclick (e) {
	if (!e) e = event
	var o = (e.target ? e.target : e.srcElement).parentNode.o
	if (o) {
		return mainscrollclick (e, o, e.button == 2 || e.shiftKey ? -1 : 1)
	}
}

function mainscroll (e) {
	if (!e) e = event
	var o = (e.target ? e.target : e.srcElement).parentNode.o
	if (o) {
		return mainscrollclick (e, o, e.detail ? - e.detail : e.wheelDelta)
	}
}

function mainscrollclick (e, o, coef) {
	coef = Math.pow (1.5, sign (coef))
//console.log (coef, e.detail, e.wheelDelta, e.button, e.altKey, e.shiftKey, e.ctrlKey)	
	function prop (rock, coef) {
		coef = rock.coef /= coef
		for (var i = 0; i < 2; i++) {
			rock.proportions [i] = Math.ceil (rock.origProportions [i] * coef / 2) * 2
		}
	}
	map (rocks, function (rock) {
		prop (rock, coef)
	})
	prop (o, 1 / (coef * coef))

	client = []
	client [0] = e.clientX - main.offsetLeft
	client [1] = e.clientY - main.offsetTop
	client [2] = offset [0] - client [0]
	client [3] = offset [1] - client [1]
	pole = [(client [0] - padding [0]) * zoom + max [0], (client [1] - padding [1]) * zoom + max [1]]
	var diag = Math.sqrt (offset [1] * offset [1] + offset [0] * offset [0])
	adjust = [diag / client [0]
		, diag / client [1]
		, diag / client [2]
		, diag / client [3]]
	map (rocks, function (rock) {
		rock.pole = visualDistance (pole, rock.rect)
	})
	rocks.sort (function (a, b) { return a.pole - b.pole })

	layout ()

	if (e.stopPropagation)
		e.stopPropagation ()
	if (e.preventDefault)
		e.preventDefault ()
	e.cancelBubble = true
	e.cancel = true
	e.returnValue = false
	return false
}
document.documentElement.onmousewheel = mainscroll

window.onresize = mainresize
main.onclick = mainclick
if (main.addEventListener) {
	/*main.addEventListener ('click', mainclick, false)/**/
	main.addEventListener ('DOMMouseScroll', mainscroll, false)/**/
}

function check (newroom, room, rect, i, j, k, hm) {
	if (newroom.rect [0] < room.rect [0]
	 || newroom.rect [1] < room.rect [1]
	 || newroom.rect [2] > room.rect [2]
	 || newroom.rect [3] > room.rect [3]) {
		console.log ('conflict with old room', newroom.rect, room.rect, i, j, k, hm)
		die
	}
	if (newroom.rect [0] < rect [2]
	 && newroom.rect [2] > rect [0]
	 && newroom.rect [1] < rect [3]
	 && newroom.rect [3] > rect [1]) {
		console.log ('unallowed intersection', newroom.rect, rect, i, j, k, hm)
		die
	}
	if (newroom.rect [0] == newroom.rect [2]
	 || newroom.rect [1] == newroom.rect [3]) {
		console.log ('room too thin', newroom.rect, i, j, k, hm)
		die
	}
}

function sign (a) {
	return a < 0 ? -1 : 1
}

function distance (a, b) {
	return Math.abs (a - b)
}

}

//       thumbnailsSizes :: 100 -> [50, 25, 12]
function thumbnailsSizes (y) {
	var out = []
	var divider = 2
	var yy

	while ((yy = Math.floor (y / divider)) >= 10) {
		out.push (yy)
		divider *= 2
	}

	return out
}

}) ()

